RecipeViewingScreen.java 25 KB

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