RecipeViewingScreen.java 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558
  1. /*
  2. * This file is licensed under the MIT License, part of Roughly Enough Items.
  3. * Copyright (c) 2018, 2019, 2020 shedaniel
  4. *
  5. * Permission is hereby granted, free of charge, to any person obtaining a copy
  6. * of this software and associated documentation files (the "Software"), to deal
  7. * in the Software without restriction, including without limitation the rights
  8. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  9. * copies of the Software, and to permit persons to whom the Software is
  10. * furnished to do so, subject to the following conditions:
  11. *
  12. * The above copyright notice and this permission notice shall be included in all
  13. * copies or substantial portions of the Software.
  14. *
  15. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  18. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  20. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  21. * SOFTWARE.
  22. */
  23. package me.shedaniel.rei.gui;
  24. import com.google.common.collect.Lists;
  25. import com.google.common.collect.Maps;
  26. import com.mojang.blaze3d.systems.RenderSystem;
  27. import me.shedaniel.clothconfig2.api.ModifierKeyCode;
  28. import me.shedaniel.math.api.Point;
  29. import me.shedaniel.math.api.Rectangle;
  30. import me.shedaniel.math.impl.PointHelper;
  31. import me.shedaniel.rei.api.*;
  32. import me.shedaniel.rei.api.widgets.Widgets;
  33. import me.shedaniel.rei.gui.widget.*;
  34. import me.shedaniel.rei.impl.ClientHelperImpl;
  35. import me.shedaniel.rei.impl.ScreenHelper;
  36. import me.shedaniel.rei.utils.CollectionUtils;
  37. import net.minecraft.client.MinecraftClient;
  38. import net.minecraft.client.gui.Element;
  39. import net.minecraft.client.gui.screen.Screen;
  40. import net.minecraft.client.render.Tessellator;
  41. import net.minecraft.client.render.VertexConsumerProvider;
  42. import net.minecraft.client.resource.language.I18n;
  43. import net.minecraft.client.sound.PositionedSoundInstance;
  44. import net.minecraft.client.util.NarratorManager;
  45. import net.minecraft.client.util.Window;
  46. import net.minecraft.client.util.math.Matrix4f;
  47. import net.minecraft.client.util.math.MatrixStack;
  48. import net.minecraft.sound.SoundEvents;
  49. import net.minecraft.text.TranslatableText;
  50. import net.minecraft.util.Formatting;
  51. import net.minecraft.util.Identifier;
  52. import net.minecraft.util.math.MathHelper;
  53. import org.jetbrains.annotations.ApiStatus;
  54. import org.jetbrains.annotations.Nullable;
  55. import java.util.*;
  56. import java.util.function.Supplier;
  57. @ApiStatus.Internal
  58. public class RecipeViewingScreen extends Screen implements RecipeScreen {
  59. public static final Identifier CHEST_GUI_TEXTURE = new Identifier("roughlyenoughitems", "textures/gui/recipecontainer.png");
  60. private final List<Widget> preWidgets = Lists.newArrayList();
  61. private final List<Widget> widgets = Lists.newArrayList();
  62. private final Map<Rectangle, List<Widget>> recipeBounds = Maps.newHashMap();
  63. private final List<TabWidget> tabs = Lists.newArrayList();
  64. private final Map<RecipeCategory<?>, List<RecipeDisplay>> categoriesMap;
  65. private final List<RecipeCategory<?>> categories;
  66. private final RecipeCategory<RecipeDisplay> selectedCategory;
  67. public int guiWidth;
  68. public int guiHeight;
  69. public int page;
  70. public int categoryPages = -1;
  71. public int largestWidth, largestHeight;
  72. public boolean choosePageActivated = false;
  73. public RecipeChoosePageWidget recipeChoosePageWidget;
  74. private int tabsPerPage = 5;
  75. private Rectangle bounds;
  76. @Nullable
  77. private CategoryBaseWidget workingStationsBaseWidget;
  78. private ButtonWidget recipeBack, recipeNext, categoryBack, categoryNext;
  79. private EntryStack ingredientStackToNotice = EntryStack.empty();
  80. private EntryStack resultStackToNotice = EntryStack.empty();
  81. public RecipeViewingScreen(Map<RecipeCategory<?>, List<RecipeDisplay>> categoriesMap, @Nullable Identifier category) {
  82. super(NarratorManager.EMPTY);
  83. Window window = MinecraftClient.getInstance().getWindow();
  84. this.bounds = new Rectangle(window.getScaledWidth() / 2 - guiWidth / 2, window.getScaledHeight() / 2 - guiHeight / 2, 176, 150);
  85. this.categoriesMap = categoriesMap;
  86. this.categories = Lists.newArrayList(categoriesMap.keySet());
  87. RecipeCategory<?> selected = categories.get(0);
  88. if (category != null) {
  89. for (RecipeCategory<?> recipeCategory : categories) {
  90. if (recipeCategory.getIdentifier().equals(category)) {
  91. selected = recipeCategory;
  92. break;
  93. }
  94. }
  95. }
  96. this.selectedCategory = (RecipeCategory<RecipeDisplay>) selected;
  97. }
  98. @ApiStatus.Internal
  99. static void transformIngredientNotice(List<Widget> setupDisplay, EntryStack noticeStack) {
  100. transformNotice(1, setupDisplay, noticeStack);
  101. }
  102. @ApiStatus.Internal
  103. static void transformResultNotice(List<Widget> setupDisplay, EntryStack noticeStack) {
  104. transformNotice(2, setupDisplay, noticeStack);
  105. }
  106. private static void transformNotice(int marker, List<Widget> setupDisplay, EntryStack noticeStack) {
  107. if (noticeStack.isEmpty())
  108. return;
  109. for (Widget widget : setupDisplay) {
  110. if (widget instanceof EntryWidget) {
  111. EntryWidget entry = (EntryWidget) widget;
  112. if (entry.getNoticeMark() == marker && entry.entries().size() > 1) {
  113. EntryStack stack = CollectionUtils.findFirstOrNullEqualsEntryIgnoreAmount(entry.entries(), noticeStack);
  114. if (stack != null) {
  115. entry.clearStacks();
  116. entry.entry(stack);
  117. }
  118. }
  119. }
  120. }
  121. }
  122. @ApiStatus.Internal
  123. @Override
  124. public void addIngredientStackToNotice(EntryStack stack) {
  125. this.ingredientStackToNotice = stack;
  126. }
  127. @ApiStatus.Internal
  128. @Override
  129. public void addResultStackToNotice(EntryStack stack) {
  130. this.resultStackToNotice = stack;
  131. }
  132. @Override
  133. public Identifier getCurrentCategory() {
  134. return selectedCategory.getIdentifier();
  135. }
  136. @Override
  137. public void recalculateCategoryPage() {
  138. this.categoryPages = -1;
  139. }
  140. @Nullable
  141. public CategoryBaseWidget getWorkingStationsBaseWidget() {
  142. return workingStationsBaseWidget;
  143. }
  144. @Override
  145. public boolean keyPressed(int int_1, int int_2, int int_3) {
  146. if (int_1 == 256 && choosePageActivated) {
  147. choosePageActivated = false;
  148. init();
  149. return true;
  150. }
  151. if (int_1 == 258) {
  152. boolean boolean_1 = !hasShiftDown();
  153. if (!this.changeFocus(boolean_1))
  154. this.changeFocus(boolean_1);
  155. return true;
  156. }
  157. if (choosePageActivated)
  158. return recipeChoosePageWidget.keyPressed(int_1, int_2, int_3);
  159. else if (ConfigObject.getInstance().getNextPageKeybind().matchesKey(int_1, int_2)) {
  160. if (recipeNext.enabled)
  161. recipeNext.onPressed();
  162. return recipeNext.enabled;
  163. } else if (ConfigObject.getInstance().getPreviousPageKeybind().matchesKey(int_1, int_2)) {
  164. if (recipeBack.enabled)
  165. recipeBack.onPressed();
  166. return recipeBack.enabled;
  167. }
  168. for (Element element : children())
  169. if (element.keyPressed(int_1, int_2, int_3))
  170. return true;
  171. if (int_1 == 256 || this.minecraft.options.keyInventory.matchesKey(int_1, int_2)) {
  172. MinecraftClient.getInstance().openScreen(ScreenHelper.getLastContainerScreen());
  173. ScreenHelper.getLastOverlay().init();
  174. return true;
  175. }
  176. if (int_1 == 259) {
  177. if (ScreenHelper.hasLastRecipeScreen())
  178. minecraft.openScreen(ScreenHelper.getLastRecipeScreen());
  179. else
  180. minecraft.openScreen(ScreenHelper.getLastContainerScreen());
  181. return true;
  182. }
  183. return super.keyPressed(int_1, int_2, int_3);
  184. }
  185. @Override
  186. public boolean isPauseScreen() {
  187. return false;
  188. }
  189. @Override
  190. public void init() {
  191. super.init();
  192. boolean isCompactTabs = ConfigObject.getInstance().isUsingCompactTabs();
  193. int tabSize = isCompactTabs ? 24 : 28;
  194. this.children.clear();
  195. this.recipeBounds.clear();
  196. this.tabs.clear();
  197. this.preWidgets.clear();
  198. this.widgets.clear();
  199. this.largestWidth = width - 100;
  200. this.largestHeight = Math.max(height - 36, 100);
  201. int maxWidthDisplay = CollectionUtils.mapAndMax(getCurrentDisplayed(), selectedCategory::getDisplayWidth, Comparator.naturalOrder()).orElse(150);
  202. this.guiWidth = maxWidthDisplay + 20;
  203. this.guiHeight = MathHelper.floor(MathHelper.clamp((double) (selectedCategory.getDisplayHeight() + 4) * (getRecipesPerPage() + 1) + 36, 100, largestHeight));
  204. this.tabsPerPage = Math.max(5, MathHelper.floor((guiWidth - 20d) / tabSize));
  205. if (this.categoryPages == -1) {
  206. this.categoryPages = Math.max(0, categories.indexOf(selectedCategory) / tabsPerPage);
  207. }
  208. this.bounds = new Rectangle(width / 2 - guiWidth / 2, height / 2 - guiHeight / 2, guiWidth, guiHeight);
  209. this.page = MathHelper.clamp(page, 0, getTotalPages(selectedCategory) - 1);
  210. ButtonWidget w, w2;
  211. this.widgets.add(w = ButtonWidget.create(new Rectangle(bounds.x + 2, bounds.y - 16, 10, 10), new TranslatableText("text.rei.left_arrow"), buttonWidget -> {
  212. categoryPages--;
  213. if (categoryPages < 0)
  214. categoryPages = MathHelper.ceil(categories.size() / (float) tabsPerPage) - 1;
  215. RecipeViewingScreen.this.init();
  216. }));
  217. this.widgets.add(w2 = ButtonWidget.create(new Rectangle(bounds.x + bounds.width - 12, bounds.y - 16, 10, 10), new TranslatableText("text.rei.right_arrow"), buttonWidget -> {
  218. categoryPages++;
  219. if (categoryPages > MathHelper.ceil(categories.size() / (float) tabsPerPage) - 1)
  220. categoryPages = 0;
  221. RecipeViewingScreen.this.init();
  222. }));
  223. w.enabled = w2.enabled = categories.size() > tabsPerPage;
  224. widgets.add(categoryBack = ButtonWidget.create(new Rectangle(bounds.getX() + 5, bounds.getY() + 5, 12, 12), new TranslatableText("text.rei.left_arrow"), buttonWidget -> {
  225. int currentCategoryIndex = categories.indexOf(selectedCategory);
  226. currentCategoryIndex--;
  227. if (currentCategoryIndex < 0)
  228. currentCategoryIndex = categories.size() - 1;
  229. ClientHelperImpl.getInstance().openRecipeViewingScreen(categoriesMap, categories.get(currentCategoryIndex).getIdentifier(), ingredientStackToNotice, resultStackToNotice);
  230. }).tooltip(() -> I18n.translate("text.rei.previous_category")));
  231. widgets.add(Widgets.createClickableLabel(new Point(bounds.getCenterX(), bounds.getY() + 7), selectedCategory.getCategoryName(), clickableLabelWidget -> {
  232. ClientHelper.getInstance().executeViewAllRecipesKeyBind();
  233. }).tooltipLine(I18n.translate("text.rei.view_all_categories")));
  234. widgets.add(categoryNext = ButtonWidget.create(new Rectangle(bounds.getMaxX() - 17, bounds.getY() + 5, 12, 12), new TranslatableText("text.rei.right_arrow"), buttonWidget -> {
  235. int currentCategoryIndex = categories.indexOf(selectedCategory);
  236. currentCategoryIndex++;
  237. if (currentCategoryIndex >= categories.size())
  238. currentCategoryIndex = 0;
  239. ClientHelperImpl.getInstance().openRecipeViewingScreen(categoriesMap, categories.get(currentCategoryIndex).getIdentifier(), ingredientStackToNotice, resultStackToNotice);
  240. }).tooltip(() -> I18n.translate("text.rei.next_category")));
  241. categoryBack.enabled = categories.size() > 1;
  242. categoryNext.enabled = categories.size() > 1;
  243. widgets.add(recipeBack = ButtonWidget.create(new Rectangle(bounds.getX() + 5, bounds.getY() + 19, 12, 12), new TranslatableText("text.rei.left_arrow"), buttonWidget -> {
  244. page--;
  245. if (page < 0)
  246. page = getTotalPages(selectedCategory) - 1;
  247. RecipeViewingScreen.this.init();
  248. }).tooltip(() -> I18n.translate("text.rei.previous_page")));
  249. widgets.add(Widgets.createClickableLabel(new Point(bounds.getCenterX(), bounds.getY() + 21), "", label -> {
  250. RecipeViewingScreen.this.choosePageActivated = true;
  251. RecipeViewingScreen.this.init();
  252. }).onRender(label -> {
  253. label.setText(String.format("%d/%d", page + 1, getTotalPages(selectedCategory)));
  254. label.setClickable(categoriesMap.get(selectedCategory).size() > getRecipesPerPageByHeight());
  255. }).tooltipSupplier(label -> label.isClickable() ? I18n.translate("text.rei.choose_page") : null));
  256. widgets.add(recipeNext = ButtonWidget.create(new Rectangle(bounds.getMaxX() - 17, bounds.getY() + 19, 12, 12), new TranslatableText("text.rei.right_arrow"), buttonWidget -> {
  257. page++;
  258. if (page >= getTotalPages(selectedCategory))
  259. page = 0;
  260. RecipeViewingScreen.this.init();
  261. }).tooltip(() -> I18n.translate("text.rei.next_page")));
  262. recipeBack.enabled = recipeNext.enabled = categoriesMap.get(selectedCategory).size() > getRecipesPerPageByHeight();
  263. int tabV = isCompactTabs ? 166 : 192;
  264. for (int i = 0; i < tabsPerPage; i++) {
  265. int j = i + categoryPages * tabsPerPage;
  266. if (categories.size() > j) {
  267. TabWidget tab;
  268. tabs.add(tab = TabWidget.create(i, tabSize, bounds.x + bounds.width / 2 - Math.min(categories.size() - categoryPages * tabsPerPage, tabsPerPage) * tabSize / 2, bounds.y, 0, tabV, widget -> {
  269. MinecraftClient.getInstance().getSoundManager().play(PositionedSoundInstance.master(SoundEvents.UI_BUTTON_CLICK, 1.0F));
  270. if (widget.getId() + categoryPages * tabsPerPage == categories.indexOf(selectedCategory))
  271. return false;
  272. ClientHelperImpl.getInstance().openRecipeViewingScreen(categoriesMap, categories.get(widget.getId() + categoryPages * tabsPerPage).getIdentifier(), ingredientStackToNotice, resultStackToNotice);
  273. return true;
  274. }));
  275. tab.setRenderer(categories.get(j), categories.get(j).getLogo(), categories.get(j).getCategoryName(), tab.getId() + categoryPages * tabsPerPage == categories.indexOf(selectedCategory));
  276. }
  277. }
  278. Optional<ButtonAreaSupplier> supplier = RecipeHelper.getInstance().getAutoCraftButtonArea(selectedCategory);
  279. int recipeHeight = selectedCategory.getDisplayHeight();
  280. List<RecipeDisplay> currentDisplayed = getCurrentDisplayed();
  281. for (int i = 0; i < currentDisplayed.size(); i++) {
  282. final RecipeDisplay display = currentDisplayed.get(i);
  283. final Supplier<RecipeDisplay> displaySupplier = () -> display;
  284. int displayWidth = selectedCategory.getDisplayWidth(displaySupplier.get());
  285. final Rectangle displayBounds = new Rectangle(getBounds().getCenterX() - displayWidth / 2, getBounds().y - 2 + 36 + recipeHeight * i + 4 * i, displayWidth, recipeHeight);
  286. List<Widget> setupDisplay = selectedCategory.setupDisplay(display, displayBounds);
  287. transformIngredientNotice(setupDisplay, ingredientStackToNotice);
  288. transformResultNotice(setupDisplay, resultStackToNotice);
  289. recipeBounds.put(displayBounds, setupDisplay);
  290. this.widgets.addAll(setupDisplay);
  291. if (supplier.isPresent() && supplier.get().get(displayBounds) != null)
  292. this.widgets.add(new AutoCraftingButtonWidget(displayBounds, supplier.get().get(displayBounds), supplier.get().getButtonText(), displaySupplier, setupDisplay, selectedCategory));
  293. }
  294. if (choosePageActivated)
  295. recipeChoosePageWidget = new RecipeChoosePageWidget(this, page, getTotalPages(selectedCategory));
  296. else
  297. recipeChoosePageWidget = null;
  298. workingStationsBaseWidget = null;
  299. List<List<EntryStack>> workingStations = RecipeHelper.getInstance().getWorkingStations(selectedCategory.getIdentifier());
  300. if (!workingStations.isEmpty()) {
  301. int hh = MathHelper.floor((bounds.height - 16) / 18f);
  302. int actualHeight = Math.min(hh, workingStations.size());
  303. int innerWidth = MathHelper.ceil(workingStations.size() / ((float) hh));
  304. int xx = bounds.x - (8 + innerWidth * 16) + 6;
  305. int yy = bounds.y + 16;
  306. preWidgets.add(workingStationsBaseWidget = new CategoryBaseWidget(new Rectangle(xx - 5, yy - 5, 15 + innerWidth * 16, 10 + actualHeight * 16)));
  307. preWidgets.add(new SlotBaseWidget(new Rectangle(xx - 1, yy - 1, innerWidth * 16 + 2, actualHeight * 16 + 2)));
  308. int index = 0;
  309. List<String> list = Collections.singletonList(Formatting.YELLOW.toString() + I18n.translate("text.rei.working_station"));
  310. xx += (innerWidth - 1) * 16;
  311. for (List<EntryStack> workingStation : workingStations) {
  312. preWidgets.add(new WorkstationSlotWidget(xx, yy, CollectionUtils.map(workingStation, stack -> stack.copy().setting(EntryStack.Settings.TOOLTIP_APPEND_EXTRA, s -> list))));
  313. index++;
  314. yy += 16;
  315. if (index >= hh) {
  316. index = 0;
  317. yy = bounds.y + 16;
  318. xx -= 16;
  319. }
  320. }
  321. }
  322. children.addAll(tabs);
  323. children.add(ScreenHelper.getLastOverlay(true, false));
  324. children.addAll(widgets);
  325. children.addAll(preWidgets);
  326. }
  327. public List<Widget> getWidgets() {
  328. return widgets;
  329. }
  330. public List<RecipeDisplay> getCurrentDisplayed() {
  331. List<RecipeDisplay> list = Lists.newArrayList();
  332. int recipesPerPage = getRecipesPerPage();
  333. for (int i = 0; i <= recipesPerPage; i++)
  334. if (page * (recipesPerPage + 1) + i < categoriesMap.get(selectedCategory).size())
  335. list.add(categoriesMap.get(selectedCategory).get(page * (recipesPerPage + 1) + i));
  336. return list;
  337. }
  338. public RecipeCategory<RecipeDisplay> getSelectedCategory() {
  339. return selectedCategory;
  340. }
  341. public int getPage() {
  342. return page;
  343. }
  344. public int getCategoryPage() {
  345. return categoryPages;
  346. }
  347. private int getRecipesPerPage() {
  348. if (selectedCategory.getFixedRecipesPerPage() > 0)
  349. return selectedCategory.getFixedRecipesPerPage() - 1;
  350. int height = selectedCategory.getDisplayHeight();
  351. return MathHelper.clamp(MathHelper.floor(((double) largestHeight - 36) / ((double) height + 4)) - 1, 0, Math.min(ConfigObject.getInstance().getMaxRecipePerPage() - 1, selectedCategory.getMaximumRecipePerPage() - 1));
  352. }
  353. private int getRecipesPerPageByHeight() {
  354. int height = selectedCategory.getDisplayHeight();
  355. return MathHelper.clamp(MathHelper.floor(((double) guiHeight - 36) / ((double) height + 4)), 0, Math.min(ConfigObject.getInstance().getMaxRecipePerPage() - 1, selectedCategory.getMaximumRecipePerPage() - 1));
  356. }
  357. @Override
  358. public void render(int mouseX, int mouseY, float delta) {
  359. this.fillGradient(0, 0, this.width, this.height, -1072689136, -804253680);
  360. for (Widget widget : preWidgets) {
  361. widget.render(mouseX, mouseY, delta);
  362. }
  363. if (selectedCategory != null)
  364. selectedCategory.drawCategoryBackground(bounds, mouseX, mouseY, delta);
  365. else {
  366. PanelWidget.render(bounds, -1);
  367. if (REIHelper.getInstance().isDarkThemeEnabled()) {
  368. fill(bounds.x + 17, bounds.y + 5, bounds.x + bounds.width - 17, bounds.y + 17, 0xFF404040);
  369. fill(bounds.x + 17, bounds.y + 19, bounds.x + bounds.width - 17, bounds.y + 30, 0xFF404040);
  370. } else {
  371. fill(bounds.x + 17, bounds.y + 5, bounds.x + bounds.width - 17, bounds.y + 17, 0xFF9E9E9E);
  372. fill(bounds.x + 17, bounds.y + 19, bounds.x + bounds.width - 17, bounds.y + 31, 0xFF9E9E9E);
  373. }
  374. }
  375. for (TabWidget tab : tabs) {
  376. if (!tab.isSelected())
  377. tab.render(mouseX, mouseY, delta);
  378. }
  379. super.render(mouseX, mouseY, delta);
  380. for (Widget widget : widgets) {
  381. widget.render(mouseX, mouseY, delta);
  382. }
  383. RenderSystem.color4f(1.0F, 1.0F, 1.0F, 1.0F);
  384. for (TabWidget tab : tabs) {
  385. if (tab.isSelected())
  386. tab.render(mouseX, mouseY, delta);
  387. }
  388. ScreenHelper.getLastOverlay().render(mouseX, mouseY, delta);
  389. ScreenHelper.getLastOverlay().lateRender(mouseX, mouseY, delta);
  390. {
  391. ModifierKeyCode export = ConfigObject.getInstance().getExportImageKeybind();
  392. if (export.matchesCurrentKey()) {
  393. for (Map.Entry<Rectangle, List<Widget>> entry : recipeBounds.entrySet()) {
  394. Rectangle bounds = entry.getKey();
  395. setBlitOffset(470);
  396. if (bounds.contains(mouseX, mouseY)) {
  397. fillGradient(bounds.x, bounds.y, bounds.getMaxX(), bounds.getMaxY(), 1744822402, 1744822402);
  398. String s = I18n.translate("text.rei.release_export", export.getLocalizedName());
  399. MatrixStack matrixStack_1 = new MatrixStack();
  400. VertexConsumerProvider.Immediate immediate = VertexConsumerProvider.immediate(Tessellator.getInstance().getBuffer());
  401. matrixStack_1.translate(0.0D, 0.0D, 480);
  402. Matrix4f matrix4f_1 = matrixStack_1.peek().getModel();
  403. font.draw(s, bounds.getCenterX() - font.getStringWidth(s) / 2f, bounds.getCenterY() - 4.5f, 0xff000000, false, matrix4f_1, immediate, false, 0, 15728880);
  404. immediate.draw();
  405. } else {
  406. fillGradient(bounds.x, bounds.y, bounds.getMaxX(), bounds.getMaxY(), 1744830463, 1744830463);
  407. }
  408. setBlitOffset(0);
  409. }
  410. }
  411. }
  412. if (choosePageActivated) {
  413. setBlitOffset(500);
  414. this.fillGradient(0, 0, this.width, this.height, -1072689136, -804253680);
  415. setBlitOffset(0);
  416. recipeChoosePageWidget.render(mouseX, mouseY, delta);
  417. }
  418. }
  419. @Override
  420. public boolean keyReleased(int keyCode, int scanCode, int modifiers) {
  421. ModifierKeyCode export = ConfigObject.getInstance().getExportImageKeybind();
  422. if (export.matchesKey(keyCode, scanCode)) {
  423. for (Map.Entry<Rectangle, List<Widget>> entry : recipeBounds.entrySet()) {
  424. Rectangle bounds = entry.getKey();
  425. if (bounds.contains(PointHelper.ofMouse())) {
  426. RecipeDisplayExporter.exportRecipeDisplay(bounds, entry.getValue());
  427. break;
  428. }
  429. }
  430. }
  431. return super.keyReleased(keyCode, scanCode, modifiers);
  432. }
  433. public int getTotalPages(RecipeCategory<RecipeDisplay> category) {
  434. return MathHelper.ceil(categoriesMap.get(category).size() / (double) (getRecipesPerPage() + 1));
  435. }
  436. public Rectangle getBounds() {
  437. return bounds;
  438. }
  439. @Override
  440. public boolean charTyped(char char_1, int int_1) {
  441. if (choosePageActivated) {
  442. return recipeChoosePageWidget.charTyped(char_1, int_1);
  443. }
  444. for (Element listener : children())
  445. if (listener.charTyped(char_1, int_1))
  446. return true;
  447. return super.charTyped(char_1, int_1);
  448. }
  449. @Override
  450. public boolean mouseDragged(double double_1, double double_2, int int_1, double double_3, double double_4) {
  451. if (choosePageActivated) {
  452. return recipeChoosePageWidget.mouseDragged(double_1, double_2, int_1, double_3, double_4);
  453. }
  454. return super.mouseDragged(double_1, double_2, int_1, double_3, double_4);
  455. }
  456. @Override
  457. public boolean mouseReleased(double double_1, double double_2, int int_1) {
  458. if (choosePageActivated) {
  459. return recipeChoosePageWidget.mouseReleased(double_1, double_2, int_1);
  460. }
  461. return super.mouseReleased(double_1, double_2, int_1);
  462. }
  463. @Override
  464. public boolean mouseScrolled(double i, double j, double amount) {
  465. for (Element listener : children())
  466. if (listener.mouseScrolled(i, j, amount))
  467. return true;
  468. if (getBounds().contains(PointHelper.ofMouse())) {
  469. if (amount > 0 && recipeBack.enabled)
  470. recipeBack.onPressed();
  471. else if (amount < 0 && recipeNext.enabled)
  472. recipeNext.onPressed();
  473. }
  474. if ((new Rectangle(bounds.x, bounds.y - 28, bounds.width, 28)).contains(PointHelper.ofMouse())) {
  475. if (amount > 0 && categoryBack.enabled)
  476. categoryBack.onPressed();
  477. else if (amount < 0 && categoryNext.enabled)
  478. categoryNext.onPressed();
  479. }
  480. return super.mouseScrolled(i, j, amount);
  481. }
  482. @Override
  483. public boolean mouseClicked(double double_1, double double_2, int int_1) {
  484. if (choosePageActivated)
  485. if (recipeChoosePageWidget.containsMouse(double_1, double_2)) {
  486. return recipeChoosePageWidget.mouseClicked(double_1, double_2, int_1);
  487. } else {
  488. choosePageActivated = false;
  489. init();
  490. return false;
  491. }
  492. for (Element entry : children())
  493. if (entry.mouseClicked(double_1, double_2, int_1)) {
  494. setFocused(entry);
  495. if (int_1 == 0)
  496. setDragging(true);
  497. return true;
  498. }
  499. return false;
  500. }
  501. @Override
  502. public Element getFocused() {
  503. if (choosePageActivated)
  504. return recipeChoosePageWidget;
  505. return super.getFocused();
  506. }
  507. public static class WorkstationSlotWidget extends EntryWidget {
  508. public WorkstationSlotWidget(int x, int y, List<EntryStack> widgets) {
  509. super(new Point(x, y));
  510. entries(widgets);
  511. noBackground();
  512. }
  513. @Override
  514. public boolean containsMouse(double mouseX, double mouseY) {
  515. return getInnerBounds().contains(mouseX, mouseY);
  516. }
  517. }
  518. }