EntryWidget.java 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394
  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.widget;
  24. import com.mojang.blaze3d.systems.RenderSystem;
  25. import me.shedaniel.clothconfig2.api.ModifierKeyCode;
  26. import me.shedaniel.math.Point;
  27. import me.shedaniel.math.Rectangle;
  28. import me.shedaniel.math.impl.PointHelper;
  29. import me.shedaniel.rei.api.*;
  30. import me.shedaniel.rei.api.widgets.Slot;
  31. import me.shedaniel.rei.api.widgets.Tooltip;
  32. import me.shedaniel.rei.gui.ContainerScreenOverlay;
  33. import me.shedaniel.rei.impl.ScreenHelper;
  34. import me.shedaniel.rei.utils.CollectionUtils;
  35. import net.minecraft.client.gui.Element;
  36. import net.minecraft.client.resource.language.I18n;
  37. import net.minecraft.client.sound.PositionedSoundInstance;
  38. import net.minecraft.sound.SoundEvents;
  39. import net.minecraft.util.Identifier;
  40. import net.minecraft.util.math.MathHelper;
  41. import org.jetbrains.annotations.ApiStatus;
  42. import org.jetbrains.annotations.NotNull;
  43. import org.jetbrains.annotations.Nullable;
  44. import java.util.*;
  45. public class EntryWidget extends Slot {
  46. protected static final Identifier RECIPE_GUI = new Identifier("roughlyenoughitems", "textures/gui/recipecontainer.png");
  47. protected static final Identifier RECIPE_GUI_DARK = new Identifier("roughlyenoughitems", "textures/gui/recipecontainer_dark.png");
  48. @ApiStatus.Internal
  49. private byte noticeMark = 0;
  50. protected boolean highlight = true;
  51. protected boolean tooltips = true;
  52. protected boolean background = true;
  53. protected boolean interactable = true;
  54. protected boolean interactableFavorites = true;
  55. private Rectangle bounds;
  56. private List<EntryStack> entryStacks;
  57. protected EntryWidget(int x, int y) {
  58. this(new Point(x, y));
  59. }
  60. protected EntryWidget(Point point) {
  61. this.bounds = new Rectangle(point.x - 1, point.y - 1, 18, 18);
  62. this.entryStacks = new ArrayList<>();
  63. }
  64. /**
  65. * @see me.shedaniel.rei.api.widgets.Widgets#createSlot(me.shedaniel.math.Point)
  66. */
  67. @ApiStatus.ScheduledForRemoval
  68. @Deprecated
  69. @NotNull
  70. public static EntryWidget create(int x, int y) {
  71. return create(new Point(x, y));
  72. }
  73. /**
  74. * @see me.shedaniel.rei.api.widgets.Widgets#createSlot(me.shedaniel.math.Point)
  75. */
  76. @ApiStatus.ScheduledForRemoval
  77. @Deprecated
  78. @NotNull
  79. public static EntryWidget create(Point point) {
  80. return new EntryWidget(point);
  81. }
  82. @Override
  83. @NotNull
  84. public EntryWidget unmarkInputOrOutput() {
  85. noticeMark = 0;
  86. return this;
  87. }
  88. public EntryWidget markIsInput() {
  89. noticeMark = 1;
  90. return this;
  91. }
  92. public EntryWidget markIsOutput() {
  93. noticeMark = 2;
  94. return this;
  95. }
  96. @Override
  97. public byte getNoticeMark() {
  98. return noticeMark;
  99. }
  100. @Override
  101. public void setNoticeMark(byte noticeMark) {
  102. this.noticeMark = noticeMark;
  103. }
  104. @Override
  105. public void setInteractable(boolean interactable) {
  106. interactable(interactable);
  107. }
  108. @Override
  109. public boolean isInteractable() {
  110. return this.interactable;
  111. }
  112. @Override
  113. public void setInteractableFavorites(boolean interactableFavorites) {
  114. interactableFavorites(interactableFavorites);
  115. }
  116. @Override
  117. public boolean isInteractableFavorites() {
  118. return interactableFavorites;
  119. }
  120. public EntryWidget disableInteractions() {
  121. return interactable(false);
  122. }
  123. @NotNull
  124. @Override
  125. public EntryWidget interactable(boolean b) {
  126. interactable = b;
  127. interactableFavorites = interactableFavorites && interactable;
  128. return this;
  129. }
  130. public EntryWidget disableFavoritesInteractions() {
  131. return interactableFavorites(false);
  132. }
  133. @NotNull
  134. @Override
  135. public EntryWidget interactableFavorites(boolean b) {
  136. interactableFavorites = b && interactable;
  137. return this;
  138. }
  139. public EntryWidget noHighlight() {
  140. return highlight(false);
  141. }
  142. public EntryWidget highlight(boolean b) {
  143. highlight = b;
  144. return this;
  145. }
  146. @Override
  147. public boolean isHighlightEnabled() {
  148. return highlight;
  149. }
  150. @Override
  151. public void setHighlightEnabled(boolean highlights) {
  152. highlight(highlights);
  153. }
  154. public EntryWidget noTooltips() {
  155. return tooltips(false);
  156. }
  157. public EntryWidget tooltips(boolean b) {
  158. tooltips = b;
  159. return this;
  160. }
  161. @Override
  162. public void setTooltipsEnabled(boolean tooltipsEnabled) {
  163. tooltips(tooltipsEnabled);
  164. }
  165. @Override
  166. public boolean isTooltipsEnabled() {
  167. return tooltips;
  168. }
  169. public EntryWidget noBackground() {
  170. return background(false);
  171. }
  172. public EntryWidget background(boolean b) {
  173. background = b;
  174. return this;
  175. }
  176. @Override
  177. public void setBackgroundEnabled(boolean backgroundEnabled) {
  178. background(backgroundEnabled);
  179. }
  180. @Override
  181. public boolean isBackgroundEnabled() {
  182. return background;
  183. }
  184. public EntryWidget clearStacks() {
  185. entryStacks.clear();
  186. return this;
  187. }
  188. @NotNull
  189. @Override
  190. public Slot clearEntries() {
  191. return clearStacks();
  192. }
  193. @NotNull
  194. @Override
  195. public EntryWidget entry(EntryStack stack) {
  196. entryStacks.add(stack);
  197. return this;
  198. }
  199. @NotNull
  200. @Override
  201. public EntryWidget entries(Collection<EntryStack> stacks) {
  202. entryStacks.addAll(stacks);
  203. return this;
  204. }
  205. protected EntryStack getCurrentEntry() {
  206. if (entryStacks.isEmpty())
  207. return EntryStack.empty();
  208. if (entryStacks.size() == 1)
  209. return entryStacks.get(0);
  210. return entryStacks.get(MathHelper.floor((System.currentTimeMillis() / 500 % (double) entryStacks.size()) / 1f));
  211. }
  212. @NotNull
  213. @Override
  214. public List<EntryStack> getEntries() {
  215. return entryStacks;
  216. }
  217. public List<EntryStack> entries() {
  218. return entryStacks;
  219. }
  220. @NotNull
  221. @Override
  222. public Rectangle getBounds() {
  223. return bounds;
  224. }
  225. protected Rectangle getInnerBounds() {
  226. return new Rectangle(bounds.x + 1, bounds.y + 1, bounds.width - 2, bounds.height - 2);
  227. }
  228. @Override
  229. public void render(int mouseX, int mouseY, float delta) {
  230. drawBackground(mouseX, mouseY, delta);
  231. drawCurrentEntry(mouseX, mouseY, delta);
  232. boolean highlighted = containsMouse(mouseX, mouseY);
  233. if (hasTooltips() && highlighted) {
  234. queueTooltip(mouseX, mouseY, delta);
  235. }
  236. if (hasHighlight() && highlighted) {
  237. drawHighlighted(mouseX, mouseY, delta);
  238. }
  239. }
  240. public final boolean hasTooltips() {
  241. return tooltips;
  242. }
  243. public final boolean hasHighlight() {
  244. return highlight;
  245. }
  246. protected void drawBackground(int mouseX, int mouseY, float delta) {
  247. if (background) {
  248. minecraft.getTextureManager().bindTexture(REIHelper.getInstance().isDarkThemeEnabled() ? RECIPE_GUI_DARK : RECIPE_GUI);
  249. drawTexture(bounds.x, bounds.y, 0, 222, bounds.width, bounds.height);
  250. }
  251. }
  252. protected void drawCurrentEntry(int mouseX, int mouseY, float delta) {
  253. EntryStack entry = getCurrentEntry();
  254. entry.setZ(100);
  255. entry.render(getInnerBounds(), mouseX, mouseY, delta);
  256. }
  257. protected void queueTooltip(int mouseX, int mouseY, float delta) {
  258. Tooltip tooltip = getCurrentTooltip(new Point(mouseX, mouseY));
  259. if (tooltip != null) {
  260. if (interactableFavorites && ConfigObject.getInstance().doDisplayFavoritesTooltip() && !ConfigObject.getInstance().getFavoriteKeyCode().isUnknown()) {
  261. String name = ConfigObject.getInstance().getFavoriteKeyCode().getLocalizedName();
  262. if (reverseFavoritesAction())
  263. tooltip.getText().addAll(Arrays.asList(I18n.translate("text.rei.remove_favorites_tooltip", name).split("\n")));
  264. else
  265. tooltip.getText().addAll(Arrays.asList(I18n.translate("text.rei.favorites_tooltip", name).split("\n")));
  266. }
  267. tooltip.queue();
  268. }
  269. }
  270. @Override
  271. public @Nullable Tooltip getCurrentTooltip(me.shedaniel.math.Point point) {
  272. return getCurrentEntry().getTooltip(point);
  273. }
  274. protected void drawHighlighted(int mouseX, int mouseY, float delta) {
  275. RenderSystem.disableDepthTest();
  276. RenderSystem.colorMask(true, true, true, false);
  277. int color = REIHelper.getInstance().isDarkThemeEnabled() ? -1877929711 : -2130706433;
  278. setZ(300);
  279. Rectangle bounds = getInnerBounds();
  280. fillGradient(bounds.x, bounds.y, bounds.getMaxX(), bounds.getMaxY(), color, color);
  281. setZ(0);
  282. RenderSystem.colorMask(true, true, true, true);
  283. RenderSystem.enableDepthTest();
  284. }
  285. @Override
  286. public List<? extends Element> children() {
  287. return Collections.emptyList();
  288. }
  289. @Override
  290. public boolean mouseClicked(double mouseX, double mouseY, int button) {
  291. if (!interactable)
  292. return false;
  293. if (containsMouse(mouseX, mouseY)) {
  294. if (button == 0)
  295. return ClientHelper.getInstance().executeRecipeKeyBind(getCurrentEntry());
  296. else if (button == 1)
  297. return ClientHelper.getInstance().executeUsageKeyBind(getCurrentEntry());
  298. }
  299. return false;
  300. }
  301. protected boolean reverseFavoritesAction() {
  302. return false;
  303. }
  304. @Override
  305. public boolean keyPressed(int int_1, int int_2, int int_3) {
  306. if (!interactable)
  307. return false;
  308. if (containsMouse(PointHelper.ofMouse())) {
  309. if (interactableFavorites && ConfigObject.getInstance().isFavoritesEnabled() && containsMouse(PointHelper.ofMouse()) && !getCurrentEntry().isEmpty()) {
  310. ModifierKeyCode keyCode = ConfigObject.getInstance().getFavoriteKeyCode();
  311. EntryStack entry = getCurrentEntry().copy();
  312. entry.setAmount(127);
  313. if (keyCode.matchesKey(int_1, int_2)) {
  314. if (reverseFavoritesAction())
  315. ConfigObject.getInstance().getFavorites().remove(entry);
  316. else if (!CollectionUtils.anyMatchEqualsEntryIgnoreAmount(ConfigObject.getInstance().getFavorites(), entry))
  317. ConfigObject.getInstance().getFavorites().add(entry);
  318. ConfigManager.getInstance().saveConfig();
  319. if (ConfigObject.getInstance().doDisplayFavoritesOnTheLeft()) {
  320. FavoritesListWidget favoritesListWidget = ContainerScreenOverlay.getFavoritesListWidget();
  321. if (favoritesListWidget != null)
  322. favoritesListWidget.updateSearch(ContainerScreenOverlay.getEntryListWidget(), ScreenHelper.getSearchField().getText());
  323. } else {
  324. ContainerScreenOverlay.getEntryListWidget().updateSearch(ScreenHelper.getSearchField().getText());
  325. }
  326. minecraft.getSoundManager().play(PositionedSoundInstance.master(SoundEvents.UI_BUTTON_CLICK, 1.0F));
  327. return true;
  328. }
  329. }
  330. if (ConfigObject.getInstance().getRecipeKeybind().matchesKey(int_1, int_2))
  331. return ClientHelper.getInstance().executeRecipeKeyBind(getCurrentEntry());
  332. else if (ConfigObject.getInstance().getUsageKeybind().matchesKey(int_1, int_2))
  333. return ClientHelper.getInstance().executeUsageKeyBind(getCurrentEntry());
  334. }
  335. return false;
  336. }
  337. }