From b07b0f77ec1327a8f927e4f4559387a0560b02ba Mon Sep 17 00:00:00 2001 From: shedaniel Date: Fri, 14 Jan 2022 23:37:16 +0800 Subject: Introduce config button menu --- .../shedaniel/rei/impl/client/REIRuntimeImpl.java | 7 +- .../rei/impl/client/config/ConfigObjectImpl.java | 28 ++++ .../rei/impl/client/gui/ScreenOverlayImpl.java | 85 +++++++++++- .../impl/client/gui/modules/AbstractMenuEntry.java | 54 ++++++++ .../rei/impl/client/gui/modules/Menu.java | 64 ++++++--- .../entries/EntryStackSubsetsMenuEntry.java | 39 ++---- .../gui/modules/entries/GameModeMenuEntry.java | 37 ++--- .../gui/modules/entries/SeparatorMenuEntry.java | 30 ++++ .../client/gui/modules/entries/SubMenuEntry.java | 130 ++++++++++++++++++ .../gui/modules/entries/SubSubsetsMenuEntry.java | 152 +++++---------------- .../gui/modules/entries/ToggleMenuEntry.java | 111 +++++++++++++++ .../gui/modules/entries/WeatherMenuEntry.java | 37 ++--- .../gui/screen/DefaultDisplayViewingScreen.java | 23 ++-- .../rei/impl/client/gui/widget/EntryWidget.java | 29 +++- .../rei/impl/client/gui/widget/TabWidget.java | 16 ++- .../client/gui/widget/basewidgets/ArrowWidget.java | 24 +++- .../gui/widget/basewidgets/BurningFireWidget.java | 24 +++- .../client/gui/widget/basewidgets/LabelWidget.java | 16 ++- .../client/gui/widget/basewidgets/PanelWidget.java | 28 +++- .../gui/widget/region/RegionEntryListEntry.java | 8 +- 20 files changed, 689 insertions(+), 253 deletions(-) create mode 100644 runtime/src/main/java/me/shedaniel/rei/impl/client/gui/modules/AbstractMenuEntry.java create mode 100644 runtime/src/main/java/me/shedaniel/rei/impl/client/gui/modules/entries/SeparatorMenuEntry.java create mode 100644 runtime/src/main/java/me/shedaniel/rei/impl/client/gui/modules/entries/SubMenuEntry.java create mode 100644 runtime/src/main/java/me/shedaniel/rei/impl/client/gui/modules/entries/ToggleMenuEntry.java (limited to 'runtime/src/main/java/me') diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/REIRuntimeImpl.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/REIRuntimeImpl.java index d5d89a653..632a371b3 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/REIRuntimeImpl.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/REIRuntimeImpl.java @@ -181,7 +181,12 @@ public class REIRuntimeImpl implements REIRuntime { @Override public ResourceLocation getDefaultDisplayTexture() { - return isDarkThemeEnabled() ? DISPLAY_TEXTURE_DARK : DISPLAY_TEXTURE; + return getDefaultDisplayTexture(isDarkThemeEnabled()); + } + + @Override + public ResourceLocation getDefaultDisplayTexture(boolean darkTheme) { + return darkTheme ? DISPLAY_TEXTURE_DARK : DISPLAY_TEXTURE; } @Override diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/config/ConfigObjectImpl.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/config/ConfigObjectImpl.java index d03b482b7..0e21e7103 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/config/ConfigObjectImpl.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/config/ConfigObjectImpl.java @@ -96,6 +96,10 @@ public class ConfigObjectImpl implements ConfigObject, ConfigData { return appearance.theme == AppearanceTheme.DARK; } + public void setUsingDarkTheme(boolean dark) { + appearance.theme = dark ? AppearanceTheme.DARK : AppearanceTheme.LIGHT; + } + @Override public boolean isGrabbingItems() { return basics.cheatingStyle == ItemCheatingStyle.GRAB; @@ -116,6 +120,10 @@ public class ConfigObjectImpl implements ConfigObject, ConfigData { return appearance.scrollingEntryListWidget; } + public void setEntryListWidgetScrolled(boolean scrollingEntryListWidget) { + appearance.scrollingEntryListWidget = scrollingEntryListWidget; + } + @Override public boolean shouldAppendModNames() { return advanced.tooltips.appendModNames; @@ -136,16 +144,28 @@ public class ConfigObjectImpl implements ConfigObject, ConfigData { return appearance.layout.searchFieldLocation; } + public void setSearchFieldLocation(SearchFieldLocation location) { + appearance.layout.searchFieldLocation = location; + } + @Override public DisplayPanelLocation getDisplayPanelLocation() { return advanced.accessibility.displayPanelLocation; } + public void setDisplayPanelLocation(DisplayPanelLocation location) { + advanced.accessibility.displayPanelLocation = location; + } + @Override public boolean isCraftableFilterEnabled() { return appearance.layout.enableCraftableOnlyButton; } + public void setCraftableFilterEnabled(boolean enabled) { + appearance.layout.enableCraftableOnlyButton = enabled; + } + @Override public String getGamemodeCommand() { return advanced.commands.gamemodeCommand; @@ -176,6 +196,10 @@ public class ConfigObjectImpl implements ConfigObject, ConfigData { return functionality.disableRecipeBook; } + public void setDisableRecipeBook(boolean disableRecipeBook) { + functionality.disableRecipeBook = disableRecipeBook; + } + @Override public boolean doesFixTabCloseContainer() { return functionality.disableRecipeBook; @@ -390,6 +414,10 @@ public class ConfigObjectImpl implements ConfigObject, ConfigData { return appearance.syntaxHighlightingMode; } + public void setSyntaxHighlightingMode(SyntaxHighlightingMode mode) { + appearance.syntaxHighlightingMode = mode; + } + @Override public SearchMode getTooltipSearchMode() { return advanced.search.tooltipSearch; diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/ScreenOverlayImpl.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/ScreenOverlayImpl.java index d9c57ea73..831cfe342 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/ScreenOverlayImpl.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/ScreenOverlayImpl.java @@ -39,6 +39,7 @@ import me.shedaniel.rei.api.client.config.ConfigObject; import me.shedaniel.rei.api.client.favorites.FavoriteEntry; import me.shedaniel.rei.api.client.gui.config.DisplayPanelLocation; import me.shedaniel.rei.api.client.gui.config.SearchFieldLocation; +import me.shedaniel.rei.api.client.gui.config.SyntaxHighlightingMode; import me.shedaniel.rei.api.client.gui.drag.DraggableStackProvider; import me.shedaniel.rei.api.client.gui.drag.DraggableStackVisitor; import me.shedaniel.rei.api.client.gui.drag.DraggingContext; @@ -62,9 +63,15 @@ import me.shedaniel.rei.api.common.util.EntryStacks; import me.shedaniel.rei.api.common.util.ImmutableTextComponent; import me.shedaniel.rei.impl.client.ClientHelperImpl; import me.shedaniel.rei.impl.client.REIRuntimeImpl; +import me.shedaniel.rei.impl.client.config.ConfigManagerImpl; +import me.shedaniel.rei.impl.client.config.ConfigObjectImpl; import me.shedaniel.rei.impl.client.gui.craftable.CraftableFilter; import me.shedaniel.rei.impl.client.gui.dragging.CurrentDraggingStack; import me.shedaniel.rei.impl.client.gui.modules.Menu; +import me.shedaniel.rei.impl.client.gui.modules.MenuEntry; +import me.shedaniel.rei.impl.client.gui.modules.entries.SeparatorMenuEntry; +import me.shedaniel.rei.impl.client.gui.modules.entries.SubMenuEntry; +import me.shedaniel.rei.impl.client.gui.modules.entries.ToggleMenuEntry; import me.shedaniel.rei.impl.client.gui.widget.*; import me.shedaniel.rei.impl.client.gui.widget.search.OverlaySearchField; import me.shedaniel.rei.impl.common.util.Weather; @@ -153,7 +160,7 @@ public class ScreenOverlayImpl extends ScreenOverlay { this.uuid = uuid; this.menu = menu; this.wrappedMenu = wrappedMenu; - this.inBounds = or.or(point -> menu.getBounds().contains(point)).and(and); + this.inBounds = or.or(menu::containsMouse).and(and); } } @@ -237,7 +244,6 @@ public class ScreenOverlayImpl extends ScreenOverlay { this.shouldReloadSearch = false; //Update Variables this.children().clear(); - this.closeOverlayMenu(); this.window = Minecraft.getInstance().getWindow(); this.screenBounds = ScreenRegistry.getInstance().getScreenBounds(Minecraft.getInstance().screen); this.bounds = calculateOverlayBounds(); @@ -277,6 +283,7 @@ public class ScreenOverlayImpl extends ScreenOverlay { } final Rectangle configButtonArea = getConfigButtonArea(); + UUID configButtonUuid = UUID.fromString("4357bc36-0a4e-47d2-8e07-ddc220df4a0f"); widgets.add(configButton = InternalWidgets.wrapLateRenderable( Widgets.withTranslate( InternalWidgets.concatWidgets( @@ -294,6 +301,19 @@ public class ScreenOverlayImpl extends ScreenOverlay { } else { button.removeTint(); } + + boolean isOpened = isMenuOpened(configButtonUuid); + if (isOpened || !isAnyMenuOpened()) { + boolean inBounds = (isNotInExclusionZones(PointHelper.getMouseFloatingX(), PointHelper.getMouseFloatingY()) && button.containsMouse(PointHelper.ofMouse())) || isMenuInBounds(configButtonUuid); + if (isOpened != inBounds) { + if (inBounds) { + Menu menu = new Menu(button.getBounds(), provideConfigButtonMenu(), false); + openMenu(configButtonUuid, menu, button::containsMouse, point -> true); + } else { + closeOverlayMenu(); + } + } + } }) .focusable(false) .containsMousePredicate((button, point) -> button.getBounds().contains(point) && isNotInExclusionZones(point.x, point.y)) @@ -327,7 +347,7 @@ public class ScreenOverlayImpl extends ScreenOverlay { widgets.add(InternalWidgets.wrapLateRenderable(Widgets.withTranslate(Widgets.createButton(subsetsButtonBounds, ClientHelperImpl.getInstance().isAprilFools.get() ? new TranslatableComponent("text.rei.tiny_potato") : new TranslatableComponent("text.rei.subsets")) .onClick(button -> { proceedOpenMenuOrElse(Menu.SUBSETS, () -> { - openMenu(Menu.SUBSETS, Menu.createSubsetsMenuFromRegistry(new Point(subsetsButtonBounds.x, subsetsButtonBounds.getMaxY())), point -> true, point -> true); + openMenu(Menu.SUBSETS, Menu.createSubsetsMenuFromRegistry(subsetsButtonBounds), point -> true, point -> true); }, menu -> { closeOverlayMenu(); }); @@ -376,6 +396,65 @@ public class ScreenOverlayImpl extends ScreenOverlay { widgets.add(draggingStack); } + private Collection provideConfigButtonMenu() { + ConfigObjectImpl config = ConfigManagerImpl.getInstance().getConfig(); + return Arrays.asList( + ToggleMenuEntry.of(new TranslatableComponent("text.rei.cheating"), + config::isCheating, + config::setCheating + ), + new SeparatorMenuEntry(), + ToggleMenuEntry.ofDeciding(new TranslatableComponent("text.rei.config.menu.dark_theme"), + config::isUsingDarkTheme, + dark -> { + config.setUsingDarkTheme(dark); + return false; + } + ), + ToggleMenuEntry.of(new TranslatableComponent("text.rei.config.menu.craftable_filter"), + config::isCraftableFilterEnabled, + config::setCraftableFilterEnabled + ), + new SubMenuEntry(new TranslatableComponent("text.rei.config.menu.display"), Arrays.asList( + ToggleMenuEntry.of(new TranslatableComponent("text.rei.config.menu.display.remove_recipe_book"), + config::doesDisableRecipeBook, + disableRecipeBook -> { + config.setDisableRecipeBook(disableRecipeBook); + Screen screen = Minecraft.getInstance().screen; + + if (screen != null) { + screen.init(minecraft, screen.width, screen.height); + } + } + ), + ToggleMenuEntry.of(new TranslatableComponent("text.rei.config.menu.display.left_side_panel"), + config::isLeftHandSidePanel, + bool -> config.setDisplayPanelLocation(bool ? DisplayPanelLocation.LEFT : DisplayPanelLocation.RIGHT) + ), + ToggleMenuEntry.of(new TranslatableComponent("text.rei.config.menu.display.scrolling_side_panel"), + config::isEntryListWidgetScrolled, + config::setEntryListWidgetScrolled + ), + new SeparatorMenuEntry(), + ToggleMenuEntry.of(new TranslatableComponent("text.rei.config.menu.display.side_search_field"), + () -> config.getSearchFieldLocation() != SearchFieldLocation.CENTER, + bool -> config.setSearchFieldLocation(bool ? SearchFieldLocation.BOTTOM_SIDE : SearchFieldLocation.CENTER) + ), + ToggleMenuEntry.of(new TranslatableComponent("text.rei.config.menu.display.syntax_highlighting"), + () -> config.getSyntaxHighlightingMode() == SyntaxHighlightingMode.COLORFUL || config.getSyntaxHighlightingMode() == SyntaxHighlightingMode.COLORFUL_UNDERSCORED, + bool -> config.setSyntaxHighlightingMode(bool ? SyntaxHighlightingMode.COLORFUL : SyntaxHighlightingMode.PLAIN_UNDERSCORED) + ) + )), + new SeparatorMenuEntry(), + ToggleMenuEntry.ofDeciding(new TranslatableComponent("text.rei.config.menu.config"), + () -> false, + $ -> { + ConfigManager.getInstance().openConfigScreen(REIRuntime.getInstance().getPreviousScreen()); + return false; + }) + ); + } + private Rectangle getSubsetsButtonBounds() { if (ConfigObject.getInstance().isSubsetsEnabled()) { ScreenRegistry registry = ScreenRegistry.getInstance(); diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/modules/AbstractMenuEntry.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/modules/AbstractMenuEntry.java new file mode 100644 index 000000000..3b2908d2e --- /dev/null +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/modules/AbstractMenuEntry.java @@ -0,0 +1,54 @@ +package me.shedaniel.rei.impl.client.gui.modules; + +public abstract class AbstractMenuEntry extends MenuEntry { + private int x, y, width; + private boolean selected, containsMouse, rendering; + + @Override + public void updateInformation(int xPos, int yPos, boolean selected, boolean containsMouse, boolean rendering, int width) { + this.x = xPos; + this.y = yPos; + this.selected = selected; + this.containsMouse = containsMouse; + this.rendering = rendering; + this.width = width; + } + + @Override + public boolean mouseClicked(double mouseX, double mouseY, int button) { + if (isRendering() && mouseX >= getX() && mouseX <= getX() + getWidth() && mouseY >= getY() && mouseY < getY() + getEntryHeight()) { + if (onClick(mouseX, mouseY, button)) { + return true; + } + } + return super.mouseClicked(mouseX, mouseY, button); + } + + protected boolean onClick(double mouseX, double mouseY, int button) { + return false; + } + + public int getX() { + return x; + } + + public int getY() { + return y; + } + + public int getWidth() { + return width; + } + + public boolean isSelected() { + return selected; + } + + public boolean containsMouse() { + return containsMouse; + } + + public boolean isRendering() { + return rendering; + } +} diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/modules/Menu.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/modules/Menu.java index 7c6505c98..475da54e4 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/modules/Menu.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/modules/Menu.java @@ -41,10 +41,13 @@ import me.shedaniel.rei.api.common.entry.EntryStack; import me.shedaniel.rei.api.common.util.CollectionUtils; import me.shedaniel.rei.api.common.util.EntryStacks; import me.shedaniel.rei.impl.client.gui.modules.entries.EntryStackSubsetsMenuEntry; +import me.shedaniel.rei.impl.client.gui.modules.entries.SubMenuEntry; import me.shedaniel.rei.impl.client.gui.modules.entries.SubSubsetsMenuEntry; import me.shedaniel.rei.impl.client.gui.widget.LateRenderable; +import net.minecraft.client.Minecraft; import net.minecraft.client.resources.language.I18n; import net.minecraft.core.Registry; +import net.minecraft.network.chat.TranslatableComponent; import net.minecraft.world.item.CreativeModeTab; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; @@ -61,6 +64,8 @@ public class Menu extends WidgetWithBounds implements LateRenderable { public static final UUID GAME_TYPE = UUID.randomUUID(); public final Point menuStartPoint; + public final boolean facingRight; + public final boolean facingDownwards; private final List entries = Lists.newArrayList(); public final ScrollingContainer scrolling = new ScrollingContainer() { @Override @@ -83,12 +88,26 @@ public class Menu extends WidgetWithBounds implements LateRenderable { } }; - public Menu(Point menuStartPoint, Collection entries) { - this.menuStartPoint = menuStartPoint; - buildEntries(entries); + public Menu(Rectangle menuStart, Collection entries, boolean sort) { + buildEntries(entries, sort); + int fullWidth = Minecraft.getInstance().screen.width; + int fullHeight = Minecraft.getInstance().screen.height; + boolean facingRight = true; + this.facingDownwards = fullHeight - menuStart.getMaxY() > menuStart.y; + int y = facingDownwards ? menuStart.getMaxY() : menuStart.y - (scrolling.getMaxScrollHeight() + 2); + boolean hasScrollBar = scrolling.getMaxScrollHeight() > getInnerHeight(y); + int menuWidth = getMaxEntryWidth() + 2 + (hasScrollBar ? 6 : 0); + if (facingRight && fullWidth - menuStart.getMaxX() < menuWidth + 10) { + facingRight = false; + } else if (!facingRight && menuStart.x < menuWidth + 10) { + facingRight = true; + } + this.facingRight = facingRight; + int x = facingRight ? menuStart.x : menuStart.getMaxX() - (getMaxEntryWidth() + 2 + (hasScrollBar ? 6 : 0)); + this.menuStartPoint = new Point(x, y); } - public static Menu createSubsetsMenuFromRegistry(Point menuStartPoint) { + public static Menu createSubsetsMenuFromRegistry(Rectangle menuStart) { EntryRegistry instance = EntryRegistry.getInstance(); List> stacks = instance.getEntryStacks().collect(Collectors.toList()); Map entries = Maps.newHashMap(); @@ -132,7 +151,7 @@ public class Menu extends WidgetWithBounds implements LateRenderable { } } } - return new Menu(menuStartPoint, buildEntries(entries)); + return new Menu(menuStart, buildEntries(entries), true); } private static Map getOrCreateSubEntryInMap(Map parent, String pathSegment) { @@ -166,12 +185,12 @@ public class Menu extends WidgetWithBounds implements LateRenderable { } else { Map entryMap = (Map) entry.getValue(); if (entry.getKey().startsWith("_item_group_")) { - entries.add(new SubSubsetsMenuEntry(I18n.get(entry.getKey().replace("_item_group_", "itemGroup.")), buildEntries(entryMap))); + entries.add(new SubSubsetsMenuEntry(new TranslatableComponent(entry.getKey().replace("_item_group_", "itemGroup.")), buildEntries(entryMap))); } else { String translationKey = "subsets.rei." + entry.getKey().replace(':', '.'); if (!I18n.exists(translationKey)) RoughlyEnoughItemsCore.LOGGER.warn("Subsets menu " + translationKey + " does not have a translation"); - entries.add(new SubSubsetsMenuEntry(I18n.get(translationKey), buildEntries(entryMap))); + entries.add(new SubSubsetsMenuEntry(new TranslatableComponent(translationKey), buildEntries(entryMap))); } } } @@ -179,11 +198,13 @@ public class Menu extends WidgetWithBounds implements LateRenderable { } @SuppressWarnings("deprecation") - private void buildEntries(Collection entries) { + private void buildEntries(Collection entries, boolean sort) { this.entries.clear(); this.entries.addAll(entries); - this.entries.sort(Comparator.comparing(entry -> entry instanceof SubSubsetsMenuEntry ? 0 : 1) - .thenComparing(entry -> entry instanceof SubSubsetsMenuEntry menuEntry ? menuEntry.text : "")); + if (sort) { + this.entries.sort(Comparator.comparing(entry -> entry instanceof SubMenuEntry ? 0 : 1) + .thenComparing(entry -> entry instanceof SubMenuEntry menuEntry ? menuEntry.text.getString() : "")); + } for (MenuEntry entry : this.entries) { entry.parent = this; } @@ -191,19 +212,19 @@ public class Menu extends WidgetWithBounds implements LateRenderable { @Override public Rectangle getBounds() { - return new Rectangle(menuStartPoint.x, menuStartPoint.y, getMaxEntryWidth() + 2 + (hasScrollBar() ? 6 : 0), getInnerHeight() + 2); + return new Rectangle(menuStartPoint.x, menuStartPoint.y, getMaxEntryWidth() + 2 + (hasScrollBar() ? 6 : 0), getInnerHeight(menuStartPoint.y) + 2); } public Rectangle getInnerBounds() { - return new Rectangle(menuStartPoint.x + 1, menuStartPoint.y + 1, getMaxEntryWidth() + (hasScrollBar() ? 6 : 0), getInnerHeight()); + return new Rectangle(menuStartPoint.x + 1, menuStartPoint.y + 1, getMaxEntryWidth() + (hasScrollBar() ? 6 : 0), getInnerHeight(menuStartPoint.y)); } public boolean hasScrollBar() { - return scrolling.getMaxScrollHeight() > getInnerHeight(); + return scrolling.getMaxScrollHeight() > getInnerHeight(menuStartPoint.y); } - public int getInnerHeight() { - return Math.min(scrolling.getMaxScrollHeight(), minecraft.screen.height - 20 - menuStartPoint.y); + public int getInnerHeight(int y) { + return Math.min(scrolling.getMaxScrollHeight(), minecraft.screen.height - 20 - y); } public int getMaxEntryWidth() { @@ -268,7 +289,7 @@ public class Menu extends WidgetWithBounds implements LateRenderable { return true; } for (MenuEntry child : children()) { - if (child instanceof SubSubsetsMenuEntry) { + if (child instanceof SubMenuEntry) { if (child.mouseScrolled(mouseX, mouseY, amount)) return true; } @@ -276,6 +297,17 @@ public class Menu extends WidgetWithBounds implements LateRenderable { return super.mouseScrolled(mouseX, mouseY, amount); } + @Override + public boolean containsMouse(double mouseX, double mouseY) { + if (super.containsMouse(mouseX, mouseY)) return true; + for (MenuEntry child : children()) { + if (child.containsMouse(mouseX, mouseY)) { + return true; + } + } + return false; + } + @Override public List children() { return entries; diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/modules/entries/EntryStackSubsetsMenuEntry.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/modules/entries/EntryStackSubsetsMenuEntry.java index 7ec5bd243..4d6c885c1 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/modules/entries/EntryStackSubsetsMenuEntry.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/modules/entries/EntryStackSubsetsMenuEntry.java @@ -36,6 +36,7 @@ import me.shedaniel.rei.api.common.entry.EntryStack; import me.shedaniel.rei.api.common.util.EntryStacks; import me.shedaniel.rei.impl.client.REIRuntimeImpl; import me.shedaniel.rei.impl.client.gui.ScreenOverlayImpl; +import me.shedaniel.rei.impl.client.gui.modules.AbstractMenuEntry; import me.shedaniel.rei.impl.client.gui.modules.Menu; import me.shedaniel.rei.impl.client.gui.modules.MenuEntry; import net.minecraft.client.gui.components.events.GuiEventListener; @@ -48,14 +49,12 @@ import java.util.List; @ApiStatus.Experimental @ApiStatus.Internal -public class EntryStackSubsetsMenuEntry extends MenuEntry { - final EntryStack stack; - private int x, y, width; - private boolean selected, containsMouse, rendering; +public class EntryStackSubsetsMenuEntry extends AbstractMenuEntry { + final EntryStack stack; private boolean clickedLast = false; private Boolean isFiltered = null; - public EntryStackSubsetsMenuEntry(EntryStack stack) { + public EntryStackSubsetsMenuEntry(EntryStack stack) { this.stack = stack; } @@ -69,28 +68,14 @@ public class EntryStackSubsetsMenuEntry extends MenuEntry { return 18; } - @Override - public void updateInformation(int xPos, int yPos, boolean selected, boolean containsMouse, boolean rendering, int width) { - this.x = xPos; - this.y = yPos; - this.selected = selected; - this.containsMouse = containsMouse; - this.rendering = rendering; - this.width = width; - } - @Override public void render(PoseStack matrices, int mouseX, int mouseY, float delta) { if (isFiltered()) { - if (selected) { - fill(matrices, x, y, x + width, y + 18, -26215); - } else { - fill(matrices, x, y, x + width, y + 18, -65536); - } - } else if (selected) { - fill(matrices, x, y, x + width, y + 18, 1174405119); + fill(matrices, getX(), getY(), getX() + getWidth(), getY() + 18, isSelected() ? -26215 : -65536); + } else if (isSelected()) { + fill(matrices, getX(), getY(), getX() + getWidth(), getY() + 18, 1174405119); } - if (containsMouse && mouseX >= x + (width / 2) - 8 && mouseX <= x + (width / 2) + 8 && mouseY >= y + 1 && mouseY <= y + 17) { + if (containsMouse() && mouseX >= getX() + (getWidth() / 2) - 8 && mouseX <= getX() + (getWidth() / 2) + 8 && mouseY >= getY() + 1 && mouseY <= getY() + 17) { REIRuntime.getInstance().queueTooltip(stack.getTooltip(new Point(mouseX, mouseY))); if (RoughlyEnoughItemsCoreClient.isLeftMousePressed && !clickedLast) { clickedLast = true; @@ -113,13 +98,13 @@ public class EntryStackSubsetsMenuEntry extends MenuEntry { } } else if (!RoughlyEnoughItemsCoreClient.isLeftMousePressed) clickedLast = false; } else clickedLast = false; - stack.render(matrices, new Rectangle(x + (width / 2) - 8, y + 1, 16, 16), mouseX, mouseY, delta); + stack.render(matrices, new Rectangle(getX() + (getWidth() / 2) - 8, getY() + 1, 16, 16), mouseX, mouseY, delta); } void recalculateFilter(Menu menu) { for (MenuEntry child : menu.children()) { - if (child instanceof SubSubsetsMenuEntry && ((SubSubsetsMenuEntry) child).getSubsetsMenu() != null) { - recalculateFilter(((SubSubsetsMenuEntry) child).getSubsetsMenu()); + if (child instanceof SubSubsetsMenuEntry && ((SubSubsetsMenuEntry) child).getChildMenu() != null) { + recalculateFilter(((SubSubsetsMenuEntry) child).getChildMenu()); } else if (child instanceof EntryStackSubsetsMenuEntry && EntryStacks.equalsExact(((EntryStackSubsetsMenuEntry) child).stack, stack)) { ((EntryStackSubsetsMenuEntry) child).isFiltered = null; } @@ -128,7 +113,7 @@ public class EntryStackSubsetsMenuEntry extends MenuEntry { @Override public boolean mouseClicked(double mouseX, double mouseY, int button) { - return rendering && mouseX >= x && mouseX <= x + width && mouseY >= y && mouseY <= y + 18; + return isRendering() && mouseX >= getX() && mouseX <= getX() + getWidth() && mouseY >= getY() && mouseY <= getY() + getEntryHeight(); } @Override diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/modules/entries/GameModeMenuEntry.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/modules/entries/GameModeMenuEntry.java index 2657ff640..6cfe7a387 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/modules/entries/GameModeMenuEntry.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/modules/entries/GameModeMenuEntry.java @@ -27,7 +27,7 @@ import com.mojang.blaze3d.vertex.PoseStack; import me.shedaniel.rei.api.client.REIRuntime; import me.shedaniel.rei.api.client.config.ConfigObject; import me.shedaniel.rei.api.client.gui.widgets.Tooltip; -import me.shedaniel.rei.impl.client.gui.modules.MenuEntry; +import me.shedaniel.rei.impl.client.gui.modules.AbstractMenuEntry; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.components.events.GuiEventListener; import net.minecraft.client.resources.sounds.SimpleSoundInstance; @@ -39,11 +39,9 @@ import java.util.Collections; import java.util.List; import java.util.Locale; -public class GameModeMenuEntry extends MenuEntry { +public class GameModeMenuEntry extends AbstractMenuEntry { public final String text; public final GameType gameMode; - private int x, y, width; - private boolean selected, containsMouse, rendering; private int textWidth = -69; public GameModeMenuEntry(GameType gameMode) { @@ -73,35 +71,22 @@ public class GameModeMenuEntry extends MenuEntry { return Collections.emptyList(); } - @Override - public void updateInformation(int xPos, int yPos, boolean selected, boolean containsMouse, boolean rendering, int width) { - this.x = xPos; - this.y = yPos; - this.selected = selected; - this.containsMouse = containsMouse; - this.rendering = rendering; - this.width = width; - } - @Override public void render(PoseStack matrices, int mouseX, int mouseY, float delta) { - if (selected) { - fill(matrices, x, y, x + width, y + 12, -12237499); + if (isSelected()) { + fill(matrices, getX(), getY(), getX() + getWidth(), getY() + getEntryHeight(), -12237499); } - if (selected && containsMouse) { + if (isSelected() && containsMouse()) { REIRuntime.getInstance().queueTooltip(Tooltip.create(new TranslatableComponent("text.rei.gamemode_button.tooltip.entry", text))); } - font.draw(matrices, text, x + 2, y + 2, selected ? 16777215 : 8947848); + font.draw(matrices, text, getX() + 2, getY() + 2, isSelected() ? 16777215 : 8947848); } @Override - public boolean mouseClicked(double mouseX, double mouseY, int button) { - if (rendering && mouseX >= x && mouseX <= x + width && mouseY >= y && mouseY <= y + 12) { - Minecraft.getInstance().player.chat(ConfigObject.getInstance().getGamemodeCommand().replaceAll("\\{gamemode}", gameMode.name().toLowerCase(Locale.ROOT))); - minecraft.getSoundManager().play(SimpleSoundInstance.forUI(SoundEvents.UI_BUTTON_CLICK, 1.0F)); - REIRuntime.getInstance().getOverlay().get().closeOverlayMenu(); - return true; - } - return super.mouseClicked(mouseX, mouseY, button); + protected boolean onClick(double mouseX, double mouseY, int button) { + Minecraft.getInstance().player.chat(ConfigObject.getInstance().getGamemodeCommand().replaceAll("\\{gamemode}", gameMode.name().toLowerCase(Locale.ROOT))); + minecraft.getSoundManager().play(SimpleSoundInstance.forUI(SoundEvents.UI_BUTTON_CLICK, 1.0F)); + REIRuntime.getInstance().getOverlay().get().closeOverlayMenu(); + return true; } } diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/modules/entries/SeparatorMenuEntry.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/modules/entries/SeparatorMenuEntry.java new file mode 100644 index 000000000..1bf754ee5 --- /dev/null +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/modules/entries/SeparatorMenuEntry.java @@ -0,0 +1,30 @@ +package me.shedaniel.rei.impl.client.gui.modules.entries; + +import com.mojang.blaze3d.vertex.PoseStack; +import me.shedaniel.rei.impl.client.gui.modules.AbstractMenuEntry; +import net.minecraft.client.gui.components.events.GuiEventListener; + +import java.util.Collections; +import java.util.List; + +public class SeparatorMenuEntry extends AbstractMenuEntry { + @Override + public int getEntryWidth() { + return 0; + } + + @Override + public int getEntryHeight() { + return 5; + } + + @Override + public List children() { + return Collections.emptyList(); + } + + @Override + public void render(PoseStack matrices, int mouseX, int mouseY, float delta) { + fillGradient(matrices, getX() + 3, getY() + 2, getX() + getWidth() - 3, getY() + 3, -7829368, -7829368); + } +} \ No newline at end of file diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/modules/entries/SubMenuEntry.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/modules/entries/SubMenuEntry.java new file mode 100644 index 000000000..4c7830343 --- /dev/null +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/modules/entries/SubMenuEntry.java @@ -0,0 +1,130 @@ +package me.shedaniel.rei.impl.client.gui.modules.entries; + +import com.google.common.base.MoreObjects; +import com.google.common.collect.Lists; +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.PoseStack; +import me.shedaniel.clothconfig2.api.ScissorsHandler; +import me.shedaniel.math.Rectangle; +import me.shedaniel.rei.api.common.util.ImmutableTextComponent; +import me.shedaniel.rei.impl.client.gui.modules.AbstractMenuEntry; +import me.shedaniel.rei.impl.client.gui.modules.Menu; +import me.shedaniel.rei.impl.client.gui.modules.MenuEntry; +import me.shedaniel.rei.impl.client.gui.widget.TabWidget; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.components.events.GuiEventListener; +import net.minecraft.network.chat.Component; + +import java.util.Collections; +import java.util.List; +import java.util.function.Supplier; + +public class SubMenuEntry extends AbstractMenuEntry { + public final Component text; + private int textWidth = -69; + protected List entries; + protected Menu childMenu; + + public SubMenuEntry(Component text) { + this(text, Collections.emptyList()); + } + + public SubMenuEntry(Component text, Supplier> entries) { + this(text, entries.get()); + } + + public SubMenuEntry(Component text, List entries) { + this.text = MoreObjects.firstNonNull(text, ImmutableTextComponent.EMPTY); + this.entries = entries; + } + + private int getTextWidth() { + if (textWidth == -69) { + this.textWidth = Math.max(0, font.width(text)); + } + return this.textWidth; + } + + public Menu getChildMenu() { + if (childMenu == null) { + this.childMenu = new Menu(new Rectangle(getParent().getBounds().x + 1, getY() - 1, getParent().getBounds().width - 2, getEntryHeight() - 2), entries, false); + } + return childMenu; + } + + @Override + public int getEntryWidth() { + return 12 + getTextWidth() + 4; + } + + @Override + public int getEntryHeight() { + return 12; + } + + @Override + public void render(PoseStack poses, int mouseX, int mouseY, float delta) { + renderBackground(poses, getX(), getY(), getWidth(), getEntryHeight()); + if (isSelected()) { + if (!entries.isEmpty()) { + Menu menu = getChildMenu(); + + Rectangle menuStart = new Rectangle(getParent().getBounds().x, getY(), getParent().getBounds().width, getEntryHeight()); + + int fullWidth = Minecraft.getInstance().screen.width; + int fullHeight = Minecraft.getInstance().screen.height; + boolean facingRight = getParent().facingRight; + int menuWidth = menu.getMaxEntryWidth() + 2 + (menu.hasScrollBar() ? 6 : 0); + if (facingRight && fullWidth - menuStart.getMaxX() < menuWidth + 10) { + facingRight = false; + } else if (!facingRight && menuStart.x < menuWidth + 10) { + facingRight = true; + } + boolean facingDownwards = fullHeight - menuStart.getMaxY() > menuStart.y; + + menu.menuStartPoint.y = facingDownwards ? menuStart.y - 1 : menuStart.getMaxY() - (menu.scrolling.getMaxScrollHeight() + 1); + menu.menuStartPoint.x = facingRight ? menuStart.getMaxX() : menuStart.x - (menu.getMaxEntryWidth() + 2 + (menu.scrolling.getMaxScrollHeight() > menu.getInnerHeight(menu.menuStartPoint.y) ? 6 : 0)); + + List areas = Lists.newArrayList(ScissorsHandler.INSTANCE.getScissorsAreas()); + ScissorsHandler.INSTANCE.clearScissors(); + menu.render(poses, mouseX, mouseY, delta); + for (Rectangle area : areas) { + ScissorsHandler.INSTANCE.scissor(area); + } + } + } + font.draw(poses, text, getX() + 2, getY() + 2, isSelected() ? 16777215 : 8947848); + if (!entries.isEmpty()) { + RenderSystem.setShaderTexture(0, TabWidget.CHEST_GUI_TEXTURE); + blit(poses, getX() + getWidth() - 15, getY() - 2, 0, 28, 18, 18); + } + } + + protected void renderBackground(PoseStack poses, int x, int y, int width, int height) { + if (isSelected()) { + fill(poses, x, y, x + width, y + height, -12237499); + } + } + + @Override + public boolean containsMouse(double mouseX, double mouseY) { + if (super.containsMouse(mouseX, mouseY)) + return true; + if (childMenu != null && !childMenu.children().isEmpty() && isSelected()) + return childMenu.containsMouse(mouseX, mouseY); + return false; + } + + @Override + public boolean mouseScrolled(double mouseX, double mouseY, double amount) { + return childMenu != null && !childMenu.children().isEmpty() && isSelected() && childMenu.mouseScrolled(mouseX, mouseY, amount); + } + + @Override + public List children() { + if (childMenu != null && !childMenu.children().isEmpty() && isSelected()) { + return Collections.singletonList(childMenu); + } + return Collections.emptyList(); + } +} diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/modules/entries/SubSubsetsMenuEntry.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/modules/entries/SubSubsetsMenuEntry.java index 4481e3e28..a7372ddcb 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/modules/entries/SubSubsetsMenuEntry.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/modules/entries/SubSubsetsMenuEntry.java @@ -23,12 +23,7 @@ package me.shedaniel.rei.impl.client.gui.modules.entries; -import com.google.common.collect.Lists; -import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.vertex.PoseStack; -import me.shedaniel.clothconfig2.api.ScissorsHandler; -import me.shedaniel.math.Point; -import me.shedaniel.math.Rectangle; import me.shedaniel.rei.api.client.REIRuntime; import me.shedaniel.rei.api.client.config.ConfigManager; import me.shedaniel.rei.api.client.config.ConfigObject; @@ -40,9 +35,8 @@ import me.shedaniel.rei.impl.client.REIRuntimeImpl; import me.shedaniel.rei.impl.client.gui.ScreenOverlayImpl; import me.shedaniel.rei.impl.client.gui.modules.Menu; import me.shedaniel.rei.impl.client.gui.modules.MenuEntry; -import me.shedaniel.rei.impl.client.gui.widget.TabWidget; -import net.minecraft.client.gui.components.events.GuiEventListener; import net.minecraft.client.resources.sounds.SimpleSoundInstance; +import net.minecraft.network.chat.Component; import net.minecraft.network.chat.TextComponent; import net.minecraft.sounds.SoundEvents; import net.minecraft.util.Mth; @@ -55,118 +49,66 @@ import java.util.function.Supplier; @ApiStatus.Experimental @ApiStatus.Internal -public class SubSubsetsMenuEntry extends MenuEntry { - public final String text; - private int textWidth = -69; - private int x, y, width; - private boolean selected, containsMouse, rendering; - private List entries; - private Menu subsetsMenu; +public class SubSubsetsMenuEntry extends SubMenuEntry { private Tuple filteredRatio = null; private long lastListHash = -1; private boolean clickedBefore = false; - public SubSubsetsMenuEntry(String text) { + public SubSubsetsMenuEntry(Component text) { this(text, Collections.emptyList()); } - public SubSubsetsMenuEntry(String text, Supplier> entries) { + public SubSubsetsMenuEntry(Component text, Supplier> entries) { this(text, entries.get()); } - public SubSubsetsMenuEntry(String text, List entries) { - this.text = text; - this.entries = entries; - } - - private int getTextWidth() { - if (textWidth == -69) { - this.textWidth = Math.max(0, font.width(text)); - } - return this.textWidth; - } - - public Menu getSubsetsMenu() { - if (subsetsMenu == null) { - this.subsetsMenu = new Menu(new Point(getParent().getBounds().getMaxX() - 1, y - 1), entries); - } - return subsetsMenu; - } - - @Override - public int getEntryWidth() { - return 12 + getTextWidth() + 4; - } - - @Override - public int getEntryHeight() { - return 12; - } - - @Override - public void updateInformation(int xPos, int yPos, boolean selected, boolean containsMouse, boolean rendering, int width) { - this.x = xPos; - this.y = yPos; - this.selected = selected; - this.containsMouse = containsMouse; - this.rendering = rendering; - this.width = width; + public SubSubsetsMenuEntry(Component text, List entries) { + super(text, entries); } @Override public void render(PoseStack matrices, int mouseX, int mouseY, float delta) { - double filteredRatio = getFilteredRatio(); - if (filteredRatio > 0) { - filteredRatio = filteredRatio * 0.85 + 0.15; - fill(matrices, x, y, x + width, y + 12, (16711680 | Mth.ceil(filteredRatio * 255.0) << 24) + (selected ? 39321 : 0)); - } else if (selected) { - fill(matrices, x, y, x + width, y + 12, -12237499); - } - if (selected) { - if (!entries.isEmpty()) { - Menu menu = getSubsetsMenu(); - menu.menuStartPoint.x = getParent().getBounds().getMaxX() - 1; - menu.menuStartPoint.y = y - 1; - List areas = Lists.newArrayList(ScissorsHandler.INSTANCE.getScissorsAreas()); - ScissorsHandler.INSTANCE.clearScissors(); - menu.render(matrices, mouseX, mouseY, delta); - for (Rectangle area : areas) { - ScissorsHandler.INSTANCE.scissor(area); - } - } else clickedBefore = false; + super.render(matrices, mouseX, mouseY, delta); + if (isSelected()) { + if (entries.isEmpty()) { + clickedBefore = false; + } if (clickedBefore) { - if (rendering && mouseX >= x && mouseX <= x + width && mouseY >= y && mouseY <= y + 12 && !entries.isEmpty()) { + if (isRendering() && mouseX >= getX() && mouseX <= getX() + getWidth() && mouseY >= getY() && mouseY <= getY() + 12 && !entries.isEmpty()) { REIRuntime.getInstance().queueTooltip(Tooltip.create(new TextComponent("Click again to filter everything in this group."))); } else clickedBefore = false; } } else clickedBefore = false; - font.draw(matrices, text, x + 2, y + 2, selected ? 16777215 : 8947848); - if (!entries.isEmpty()) { - RenderSystem.setShaderTexture(0, TabWidget.CHEST_GUI_TEXTURE); - blit(matrices, x + width - 15, y - 2, 0, 28, 18, 18); + } + + @Override + protected void renderBackground(PoseStack poses, int x, int y, int width, int height) { + double filteredRatio = getFilteredRatio(); + if (filteredRatio > 0) { + filteredRatio = filteredRatio * 0.85 + 0.15; + fill(poses, x, y, x + width, y + 12, (16711680 | Mth.ceil(filteredRatio * 255.0) << 24) + (isSelected() ? 39321 : 0)); + } else if (isSelected()) { + fill(poses, x, y, x + width, y + 12, -12237499); } } @Override - public boolean mouseClicked(double mouseX, double mouseY, int button) { - if (rendering && mouseX >= x && mouseX <= x + width && mouseY >= y && mouseY <= y + 12 && !entries.isEmpty()) { - if (clickedBefore) { - clickedBefore = false; - List> filteredStacks = ConfigObject.getInstance().getFilteredStackProviders(); - Menu overlay = ((ScreenOverlayImpl) REIRuntime.getInstance().getOverlay().get()).getOverlayMenu(); - setFiltered(filteredStacks, overlay, this, !(getFilteredRatio() > 0)); - ConfigManager.getInstance().saveConfig(); - EntryRegistry.getInstance().refilter(); - if (REIRuntimeImpl.getSearchField() != null) { - ScreenOverlayImpl.getEntryListWidget().updateSearch(REIRuntimeImpl.getSearchField().getText(), true); - } - } else { - clickedBefore = true; + protected boolean onClick(double mouseX, double mouseY, int button) { + if (clickedBefore) { + clickedBefore = false; + List> filteredStacks = ConfigObject.getInstance().getFilteredStackProviders(); + Menu overlay = ((ScreenOverlayImpl) REIRuntime.getInstance().getOverlay().get()).getOverlayMenu(); + setFiltered(filteredStacks, overlay, this, !(getFilteredRatio() > 0)); + ConfigManager.getInstance().saveConfig(); + EntryRegistry.getInstance().refilter(); + if (REIRuntimeImpl.getSearchField() != null) { + ScreenOverlayImpl.getEntryListWidget().updateSearch(REIRuntimeImpl.getSearchField().getText(), true); } - minecraft.getSoundManager().play(SimpleSoundInstance.forUI(SoundEvents.UI_BUTTON_CLICK, 1.0F)); - return true; + } else { + clickedBefore = true; } - return super.mouseClicked(mouseX, mouseY, button); + minecraft.getSoundManager().play(SimpleSoundInstance.forUI(SoundEvents.UI_BUTTON_CLICK, 1.0F)); + return true; } private void setFiltered(List> filteredStacks, Menu subsetsMenu, SubSubsetsMenuEntry subSubsetsMenuEntry, boolean filtered) { @@ -213,26 +155,4 @@ public class SubSubsetsMenuEntry extends MenuEntry { } return filteredRatio; } - - @Override - public boolean containsMouse(double mouseX, double mouseY) { - if (super.containsMouse(mouseX, mouseY)) - return true; - if (subsetsMenu != null && !subsetsMenu.children().isEmpty() && selected) - return subsetsMenu.containsMouse(mouseX, mouseY); - return false; - } - - @Override - public boolean mouseScrolled(double mouseX, double mouseY, double amount) { - return subsetsMenu != null && !subsetsMenu.children().isEmpty() && selected && subsetsMenu.mouseScrolled(mouseX, mouseY, amount); - } - - @Override - public List children() { - if (subsetsMenu != null && !subsetsMenu.children().isEmpty() && selected) { - return Collections.singletonList(subsetsMenu); - } - return Collections.emptyList(); - } } diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/modules/entries/ToggleMenuEntry.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/modules/entries/ToggleMenuEntry.java new file mode 100644 index 000000000..3fb07c81f --- /dev/null +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/modules/entries/ToggleMenuEntry.java @@ -0,0 +1,111 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020, 2021 shedaniel + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package me.shedaniel.rei.impl.client.gui.modules.entries; + +import com.mojang.blaze3d.vertex.PoseStack; +import it.unimi.dsi.fastutil.booleans.BooleanConsumer; +import me.shedaniel.rei.api.client.REIRuntime; +import me.shedaniel.rei.api.client.config.ConfigManager; +import me.shedaniel.rei.api.client.overlay.ScreenOverlay; +import me.shedaniel.rei.impl.client.gui.modules.AbstractMenuEntry; +import net.minecraft.client.gui.components.events.GuiEventListener; +import net.minecraft.client.resources.sounds.SimpleSoundInstance; +import net.minecraft.network.chat.Component; +import net.minecraft.sounds.SoundEvents; + +import java.util.Collections; +import java.util.List; +import java.util.function.BooleanSupplier; + +public class ToggleMenuEntry extends AbstractMenuEntry { + public final Component text; + public final BooleanSupplier supplier; + public final BooleanUnaryOperator consumer; + private int textWidth = -69; + + public static ToggleMenuEntry of(Component text, BooleanSupplier supplier, BooleanConsumer consumer) { + return new ToggleMenuEntry(text, supplier, b -> { + consumer.accept(b); + return true; + }); + } + + public static ToggleMenuEntry ofDeciding(Component text, BooleanSupplier supplier, BooleanUnaryOperator consumer) { + return new ToggleMenuEntry(text, supplier, consumer); + } + + protected ToggleMenuEntry(Component text, BooleanSupplier supplier, BooleanUnaryOperator consumer) { + this.text = text; + this.supplier = supplier; + this.consumer = consumer; + } + + @FunctionalInterface + public interface BooleanUnaryOperator { + boolean apply(boolean b); + } + + private int getTextWidth() { + if (textWidth == -69) { + this.textWidth = Math.max(0, font.width(text)); + } + return this.textWidth; + } + + @Override + public int getEntryWidth() { + return getTextWidth() + 4 + 6; + } + + @Override + public int getEntryHeight() { + return 12; + } + + @Override + public List children() { + return Collections.emptyList(); + } + + @Override + public void render(PoseStack matrices, int mouseX, int mouseY, float delta) { + if (isSelected()) { + fill(matrices, getX(), getY(), getX() + getWidth(), getY() + getEntryHeight(), -12237499); + } + font.draw(matrices, text, getX() + 2, getY() + 2, isSelected() ? 16777215 : 8947848); + if (supplier.getAsBoolean()) { + font.draw(matrices, "✔", getX() + getWidth() - 2 - font.width("✔"), getY() + 2, isSelected() ? 16777215 : 8947848); + } + } + + @Override + protected boolean onClick(double mouseX, double mouseY, int button) { + if (consumer.apply(!supplier.getAsBoolean())) { + REIRuntime.getInstance().getOverlay().ifPresent(ScreenOverlay::queueReloadOverlay); + } + ConfigManager.getInstance().saveConfig(); + minecraft.getSoundManager().play(SimpleSoundInstance.forUI(SoundEvents.UI_BUTTON_CLICK, 1.0F)); + return true; + } +} diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/modules/entries/WeatherMenuEntry.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/modules/entries/WeatherMenuEntry.java index 5a9bfab48..9d2feed61 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/modules/entries/WeatherMenuEntry.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/modules/entries/WeatherMenuEntry.java @@ -27,7 +27,7 @@ import com.mojang.blaze3d.vertex.PoseStack; import me.shedaniel.rei.api.client.REIRuntime; import me.shedaniel.rei.api.client.config.ConfigObject; import me.shedaniel.rei.api.client.gui.widgets.Tooltip; -import me.shedaniel.rei.impl.client.gui.modules.MenuEntry; +import me.shedaniel.rei.impl.client.gui.modules.AbstractMenuEntry; import me.shedaniel.rei.impl.common.util.Weather; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.components.events.GuiEventListener; @@ -40,11 +40,9 @@ import java.util.Collections; import java.util.List; import java.util.Locale; -public class WeatherMenuEntry extends MenuEntry { +public class WeatherMenuEntry extends AbstractMenuEntry { public final String text; public final Weather weather; - private int x, y, width; - private boolean selected, containsMouse, rendering; private int textWidth = -69; public WeatherMenuEntry(Weather weather) { @@ -74,35 +72,22 @@ public class WeatherMenuEntry extends MenuEntry { return Collections.emptyList(); } - @Override - public void updateInformation(int xPos, int yPos, boolean selected, boolean containsMouse, boolean rendering, int width) { - this.x = xPos; - this.y = yPos; - this.selected = selected; - this.containsMouse = containsMouse; - this.rendering = rendering; - this.width = width; - } - @Override public void render(PoseStack matrices, int mouseX, int mouseY, float delta) { - if (selected) { - fill(matrices, x, y, x + width, y + 12, -12237499); + if (isSelected()) { + fill(matrices, getX(), getY(), getX() + getWidth(), getY() + getEntryHeight(), -12237499); } - if (selected && containsMouse) { + if (isSelected() && containsMouse()) { REIRuntime.getInstance().queueTooltip(Tooltip.create(new TranslatableComponent("text.rei.weather_button.tooltip.entry", text))); } - font.draw(matrices, text, x + 2, y + 2, selected ? 16777215 : 8947848); + font.draw(matrices, text, getX() + 2, getY() + 2, isSelected() ? 16777215 : 8947848); } @Override - public boolean mouseClicked(double mouseX, double mouseY, int button) { - if (rendering && mouseX >= x && mouseX <= x + width && mouseY >= y && mouseY <= y + 12) { - Minecraft.getInstance().player.chat(ConfigObject.getInstance().getWeatherCommand().replaceAll("\\{weather}", weather.name().toLowerCase(Locale.ROOT))); - minecraft.getSoundManager().play(SimpleSoundInstance.forUI(SoundEvents.UI_BUTTON_CLICK, 1.0F)); - REIRuntime.getInstance().getOverlay().get().closeOverlayMenu(); - return true; - } - return super.mouseClicked(mouseX, mouseY, button); + protected boolean onClick(double mouseX, double mouseY, int button) { + Minecraft.getInstance().player.chat(ConfigObject.getInstance().getWeatherCommand().replaceAll("\\{weather}", weather.name().toLowerCase(Locale.ROOT))); + minecraft.getSoundManager().play(SimpleSoundInstance.forUI(SoundEvents.UI_BUTTON_CLICK, 1.0F)); + REIRuntime.getInstance().getOverlay().get().closeOverlayMenu(); + return true; } } diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/screen/DefaultDisplayViewingScreen.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/screen/DefaultDisplayViewingScreen.java index fc16ca16b..e8702c25b 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/screen/DefaultDisplayViewingScreen.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/screen/DefaultDisplayViewingScreen.java @@ -30,11 +30,13 @@ import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.Tesselator; import com.mojang.math.Matrix4f; import me.shedaniel.clothconfig2.api.ModifierKeyCode; +import me.shedaniel.math.Color; import me.shedaniel.math.Point; import me.shedaniel.math.Rectangle; import me.shedaniel.math.impl.PointHelper; import me.shedaniel.rei.api.client.REIRuntime; import me.shedaniel.rei.api.client.config.ConfigObject; +import me.shedaniel.rei.api.client.gui.animator.ValueAnimator; import me.shedaniel.rei.api.client.gui.widgets.Button; import me.shedaniel.rei.api.client.gui.widgets.Panel; import me.shedaniel.rei.api.client.gui.widgets.Widget; @@ -339,23 +341,23 @@ public class DefaultDisplayViewingScreen extends AbstractDisplayViewingScreen { return Mth.clamp(Mth.floor(((double) totalHeight - 36) / ((double) height + 4)) - 1, 0, Math.min(ConfigObject.getInstance().getMaxRecipePerPage() - 1, category.getMaximumDisplaysPerPage() - 1)); } + private final ValueAnimator darkStripesColor = ValueAnimator.ofColor() + .withConvention(() -> Color.ofTransparent(REIRuntime.getInstance().isDarkThemeEnabled() ? 0xFF404040 : 0xFF9E9E9E), ValueAnimator.typicalTransitionTime()); + @Override public void render(PoseStack matrices, int mouseX, int mouseY, float delta) { + darkStripesColor.update(delta); this.fillGradient(matrices, 0, 0, this.width, this.height, -1072689136, -804253680); for (Widget widget : preWidgets) { widget.render(matrices, mouseX, mouseY, delta); } - PanelWidget.render(matrices, bounds, -1); - if (REIRuntime.getInstance().isDarkThemeEnabled()) { - fill(matrices, bounds.x + 17, bounds.y + 5, bounds.x + bounds.width - 17, bounds.y + 17, 0xFF404040); - fill(matrices, bounds.x + 17, bounds.y + 19, bounds.x + bounds.width - 17, bounds.y + 30, 0xFF404040); - } else { - fill(matrices, bounds.x + 17, bounds.y + 5, bounds.x + bounds.width - 17, bounds.y + 17, 0xFF9E9E9E); - fill(matrices, bounds.x + 17, bounds.y + 19, bounds.x + bounds.width - 17, bounds.y + 31, 0xFF9E9E9E); - } + PanelWidget.render(matrices, bounds, -1, delta); + fill(matrices, bounds.x + 17, bounds.y + 5, bounds.x + bounds.width - 17, bounds.y + 17, darkStripesColor.value().getColor()); + fill(matrices, bounds.x + 17, bounds.y + 19, bounds.x + bounds.width - 17, bounds.y + 30, darkStripesColor.value().getColor()); for (TabWidget tab : tabs) { - if (!tab.isSelected()) + if (!tab.isSelected()) { tab.render(matrices, mouseX, mouseY, delta); + } } super.render(matrices, mouseX, mouseY, delta); for (Widget widget : widgets) { @@ -363,8 +365,9 @@ public class DefaultDisplayViewingScreen extends AbstractDisplayViewingScreen { } RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F); for (TabWidget tab : tabs) { - if (tab.isSelected()) + if (tab.isSelected()) { tab.render(matrices, mouseX, mouseY, delta); + } } { ModifierKeyCode export = ConfigObject.getInstance().getExportImageKeybind(); diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/EntryWidget.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/EntryWidget.java index 54b7678d4..044e906ab 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/EntryWidget.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/EntryWidget.java @@ -34,6 +34,8 @@ import me.shedaniel.rei.api.client.REIRuntime; import me.shedaniel.rei.api.client.config.ConfigManager; import me.shedaniel.rei.api.client.config.ConfigObject; import me.shedaniel.rei.api.client.favorites.FavoriteEntry; +import me.shedaniel.rei.api.client.gui.animator.NumberAnimator; +import me.shedaniel.rei.api.client.gui.animator.ValueAnimator; import me.shedaniel.rei.api.client.gui.drag.DraggableStack; import me.shedaniel.rei.api.client.gui.drag.DraggableStackProviderWidget; import me.shedaniel.rei.api.client.gui.drag.DraggedAcceptorResult; @@ -300,10 +302,23 @@ public class EntryWidget extends Slot implements DraggableStackProviderWidget { return isHighlightEnabled(); } + private final NumberAnimator darkBackgroundAlpha = ValueAnimator.ofFloat() + .withConvention(() -> REIRuntime.getInstance().isDarkThemeEnabled() ? 1.0F : 0.0F, ValueAnimator.typicalTransitionTime()) + .asFloat(); + protected void drawBackground(PoseStack matrices, int mouseX, int mouseY, float delta) { if (background) { - RenderSystem.setShaderTexture(0, REIRuntime.getInstance().isDarkThemeEnabled() ? RECIPE_GUI_DARK : RECIPE_GUI); + darkBackgroundAlpha.update(delta); + RenderSystem.enableBlend(); + RenderSystem.blendFuncSeparat