ContainerScreenOverlay.java 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616
  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.mojang.blaze3d.systems.RenderSystem;
  26. import me.shedaniel.math.api.Point;
  27. import me.shedaniel.math.api.Rectangle;
  28. import me.shedaniel.math.impl.PointHelper;
  29. import me.shedaniel.rei.RoughlyEnoughItemsCore;
  30. import me.shedaniel.rei.api.*;
  31. import me.shedaniel.rei.api.widgets.Tooltip;
  32. import me.shedaniel.rei.api.widgets.Widgets;
  33. import me.shedaniel.rei.gui.config.SearchFieldLocation;
  34. import me.shedaniel.rei.gui.widget.*;
  35. import me.shedaniel.rei.impl.ScreenHelper;
  36. import me.shedaniel.rei.impl.Weather;
  37. import me.shedaniel.rei.listeners.ContainerScreenHooks;
  38. import me.shedaniel.rei.utils.CollectionUtils;
  39. import net.minecraft.client.MinecraftClient;
  40. import net.minecraft.client.gui.Element;
  41. import net.minecraft.client.gui.screen.Screen;
  42. import net.minecraft.client.gui.screen.ingame.HandledScreen;
  43. import net.minecraft.client.render.Tessellator;
  44. import net.minecraft.client.render.VertexConsumerProvider;
  45. import net.minecraft.client.resource.language.I18n;
  46. import net.minecraft.client.sound.PositionedSoundInstance;
  47. import net.minecraft.client.util.NarratorManager;
  48. import net.minecraft.client.util.Window;
  49. import net.minecraft.client.util.math.Matrix4f;
  50. import net.minecraft.client.util.math.MatrixStack;
  51. import net.minecraft.client.world.ClientWorld;
  52. import net.minecraft.item.ItemStack;
  53. import net.minecraft.screen.slot.Slot;
  54. import net.minecraft.sound.SoundEvents;
  55. import net.minecraft.text.TranslatableText;
  56. import net.minecraft.util.ActionResult;
  57. import net.minecraft.util.Identifier;
  58. import net.minecraft.world.GameMode;
  59. import org.apache.logging.log4j.util.TriConsumer;
  60. import org.jetbrains.annotations.ApiStatus;
  61. import org.jetbrains.annotations.Nullable;
  62. import java.util.*;
  63. @ApiStatus.Internal
  64. public class ContainerScreenOverlay extends WidgetWithBounds {
  65. private static final Identifier CHEST_GUI_TEXTURE = new Identifier("roughlyenoughitems", "textures/gui/recipecontainer.png");
  66. private static final List<Tooltip> TOOLTIPS = Lists.newArrayList();
  67. private static final EntryListWidget ENTRY_LIST_WIDGET = new EntryListWidget();
  68. private static FavoritesListWidget favoritesListWidget = null;
  69. private final List<Widget> widgets = Lists.newLinkedList();
  70. public boolean shouldReInit = false;
  71. private int tooltipWidth;
  72. private int tooltipHeight;
  73. private List<String> tooltipLines;
  74. public final TriConsumer<Integer, Integer, Float> renderTooltipCallback = (x, y, aFloat) -> {
  75. RenderSystem.disableRescaleNormal();
  76. RenderSystem.disableDepthTest();
  77. setZOffset(999);
  78. this.fillGradient(x - 3, y - 4, x + tooltipWidth + 3, y - 3, -267386864, -267386864);
  79. this.fillGradient(x - 3, y + tooltipHeight + 3, x + tooltipWidth + 3, y + tooltipHeight + 4, -267386864, -267386864);
  80. this.fillGradient(x - 3, y - 3, x + tooltipWidth + 3, y + tooltipHeight + 3, -267386864, -267386864);
  81. this.fillGradient(x - 4, y - 3, x - 3, y + tooltipHeight + 3, -267386864, -267386864);
  82. this.fillGradient(x + tooltipWidth + 3, y - 3, x + tooltipWidth + 4, y + tooltipHeight + 3, -267386864, -267386864);
  83. this.fillGradient(x - 3, y - 3 + 1, x - 3 + 1, y + tooltipHeight + 3 - 1, 1347420415, 1344798847);
  84. this.fillGradient(x + tooltipWidth + 2, y - 3 + 1, x + tooltipWidth + 3, y + tooltipHeight + 3 - 1, 1347420415, 1344798847);
  85. this.fillGradient(x - 3, y - 3, x + tooltipWidth + 3, y - 3 + 1, 1347420415, 1347420415);
  86. this.fillGradient(x - 3, y + tooltipHeight + 2, x + tooltipWidth + 3, y + tooltipHeight + 3, 1344798847, 1344798847);
  87. int currentY = y;
  88. MatrixStack matrixStack_1 = new MatrixStack();
  89. VertexConsumerProvider.Immediate immediate = VertexConsumerProvider.immediate(Tessellator.getInstance().getBuffer());
  90. matrixStack_1.translate(0.0D, 0.0D, getZOffset());
  91. Matrix4f matrix4f_1 = matrixStack_1.peek().getModel();
  92. for (int lineIndex = 0; lineIndex < tooltipLines.size(); lineIndex++) {
  93. font.draw(tooltipLines.get(lineIndex), x, currentY, -1, true, matrix4f_1, immediate, false, 0, 15728880);
  94. currentY += lineIndex == 0 ? 12 : 10;
  95. }
  96. immediate.draw();
  97. setZOffset(0);
  98. RenderSystem.enableDepthTest();
  99. RenderSystem.enableRescaleNormal();
  100. };
  101. private Rectangle bounds;
  102. private Window window;
  103. @Nullable private LateRenderedButton craftableToggleButton;
  104. private LateRenderedButton configButton;
  105. private ButtonWidget leftButton, rightButton;
  106. public static EntryListWidget getEntryListWidget() {
  107. return ENTRY_LIST_WIDGET;
  108. }
  109. @Nullable
  110. public static FavoritesListWidget getFavoritesListWidget() {
  111. return favoritesListWidget;
  112. }
  113. public void init(boolean useless) {
  114. init();
  115. }
  116. public void init() {
  117. this.shouldReInit = false;
  118. //Update Variables
  119. this.children().clear();
  120. this.window = MinecraftClient.getInstance().getWindow();
  121. @SuppressWarnings({"RawTypeCanBeGeneric", "rawtypes"})
  122. DisplayHelper.DisplayBoundsHandler boundsHandler = DisplayHelper.getInstance().getResponsibleBoundsHandler(MinecraftClient.getInstance().currentScreen.getClass());
  123. this.bounds = ConfigObject.getInstance().isLeftHandSidePanel() ? boundsHandler.getLeftBounds(MinecraftClient.getInstance().currentScreen) : boundsHandler.getRightBounds(MinecraftClient.getInstance().currentScreen);
  124. widgets.add(ENTRY_LIST_WIDGET);
  125. if (ConfigObject.getInstance().doDisplayFavoritesOnTheLeft() && ConfigObject.getInstance().isFavoritesEnabled()) {
  126. if (favoritesListWidget == null)
  127. favoritesListWidget = new FavoritesListWidget();
  128. widgets.add(favoritesListWidget);
  129. }
  130. ENTRY_LIST_WIDGET.updateArea(boundsHandler, ScreenHelper.getSearchField() == null ? "" : null);
  131. if (ScreenHelper.getSearchField() == null) {
  132. ScreenHelper.setSearchField(new OverlaySearchField(0, 0, 0, 0));
  133. }
  134. ScreenHelper.getSearchField().getBounds().setBounds(getSearchFieldArea());
  135. this.widgets.add(ScreenHelper.getSearchField());
  136. ScreenHelper.getSearchField().setChangedListener(s -> ENTRY_LIST_WIDGET.updateSearch(s, false));
  137. if (!ConfigObject.getInstance().isEntryListWidgetScrolled()) {
  138. widgets.add(leftButton = new ButtonWidget(new Rectangle(bounds.x, bounds.y + (ConfigObject.getInstance().getSearchFieldLocation() == SearchFieldLocation.TOP_SIDE ? 24 : 0) + 5, 16, 16), new TranslatableText("text.rei.left_arrow")) {
  139. @Override
  140. public void onPressed() {
  141. ENTRY_LIST_WIDGET.previousPage();
  142. if (ENTRY_LIST_WIDGET.getPage() < 0)
  143. ENTRY_LIST_WIDGET.setPage(ENTRY_LIST_WIDGET.getTotalPages() - 1);
  144. ENTRY_LIST_WIDGET.updateEntriesPosition();
  145. }
  146. @Override
  147. public boolean containsMouse(double mouseX, double mouseY) {
  148. return isNotInExclusionZones(mouseX, mouseY) && super.containsMouse(mouseX, mouseY);
  149. }
  150. }.tooltip(() -> I18n.translate("text.rei.previous_page")).canChangeFocuses(false));
  151. widgets.add(rightButton = new ButtonWidget(new Rectangle(bounds.x + bounds.width - 18, bounds.y + (ConfigObject.getInstance().getSearchFieldLocation() == SearchFieldLocation.TOP_SIDE ? 24 : 0) + 5, 16, 16), new TranslatableText("text.rei.right_arrow")) {
  152. @Override
  153. public void onPressed() {
  154. ENTRY_LIST_WIDGET.nextPage();
  155. if (ENTRY_LIST_WIDGET.getPage() >= ENTRY_LIST_WIDGET.getTotalPages())
  156. ENTRY_LIST_WIDGET.setPage(0);
  157. ENTRY_LIST_WIDGET.updateEntriesPosition();
  158. }
  159. @Override
  160. public boolean containsMouse(double mouseX, double mouseY) {
  161. return isNotInExclusionZones(mouseX, mouseY) && super.containsMouse(mouseX, mouseY);
  162. }
  163. }.tooltip(() -> I18n.translate("text.rei.next_page")).canChangeFocuses(false));
  164. }
  165. widgets.add(configButton = new LateRenderedButton(getConfigButtonArea(), NarratorManager.EMPTY) {
  166. @Override
  167. public void onPressed() {
  168. if (Screen.hasShiftDown()) {
  169. ClientHelper.getInstance().setCheating(!ClientHelper.getInstance().isCheating());
  170. return;
  171. }
  172. ConfigManager.getInstance().openConfigScreen(ScreenHelper.getLastHandledScreen());
  173. }
  174. @Override
  175. public void render(int mouseX, int mouseY, float delta) {
  176. }
  177. @Override
  178. public void lateRender(int mouseX, int mouseY, float delta) {
  179. setZOffset(600);
  180. super.render(mouseX, mouseY, delta);
  181. Rectangle bounds = getBounds();
  182. if (ClientHelper.getInstance().isCheating() && RoughlyEnoughItemsCore.hasOperatorPermission()) {
  183. if (RoughlyEnoughItemsCore.hasPermissionToUsePackets())
  184. fillGradient(bounds.x + 1, bounds.y + 1, bounds.getMaxX() - 1, bounds.getMaxY() - 1, 721354752, 721354752);
  185. else
  186. fillGradient(bounds.x + 1, bounds.y + 1, bounds.getMaxX() - 1, bounds.getMaxY() - 1, 1476440063, 1476440063);
  187. }
  188. MinecraftClient.getInstance().getTextureManager().bindTexture(CHEST_GUI_TEXTURE);
  189. RenderSystem.color4f(1.0F, 1.0F, 1.0F, 1.0F);
  190. blit(bounds.x + 3, bounds.y + 3, 0, 0, 14, 14);
  191. setZOffset(0);
  192. }
  193. @Override
  194. public Optional<String> getTooltips() {
  195. String tooltips = I18n.translate("text.rei.config_tooltip");
  196. tooltips += "\n ";
  197. if (!ClientHelper.getInstance().isCheating())
  198. tooltips += "\n" + I18n.translate("text.rei.cheating_disabled");
  199. else if (!RoughlyEnoughItemsCore.hasOperatorPermission())
  200. tooltips += "\n" + I18n.translate("text.rei.cheating_enabled_no_perms");
  201. else if (RoughlyEnoughItemsCore.hasPermissionToUsePackets())
  202. tooltips += "\n" + I18n.translate("text.rei.cheating_enabled");
  203. else
  204. tooltips += "\n" + I18n.translate("text.rei.cheating_limited_enabled");
  205. return Optional.ofNullable(tooltips);
  206. }
  207. @Override
  208. public boolean changeFocus(boolean boolean_1) {
  209. return false;
  210. }
  211. @Override
  212. public boolean containsMouse(double mouseX, double mouseY) {
  213. return isNotInExclusionZones(mouseX, mouseY) && super.containsMouse(mouseX, mouseY);
  214. }
  215. });
  216. if (ConfigObject.getInstance().doesShowUtilsButtons()) {
  217. widgets.add(new ButtonWidget(ConfigObject.getInstance().isLowerConfigButton() ? new Rectangle(ConfigObject.getInstance().isLeftHandSidePanel() ? window.getScaledWidth() - 30 : 10, 10, 20, 20) : new Rectangle(ConfigObject.getInstance().isLeftHandSidePanel() ? window.getScaledWidth() - 55 : 35, 10, 20, 20), NarratorManager.EMPTY) {
  218. @Override
  219. public void onPressed() {
  220. MinecraftClient.getInstance().player.sendChatMessage(ConfigObject.getInstance().getGamemodeCommand().replaceAll("\\{gamemode}", getNextGameMode(Screen.hasShiftDown()).getName()));
  221. }
  222. @Override
  223. public void render(int mouseX, int mouseY, float delta) {
  224. setText(getGameModeShortText(getCurrentGameMode()));
  225. super.render(mouseX, mouseY, delta);
  226. }
  227. @Override
  228. public boolean containsMouse(double mouseX, double mouseY) {
  229. return isNotInExclusionZones(mouseX, mouseY) && super.containsMouse(mouseX, mouseY);
  230. }
  231. }.tooltip(() -> I18n.translate("text.rei.gamemode_button.tooltip", getGameModeText(getNextGameMode(Screen.hasShiftDown())))).canChangeFocuses(false));
  232. int xxx = ConfigObject.getInstance().isLeftHandSidePanel() ? window.getScaledWidth() - 30 : 10;
  233. for (Weather weather : Weather.values()) {
  234. widgets.add(new ButtonWidget(new Rectangle(xxx, 35, 20, 20), NarratorManager.EMPTY) {
  235. @Override
  236. public void onPressed() {
  237. MinecraftClient.getInstance().player.sendChatMessage(ConfigObject.getInstance().getWeatherCommand().replaceAll("\\{weather}", weather.name().toLowerCase(Locale.ROOT)));
  238. }
  239. @Override
  240. public void render(int mouseX, int mouseY, float delta) {
  241. super.render(mouseX, mouseY, delta);
  242. MinecraftClient.getInstance().getTextureManager().bindTexture(CHEST_GUI_TEXTURE);
  243. RenderSystem.color4f(1.0F, 1.0F, 1.0F, 1.0F);
  244. blit(getBounds().x + 3, getBounds().y + 3, weather.getId() * 14, 14, 14, 14);
  245. }
  246. @Override
  247. public boolean containsMouse(double mouseX, double mouseY) {
  248. return isNotInExclusionZones(mouseX, mouseY) && super.containsMouse(mouseX, mouseY);
  249. }
  250. }.tooltip(() -> I18n.translate("text.rei.weather_button.tooltip", I18n.translate(weather.getTranslateKey()))).canChangeFocuses(false));
  251. xxx += ConfigObject.getInstance().isLeftHandSidePanel() ? -25 : 25;
  252. }
  253. }
  254. if (!ConfigObject.getInstance().isEntryListWidgetScrolled()) {
  255. widgets.add(Widgets.createClickableLabel(new Point(bounds.x + (bounds.width / 2), bounds.y + (ConfigObject.getInstance().getSearchFieldLocation() == SearchFieldLocation.TOP_SIDE ? 24 : 0) + 10), "", label -> {
  256. ENTRY_LIST_WIDGET.setPage(0);
  257. ENTRY_LIST_WIDGET.updateEntriesPosition();
  258. }).tooltipLine(I18n.translate("text.rei.go_back_first_page")).focusable(false).onRender(label -> {
  259. label.setClickable(ENTRY_LIST_WIDGET.getTotalPages() > 1);
  260. label.setText(String.format("%s/%s", ENTRY_LIST_WIDGET.getPage() + 1, Math.max(ENTRY_LIST_WIDGET.getTotalPages(), 1)));
  261. }));
  262. }
  263. if (ConfigObject.getInstance().isCraftableFilterEnabled()) {
  264. this.widgets.add(craftableToggleButton = new CraftableToggleButtonWidget(getCraftableToggleArea()) {
  265. @Override
  266. public void onPressed() {
  267. ConfigManager.getInstance().toggleCraftableOnly();
  268. ENTRY_LIST_WIDGET.updateSearch(ScreenHelper.getSearchField().getText(), true);
  269. }
  270. @Override
  271. public boolean containsMouse(double mouseX, double mouseY) {
  272. return isNotInExclusionZones(mouseX, mouseY) && super.containsMouse(mouseX, mouseY);
  273. }
  274. });
  275. } else {
  276. craftableToggleButton = null;
  277. }
  278. }
  279. private Weather getNextWeather() {
  280. try {
  281. Weather current = getCurrentWeather();
  282. int next = current.getId() + 1;
  283. if (next >= 3)
  284. next = 0;
  285. return Weather.byId(next);
  286. } catch (Exception e) {
  287. return Weather.CLEAR;
  288. }
  289. }
  290. private Weather getCurrentWeather() {
  291. ClientWorld world = MinecraftClient.getInstance().world;
  292. if (world.isThundering())
  293. return Weather.THUNDER;
  294. if (world.getLevelProperties().isRaining())
  295. return Weather.RAIN;
  296. return Weather.CLEAR;
  297. }
  298. private String getGameModeShortText(GameMode gameMode) {
  299. return I18n.translate("text.rei.short_gamemode." + gameMode.getName());
  300. }
  301. private String getGameModeText(GameMode gameMode) {
  302. return I18n.translate("selectWorld.gameMode." + gameMode.getName());
  303. }
  304. private GameMode getNextGameMode(boolean reverse) {
  305. try {
  306. GameMode current = getCurrentGameMode();
  307. int next = current.getId() + 1;
  308. if (reverse)
  309. next -= 2;
  310. if (next > 3)
  311. next = 0;
  312. if (next < 0)
  313. next = 3;
  314. return GameMode.byId(next);
  315. } catch (Exception e) {
  316. return GameMode.NOT_SET;
  317. }
  318. }
  319. private GameMode getCurrentGameMode() {
  320. return MinecraftClient.getInstance().getNetworkHandler().getPlayerListEntry(MinecraftClient.getInstance().player.getGameProfile().getId()).getGameMode();
  321. }
  322. private Rectangle getSearchFieldArea() {
  323. int widthRemoved = 1 + (ConfigObject.getInstance().isCraftableFilterEnabled() ? 22 : 0) + (ConfigObject.getInstance().isLowerConfigButton() ? 22 : 0);
  324. SearchFieldLocation searchFieldLocation = ConfigObject.getInstance().getSearchFieldLocation();
  325. if (searchFieldLocation == SearchFieldLocation.BOTTOM_SIDE)
  326. return new Rectangle(bounds.x + 2, window.getScaledHeight() - 22, bounds.width - 6 - widthRemoved, 18);
  327. if (searchFieldLocation == SearchFieldLocation.TOP_SIDE)
  328. return new Rectangle(bounds.x + 2, 4, bounds.width - 6 - widthRemoved, 18);
  329. if (MinecraftClient.getInstance().currentScreen instanceof RecipeViewingScreen) {
  330. RecipeViewingScreen widget = (RecipeViewingScreen) MinecraftClient.getInstance().currentScreen;
  331. return new Rectangle(widget.getBounds().x, window.getScaledHeight() - 22, widget.getBounds().width - widthRemoved, 18);
  332. }
  333. if (MinecraftClient.getInstance().currentScreen instanceof VillagerRecipeViewingScreen) {
  334. VillagerRecipeViewingScreen widget = (VillagerRecipeViewingScreen) MinecraftClient.getInstance().currentScreen;
  335. return new Rectangle(widget.bounds.x, window.getScaledHeight() - 22, widget.bounds.width - widthRemoved, 18);
  336. }
  337. return new Rectangle(((ContainerScreenHooks) ScreenHelper.getLastHandledScreen()).rei_getContainerLeft(), window.getScaledHeight() - 22, ((ContainerScreenHooks) ScreenHelper.getLastHandledScreen()).rei_getContainerWidth() - widthRemoved, 18);
  338. }
  339. private Rectangle getCraftableToggleArea() {
  340. Rectangle area = getSearchFieldArea();
  341. area.setLocation(area.x + area.width + 4, area.y - 1);
  342. area.setSize(20, 20);
  343. return area;
  344. }
  345. private Rectangle getConfigButtonArea() {
  346. if (ConfigObject.getInstance().isLowerConfigButton()) {
  347. Rectangle area = getSearchFieldArea();
  348. area.setLocation(area.x + area.width + (ConfigObject.getInstance().isCraftableFilterEnabled() ? 26 : 4), area.y - 1);
  349. area.setSize(20, 20);
  350. return area;
  351. }
  352. return new Rectangle(ConfigObject.getInstance().isLeftHandSidePanel() ? window.getScaledWidth() - 30 : 10, 10, 20, 20);
  353. }
  354. private String getCheatModeText() {
  355. return I18n.translate(String.format("%s%s", "text.rei.", ClientHelper.getInstance().isCheating() ? "cheat" : "nocheat"));
  356. }
  357. @Override
  358. public Rectangle getBounds() {
  359. return bounds;
  360. }
  361. @Override
  362. public void render(int mouseX, int mouseY, float delta) {
  363. List<ItemStack> currentStacks = ClientHelper.getInstance().getInventoryItemsTypes();
  364. if (shouldReInit) {
  365. ENTRY_LIST_WIDGET.updateSearch(ScreenHelper.getSearchField().getText(), true);
  366. init();
  367. } else {
  368. for (DisplayHelper.DisplayBoundsHandler<?> handler : DisplayHelper.getInstance().getSortedBoundsHandlers(minecraft.currentScreen.getClass())) {
  369. if (handler != null && handler.shouldRecalculateArea(!ConfigObject.getInstance().isLeftHandSidePanel(), bounds)) {
  370. init();
  371. break;
  372. }
  373. }
  374. }
  375. if (ConfigManager.getInstance().isCraftableOnlyEnabled() && ((currentStacks.size() != ScreenHelper.inventoryStacks.size()) || !hasSameListContent(new LinkedList<>(ScreenHelper.inventoryStacks), currentStacks))) {
  376. ScreenHelper.inventoryStacks = currentStacks;
  377. ENTRY_LIST_WIDGET.updateSearch(ScreenHelper.getSearchField().getText(), true);
  378. }
  379. if (OverlaySearchField.isSearching) {
  380. setZOffset(200);
  381. if (MinecraftClient.getInstance().currentScreen instanceof HandledScreen) {
  382. ContainerScreenHooks hooks = (ContainerScreenHooks) MinecraftClient.getInstance().currentScreen;
  383. int left = hooks.rei_getContainerLeft(), top = hooks.rei_getContainerTop();
  384. for (Slot slot : ((HandledScreen<?>) MinecraftClient.getInstance().currentScreen).getScreenHandler().slots)
  385. if (!slot.hasStack() || !ENTRY_LIST_WIDGET.canLastSearchTermsBeAppliedTo(EntryStack.create(slot.getStack())))
  386. fillGradient(left + slot.x, top + slot.y, left + slot.x + 16, top + slot.y + 16, -601874400, -601874400);
  387. }
  388. setZOffset(0);
  389. }
  390. RenderSystem.color4f(1.0F, 1.0F, 1.0F, 1.0F);
  391. this.renderWidgets(mouseX, mouseY, delta);
  392. if (MinecraftClient.getInstance().currentScreen instanceof HandledScreen && ConfigObject.getInstance().areClickableRecipeArrowsEnabled()) {
  393. ContainerScreenHooks hooks = (ContainerScreenHooks) MinecraftClient.getInstance().currentScreen;
  394. for (RecipeHelper.ScreenClickArea area : RecipeHelper.getInstance().getScreenClickAreas())
  395. if (area.getScreenClass().equals(MinecraftClient.getInstance().currentScreen.getClass()))
  396. if (area.getRectangle().contains(mouseX - hooks.rei_getContainerLeft(), mouseY - hooks.rei_getContainerTop())) {
  397. String collect = CollectionUtils.mapAndJoinToString(area.getCategories(), identifier -> RecipeHelper.getInstance().getCategory(identifier).getCategoryName(), ", ");
  398. TOOLTIPS.add(Tooltip.create(I18n.translate("text.rei.view_recipes_for", collect)));
  399. break;
  400. }
  401. }
  402. }
  403. public void lateRender(int mouseX, int mouseY, float delta) {
  404. if (ScreenHelper.isOverlayVisible()) {
  405. ScreenHelper.getSearchField().laterRender(mouseX, mouseY, delta);
  406. if (craftableToggleButton != null)
  407. craftableToggleButton.lateRender(mouseX, mouseY, delta);
  408. configButton.lateRender(mouseX, mouseY, delta);
  409. }
  410. Screen currentScreen = MinecraftClient.getInstance().currentScreen;
  411. if (!(currentScreen instanceof RecipeViewingScreen) || !((RecipeViewingScreen) currentScreen).choosePageActivated)
  412. for (Tooltip tooltip : TOOLTIPS) {
  413. if (tooltip != null)
  414. renderTooltip(tooltip);
  415. }
  416. TOOLTIPS.clear();
  417. }
  418. public void renderTooltip(Tooltip tooltip) {
  419. renderTooltip(tooltip.getText(), tooltip.getX(), tooltip.getY());
  420. }
  421. public void renderTooltip(List<String> lines, int mouseX, int mouseY) {
  422. if (lines.isEmpty())
  423. return;
  424. tooltipWidth = lines.stream().map(font::getStringWidth).max(Integer::compareTo).get();
  425. tooltipHeight = lines.size() <= 1 ? 8 : lines.size() * 10;
  426. tooltipLines = lines;
  427. ScreenHelper.drawHoveringWidget(mouseX, mouseY, renderTooltipCallback, tooltipWidth, tooltipHeight, 0);
  428. }
  429. private boolean hasSameListContent(List<ItemStack> list1, List<ItemStack> list2) {
  430. list1.sort(Comparator.comparing(Object::toString));
  431. list2.sort(Comparator.comparing(Object::toString));
  432. return CollectionUtils.mapAndJoinToString(list1, Object::toString, "").equals(CollectionUtils.mapAndJoinToString(list2, Object::toString, ""));
  433. }
  434. public void addTooltip(@Nullable Tooltip tooltip) {
  435. if (tooltip != null)
  436. TOOLTIPS.add(tooltip);
  437. }
  438. public void renderWidgets(int int_1, int int_2, float float_1) {
  439. if (!ScreenHelper.isOverlayVisible())
  440. return;
  441. if (!ConfigObject.getInstance().isEntryListWidgetScrolled())
  442. leftButton.enabled = rightButton.enabled = ENTRY_LIST_WIDGET.getTotalPages() > 1;
  443. for (Widget widget : widgets) {
  444. widget.render(int_1, int_2, float_1);
  445. }
  446. }
  447. @Override
  448. public boolean mouseScrolled(double i, double j, double amount) {
  449. if (!ScreenHelper.isOverlayVisible())
  450. return false;
  451. if (isInside(PointHelper.ofMouse())) {
  452. if (!ConfigObject.getInstance().isEntryListWidgetScrolled()) {
  453. if (amount > 0 && leftButton.enabled)
  454. leftButton.onPressed();
  455. else if (amount < 0 && rightButton.enabled)
  456. rightButton.onPressed();
  457. else
  458. return false;
  459. return true;
  460. } else if (ENTRY_LIST_WIDGET.mouseScrolled(i, j, amount))
  461. return true;
  462. }
  463. if (isNotInExclusionZones(PointHelper.getMouseX(), PointHelper.getMouseY())) {
  464. if (favoritesListWidget != null && favoritesListWidget.mouseScrolled(i, j, amount))
  465. return true;
  466. }
  467. for (Widget widget : widgets)
  468. if (widget != ENTRY_LIST_WIDGET && (favoritesListWidget == null || widget != favoritesListWidget) && widget.mouseScrolled(i, j, amount))
  469. return true;
  470. return false;
  471. }
  472. @Override
  473. public boolean keyPressed(int int_1, int int_2, int int_3) {
  474. if (ScreenHelper.isOverlayVisible()) {
  475. if (ScreenHelper.getSearchField().keyPressed(int_1, int_2, int_3))
  476. return true;
  477. for (Element listener : widgets)
  478. if (listener != ScreenHelper.getSearchField() && listener.keyPressed(int_1, int_2, int_3))
  479. return true;
  480. }
  481. if (ConfigObject.getInstance().getHideKeybind().matchesKey(int_1, int_2)) {
  482. ScreenHelper.toggleOverlayVisible();
  483. return true;
  484. }
  485. ItemStack itemStack = null;
  486. if (MinecraftClient.getInstance().currentScreen instanceof HandledScreen)
  487. if (((ContainerScreenHooks) ScreenHelper.getLastHandledScreen()).rei_getHoveredSlot() != null && !((ContainerScreenHooks) ScreenHelper.getLastHandledScreen()).rei_getHoveredSlot().getStack().isEmpty())
  488. itemStack = ((ContainerScreenHooks) ScreenHelper.getLastHandledScreen()).rei_getHoveredSlot().getStack();
  489. if (itemStack != null && !itemStack.isEmpty()) {
  490. if (ConfigObject.getInstance().getRecipeKeybind().matchesKey(int_1, int_2))
  491. return ClientHelper.getInstance().executeRecipeKeyBind(itemStack);
  492. else if (ConfigObject.getInstance().getUsageKeybind().matchesKey(int_1, int_2))
  493. return ClientHelper.getInstance().executeUsageKeyBind(itemStack);
  494. }
  495. if (!ScreenHelper.isOverlayVisible())
  496. return false;
  497. if (ConfigObject.getInstance().getFocusSearchFieldKeybind().matchesKey(int_1, int_2)) {
  498. ScreenHelper.getSearchField().setFocused(true);
  499. setFocused(ScreenHelper.getSearchField());
  500. ScreenHelper.getSearchField().keybindFocusTime = System.currentTimeMillis();
  501. ScreenHelper.getSearchField().keybindFocusKey = int_1;
  502. return true;
  503. }
  504. return false;
  505. }
  506. @Override
  507. public boolean charTyped(char char_1, int int_1) {
  508. if (!ScreenHelper.isOverlayVisible())
  509. return false;
  510. if (ScreenHelper.getSearchField().charTyped(char_1, int_1))
  511. return true;
  512. for (Element listener : widgets)
  513. if (listener != ScreenHelper.getSearchField() && listener.charTyped(char_1, int_1))
  514. return true;
  515. return false;
  516. }
  517. @Override
  518. public List<? extends Element> children() {
  519. return widgets;
  520. }
  521. @Override
  522. public boolean mouseClicked(double double_1, double double_2, int int_1) {
  523. if (!ScreenHelper.isOverlayVisible())
  524. return false;
  525. if (MinecraftClient.getInstance().currentScreen instanceof HandledScreen && ConfigObject.getInstance().areClickableRecipeArrowsEnabled()) {
  526. ContainerScreenHooks hooks = (ContainerScreenHooks) MinecraftClient.getInstance().currentScreen;
  527. for (RecipeHelper.ScreenClickArea area : RecipeHelper.getInstance().getScreenClickAreas())
  528. if (area.getScreenClass().equals(MinecraftClient.getInstance().currentScreen.getClass()))
  529. if (area.getRectangle().contains(double_1 - hooks.rei_getContainerLeft(), double_2 - hooks.rei_getContainerTop())) {
  530. ClientHelper.getInstance().executeViewAllRecipesFromCategories(Arrays.asList(area.getCategories()));
  531. MinecraftClient.getInstance().getSoundManager().play(PositionedSoundInstance.master(SoundEvents.UI_BUTTON_CLICK, 1.0F));
  532. return true;
  533. }
  534. }
  535. for (Element element : widgets)
  536. if (element.mouseClicked(double_1, double_2, int_1)) {
  537. this.setFocused(element);
  538. if (int_1 == 0)
  539. this.setDragging(true);
  540. if (!(element instanceof OverlaySearchField))
  541. ScreenHelper.getSearchField().setFocused(false);
  542. return true;
  543. }
  544. return false;
  545. }
  546. @Override
  547. public boolean mouseDragged(double double_1, double double_2, int int_1, double double_3, double double_4) {
  548. if (!ScreenHelper.isOverlayVisible())
  549. return false;
  550. return (this.getFocused() != null && this.isDragging() && int_1 == 0) && this.getFocused().mouseDragged(double_1, double_2, int_1, double_3, double_4);
  551. }
  552. public boolean isInside(double mouseX, double mouseY) {
  553. return bounds.contains(mouseX, mouseY) && isNotInExclusionZones(mouseX, mouseY);
  554. }
  555. public boolean isNotInExclusionZones(double mouseX, double mouseY) {
  556. for (DisplayHelper.DisplayBoundsHandler<?> handler : DisplayHelper.getInstance().getSortedBoundsHandlers(MinecraftClient.getInstance().currentScreen.getClass())) {
  557. ActionResult in = handler.isInZone(mouseX, mouseY);
  558. if (in != ActionResult.PASS)
  559. return in == ActionResult.SUCCESS;
  560. }
  561. return true;
  562. }
  563. public boolean isInside(Point point) {
  564. return isInside(point.getX(), point.getY());
  565. }
  566. }