diff options
| author | shedaniel <daniel@shedaniel.me> | 2022-08-28 20:48:46 +0900 |
|---|---|---|
| committer | shedaniel <daniel@shedaniel.me> | 2022-08-28 21:14:21 +0900 |
| commit | fb91ed996b01f986492de4007cb86be5e68ad192 (patch) | |
| tree | b1176be6374ac6d56094c9bcf2b48226b31e68ec /runtime-frontend/overlay-entries/src/main/java | |
| parent | 94e323f75c17e297c33fba1d3afb5c47ae66a8ad (diff) | |
| download | RoughlyEnoughItems-fb91ed996b01f986492de4007cb86be5e68ad192.tar.gz RoughlyEnoughItems-fb91ed996b01f986492de4007cb86be5e68ad192.tar.bz2 RoughlyEnoughItems-fb91ed996b01f986492de4007cb86be5e68ad192.zip | |
More internal changes
Diffstat (limited to 'runtime-frontend/overlay-entries/src/main/java')
10 files changed, 745 insertions, 44 deletions
diff --git a/runtime-frontend/overlay-entries/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/entries/CollapsedEntriesTooltip.java b/runtime-frontend/overlay-entries/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/entries/CollapsedEntriesTooltip.java index 264ac057e..9521c2e5b 100644 --- a/runtime-frontend/overlay-entries/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/entries/CollapsedEntriesTooltip.java +++ b/runtime-frontend/overlay-entries/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/entries/CollapsedEntriesTooltip.java @@ -37,7 +37,7 @@ import net.minecraft.network.chat.TextComponent; import net.minecraft.util.Mth; import net.minecraft.world.inventory.tooltip.TooltipComponent; -import static me.shedaniel.rei.impl.client.gui.overlay.InternalOverlayBounds.entrySize; +import static me.shedaniel.rei.impl.client.util.InternalEntryBounds.entrySize; public class CollapsedEntriesTooltip implements ClientTooltipComponent, TooltipComponent { private static final int MAX_WIDTH = 140; diff --git a/runtime-frontend/overlay-entries/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/entries/EntryListStackEntry.java b/runtime-frontend/overlay-entries/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/entries/EntryListStackEntry.java index e1ec62fa4..a093050f5 100644 --- a/runtime-frontend/overlay-entries/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/entries/EntryListStackEntry.java +++ b/runtime-frontend/overlay-entries/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/entries/EntryListStackEntry.java @@ -49,7 +49,7 @@ import org.jetbrains.annotations.Nullable; import java.util.List; -import static me.shedaniel.rei.impl.client.gui.overlay.InternalOverlayBounds.entrySize; +import static me.shedaniel.rei.impl.client.util.InternalEntryBounds.entrySize; @SuppressWarnings("UnstableApiUsage") public class EntryListStackEntry extends DisplayedEntryWidget { diff --git a/runtime-frontend/overlay-entries/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/entries/EntryListWidgetImpl.java b/runtime-frontend/overlay-entries/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/entries/EntryListWidgetImpl.java index 8fd0d1bd7..c9c4b3d85 100644 --- a/runtime-frontend/overlay-entries/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/entries/EntryListWidgetImpl.java +++ b/runtime-frontend/overlay-entries/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/entries/EntryListWidgetImpl.java @@ -24,8 +24,6 @@ package me.shedaniel.rei.impl.client.gui.overlay.entries; import com.mojang.blaze3d.vertex.PoseStack; -import me.shedaniel.clothconfig2.api.animator.NumberAnimator; -import me.shedaniel.clothconfig2.api.animator.ValueAnimator; import me.shedaniel.math.Point; import me.shedaniel.math.Rectangle; import me.shedaniel.rei.api.client.ClientHelper; @@ -54,7 +52,6 @@ import me.shedaniel.rei.impl.client.gui.overlay.widgets.ScaleIndicatorWidget; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.screens.Screen; import net.minecraft.client.player.LocalPlayer; -import net.minecraft.network.chat.TextComponent; import net.minecraft.network.chat.TranslatableComponent; import net.minecraft.util.Mth; import net.minecraft.world.InteractionResult; @@ -64,7 +61,7 @@ import org.jetbrains.annotations.Nullable; import java.util.List; -import static me.shedaniel.rei.impl.client.gui.overlay.InternalOverlayBounds.entrySize; +import static me.shedaniel.rei.impl.client.util.InternalEntryBounds.entrySize; @ApiStatus.Internal public abstract class EntryListWidgetImpl extends WidgetWithBounds implements EntryListWidget, DraggableStackVisitorWidget { @@ -75,28 +72,8 @@ public abstract class EntryListWidgetImpl extends WidgetWithBounds implements En private final ScaleIndicatorWidget scaleIndicator = new ScaleIndicatorWidget(); public static boolean notSteppingOnExclusionZones(int left, int top, int width, int height) { - Minecraft instance = Minecraft.getInstance(); - for (OverlayDecider decider : ScreenRegistry.getInstance().getDeciders(instance.screen)) { - InteractionResult fit = canItemSlotWidgetFit(left, top, width, height, decider); - if (fit != InteractionResult.PASS) - return fit == InteractionResult.SUCCESS; - } - return true; - } - - private static InteractionResult canItemSlotWidgetFit(int left, int top, int width, int height, OverlayDecider decider) { - InteractionResult fit; - fit = decider.isInZone(left, top); - if (fit != InteractionResult.PASS) - return fit; - fit = decider.isInZone(left + width, top); - if (fit != InteractionResult.PASS) - return fit; - fit = decider.isInZone(left, top + height); - if (fit != InteractionResult.PASS) - return fit; - fit = decider.isInZone(left + width, top + height); - return fit; + ScreenOverlay overlay = ScreenOverlay.getInstance().get(); + return overlay.isNotInExclusionZones(new Rectangle(left, top, width, height)); } private boolean containsChecked(Point point, boolean inner) { diff --git a/runtime-frontend/overlay-entries/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/entries/scrolled/ScrolledEntryListWidget.java b/runtime-frontend/overlay-entries/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/entries/scrolled/ScrolledEntryListWidget.java index d539c4848..cda032b0d 100644 --- a/runtime-frontend/overlay-entries/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/entries/scrolled/ScrolledEntryListWidget.java +++ b/runtime-frontend/overlay-entries/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/entries/scrolled/ScrolledEntryListWidget.java @@ -48,7 +48,7 @@ import java.util.Collections; import java.util.List; import java.util.stream.Stream; -import static me.shedaniel.rei.impl.client.gui.overlay.InternalOverlayBounds.entrySize; +import static me.shedaniel.rei.impl.client.util.InternalEntryBounds.entrySize; public class ScrolledEntryListWidget extends CollapsingEntryListWidget { private List</*EntryStack<?> | EntryIngredient*/ Object> stacks = new ArrayList<>(); diff --git a/runtime-frontend/overlay-entries/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/widgets/ConfigButtonWidget.java b/runtime-frontend/overlay-entries/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/widgets/ConfigButtonWidgetProvider.java index faffe97dd..eabe883a5 100644 --- a/runtime-frontend/overlay-entries/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/widgets/ConfigButtonWidget.java +++ b/runtime-frontend/overlay-entries/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/widgets/ConfigButtonWidgetProvider.java @@ -30,6 +30,7 @@ import me.shedaniel.rei.api.client.ClientHelper; 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.FavoriteMenuEntry; import me.shedaniel.rei.api.client.gui.config.AppearanceTheme; import me.shedaniel.rei.api.client.gui.config.DisplayPanelLocation; import me.shedaniel.rei.api.client.gui.config.SyntaxHighlightingMode; @@ -43,8 +44,7 @@ import me.shedaniel.rei.api.common.networking.NetworkingHelper; import me.shedaniel.rei.impl.client.config.ConfigManagerInternal; import me.shedaniel.rei.impl.client.gui.InternalTextures; import me.shedaniel.rei.impl.client.gui.menu.MenuAccess; -import me.shedaniel.rei.impl.client.gui.menu.MenuEntry; -import me.shedaniel.rei.impl.client.gui.menu.entries.*; +import me.shedaniel.rei.impl.client.gui.overlay.menu.entries.*; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.chat.NarratorChatListener; import net.minecraft.client.gui.screens.Screen; @@ -56,7 +56,7 @@ import java.util.UUID; import java.util.function.Consumer; import java.util.function.UnaryOperator; -public class ConfigButtonWidget implements OverlayWidgetProvider { +public class ConfigButtonWidgetProvider implements OverlayWidgetProvider { private static final UUID CONFIG_MENU_UUID = UUID.fromString("4357bc36-0a4e-47d2-8e07-ddc220df4a0f"); @Override @@ -81,7 +81,7 @@ public class ConfigButtonWidget implements OverlayWidgetProvider { button.removeTint(); } - access.openOrClose(CONFIG_MENU_UUID, button.getBounds(), ConfigButtonWidget::menuEntries); + access.openOrClose(CONFIG_MENU_UUID, button.getBounds(), ConfigButtonWidgetProvider::menuEntries); }) .focusable(false) .containsMousePredicate((button, point) -> button.getBounds().contains(point) && overlay.isNotInExclusionZones(point.x, point.y)); @@ -94,7 +94,7 @@ public class ConfigButtonWidget implements OverlayWidgetProvider { return lateRenderable.apply(Widgets.concat(configButton, overlayWidget)); } - private static Collection<MenuEntry> menuEntries() { + private static Collection<FavoriteMenuEntry> menuEntries() { ConfigManagerInternal manager = ConfigManagerInternal.getInstance(); ConfigObject config = ConfigObject.getInstance(); return List.of( diff --git a/runtime-frontend/overlay-entries/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/widgets/CraftableFilterButtonWidget.java b/runtime-frontend/overlay-entries/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/widgets/CraftableFilterButtonWidgetProvider.java index 63ff5fd0d..f5fbc42a0 100644 --- a/runtime-frontend/overlay-entries/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/widgets/CraftableFilterButtonWidget.java +++ b/runtime-frontend/overlay-entries/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/widgets/CraftableFilterButtonWidgetProvider.java @@ -28,6 +28,7 @@ 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; +import me.shedaniel.rei.api.client.favorites.FavoriteMenuEntry; import me.shedaniel.rei.api.client.gui.config.SearchFieldLocation; import me.shedaniel.rei.api.client.gui.widgets.*; import me.shedaniel.rei.api.client.overlay.OverlayListWidget; @@ -37,9 +38,8 @@ import me.shedaniel.rei.api.client.search.method.InputMethodRegistry; import me.shedaniel.rei.api.common.util.CollectionUtils; import me.shedaniel.rei.impl.client.config.ConfigManagerInternal; import me.shedaniel.rei.impl.client.gui.menu.MenuAccess; -import me.shedaniel.rei.impl.client.gui.menu.MenuEntry; -import me.shedaniel.rei.impl.client.gui.menu.entries.SubMenuEntry; -import me.shedaniel.rei.impl.client.gui.menu.entries.ToggleMenuEntry; +import me.shedaniel.rei.impl.client.gui.overlay.menu.entries.SubMenuEntry; +import me.shedaniel.rei.impl.client.gui.overlay.menu.entries.ToggleMenuEntry; import me.shedaniel.rei.impl.client.gui.screen.ConfigReloadingScreen; import me.shedaniel.rei.impl.common.InternalLogger; import net.minecraft.client.Minecraft; @@ -59,7 +59,7 @@ import java.util.concurrent.Executors; import java.util.function.Consumer; import java.util.function.UnaryOperator; -public class CraftableFilterButtonWidget implements OverlayWidgetProvider { +public class CraftableFilterButtonWidgetProvider implements OverlayWidgetProvider { public static final UUID FILTER_MENU_UUID = UUID.fromString("2839e998-1679-4f9e-a257-37411d16f1e6"); @Override @@ -84,7 +84,7 @@ public class CraftableFilterButtonWidget implements OverlayWidgetProvider { .onRender((matrices, button) -> { button.setTint(ConfigManager.getInstance().isCraftableOnlyEnabled() ? 0x3800d907 : 0x38ff0000); - access.openOrClose(FILTER_MENU_UUID, button.getBounds(), CraftableFilterButtonWidget::menuEntries); + access.openOrClose(FILTER_MENU_UUID, button.getBounds(), CraftableFilterButtonWidgetProvider::menuEntries); }) .containsMousePredicate((button, point) -> button.getBounds().contains(point) && overlay.isNotInExclusionZones(point.x, point.y)) .tooltipLineSupplier(button -> new TranslatableComponent(ConfigManager.getInstance().isCraftableOnlyEnabled() ? "text.rei.showing_craftable" : "text.rei.showing_all")); @@ -98,12 +98,12 @@ public class CraftableFilterButtonWidget implements OverlayWidgetProvider { return lateRenderable.apply(Widgets.concat(filterButton, overlayWidget)); } - private static Collection<MenuEntry> menuEntries() { + private static Collection<FavoriteMenuEntry> menuEntries() { ConfigManagerInternal manager = ConfigManagerInternal.getInstance(); ConfigObject config = ConfigObject.getInstance(); - ArrayList<MenuEntry> entries = new ArrayList<>(List.of( + ArrayList<FavoriteMenuEntry> entries = new ArrayList<>(List.of( new SubMenuEntry(new TranslatableComponent("text.rei.config.menu.search_field.position"), Arrays.stream(SearchFieldLocation.values()) - .<MenuEntry>map(location -> ToggleMenuEntry.of(new TextComponent(location.toString()), + .<FavoriteMenuEntry>map(location -> ToggleMenuEntry.of(new TextComponent(location.toString()), () -> config.getSearchFieldLocation() == location, bool -> manager.set("appearance.layout.searchFieldLocation", location)) .withActive(() -> config.getSearchFieldLocation() != location) @@ -126,11 +126,11 @@ public class CraftableFilterButtonWidget implements OverlayWidgetProvider { .toList(); } - public static List<MenuEntry> createInputMethodEntries(List<Map.Entry<ResourceLocation, InputMethod<?>>> applicableInputMethods) { + public static List<FavoriteMenuEntry> createInputMethodEntries(List<Map.Entry<ResourceLocation, InputMethod<?>>> applicableInputMethods) { ConfigManagerInternal manager = ConfigManagerInternal.getInstance(); ConfigObject config = ConfigObject.getInstance(); return applicableInputMethods.stream() - .<MenuEntry>map(pair -> ToggleMenuEntry.of(pair.getValue().getName(), + .<FavoriteMenuEntry>map(pair -> ToggleMenuEntry.of(pair.getValue().getName(), () -> Objects.equals(config.getInputMethodId(), pair.getKey()), bool -> { ExecutorService service = Executors.newSingleThreadExecutor(); diff --git a/runtime-frontend/overlay-entries/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/widgets/SearchFieldWidgetProvider.java b/runtime-frontend/overlay-entries/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/widgets/SearchFieldWidgetProvider.java new file mode 100644 index 000000000..7fb67cf34 --- /dev/null +++ b/runtime-frontend/overlay-entries/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/widgets/SearchFieldWidgetProvider.java @@ -0,0 +1,25 @@ +package me.shedaniel.rei.impl.client.gui.overlay.widgets; + +import me.shedaniel.rei.api.client.gui.widgets.TextField; +import me.shedaniel.rei.api.client.gui.widgets.Widget; +import me.shedaniel.rei.api.client.overlay.ScreenOverlay; +import me.shedaniel.rei.impl.client.gui.menu.MenuAccess; +import me.shedaniel.rei.impl.client.gui.overlay.widgets.search.OverlaySearchField; + +import java.util.List; +import java.util.function.Consumer; +import java.util.function.UnaryOperator; + +public class SearchFieldWidgetProvider implements OverlayWidgetProvider { + private OverlaySearchField searchField; + + @Override + public List<Widget> provide(ScreenOverlay overlay, MenuAccess access, Consumer<TextField> textFieldSink, UnaryOperator<Widget> lateRenderable) { + if (searchField == null) { + searchField = new OverlaySearchField(access); + } + + textFieldSink.accept(searchField); + return List.of(lateRenderable.apply(searchField)); + } +} diff --git a/runtime-frontend/overlay-entries/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/widgets/search/DelegateTextField.java b/runtime-frontend/overlay-entries/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/widgets/search/DelegateTextField.java new file mode 100644 index 000000000..d52764bff --- /dev/null +++ b/runtime-frontend/overlay-entries/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/widgets/search/DelegateTextField.java @@ -0,0 +1,182 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020, 2021, 2022 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.overlay.widgets.search; + +import com.mojang.blaze3d.platform.InputConstants; +import it.unimi.dsi.fastutil.booleans.BooleanConsumer; +import me.shedaniel.rei.api.client.gui.widgets.TextField; +import org.jetbrains.annotations.Nullable; + +import java.util.function.Consumer; +import java.util.function.Function; + +public interface DelegateTextField extends TextField { + TextField delegateTextField(); + + @Override + default void setFocusedResponder(BooleanConsumer responder) { + delegateTextField().setFocusedResponder(responder); + } + + @Override + @Nullable + default String getSuggestion() { + return delegateTextField().getSuggestion(); + } + + @Override + default void setSuggestion(@Nullable String suggestion) { + delegateTextField().setSuggestion(suggestion); + } + + @Override + default void setBorderColorProvider(BorderColorProvider borderColorProvider) { + delegateTextField().setBorderColorProvider(borderColorProvider); + } + + @Override + default void setFormatter(TextFormatter formatter) { + delegateTextField().setFormatter(formatter); + } + + @Override + default TextFormatter getFormatter() { + return delegateTextField().getFormatter(); + } + + @Override + default void setSuggestionRenderer(SuggestionRenderer renderer) { + delegateTextField().setSuggestionRenderer(renderer); + } + + @Override + default SuggestionRenderer getSuggestionRenderer() { + return delegateTextField().getSuggestionRenderer(); + } + + @Override + default void setTextTransformer(Function<String, String> textTransformer) { + delegateTextField().setTextTransformer(textTransformer); + } + + @Override + default void setResponder(Consumer<String> responder) { + delegateTextField().setResponder(responder); + } + + @Override + default String getText() { + return delegateTextField().getText(); + } + + @Override + default void setText(String text) { + delegateTextField().setText(text); + } + + @Override + default String getSelectedText() { + return delegateTextField().getSelectedText(); + } + + @Override + default void addText(String text) { + delegateTextField().addText(text); + } + + @Override + default void moveCursorTo(int cursor) { + delegateTextField().moveCursorTo(cursor); + } + + @Override + default void moveCursorToStart() { + delegateTextField().moveCursorToStart(); + } + + @Override + default void moveCursorToEnd() { + delegateTextField().moveCursorToEnd(); + } + + @Override + default int getMaxLength() { + return delegateTextField().getMaxLength(); + } + + @Override + default void setMaxLength(int maxLength) { + delegateTextField().setMaxLength(maxLength); + } + + @Override + default int getCursor() { + return delegateTextField().getCursor(); + } + + @Override + default void setCursorPosition(int cursor) { + delegateTextField().setCursorPosition(cursor); + } + + @Override + default boolean hasBorder() { + return delegateTextField().hasBorder(); + } + + @Override + default void setHasBorder(boolean hasBorder) { + delegateTextField().setHasBorder(hasBorder); + } + + @Override + default void setEditableColor(int editableColor) { + delegateTextField().setEditableColor(editableColor); + } + + @Override + default void setNotEditableColor(int notEditableColor) { + delegateTextField().setNotEditableColor(notEditableColor); + } + + @Override + default boolean isFocused() { + return delegateTextField().isFocused(); + } + + @Override + default void setFocused(boolean focused) { + delegateTextField().setFocused(focused); + } + + @Override + default void setFocusedFromKey(boolean focused, InputConstants.Key key) { + delegateTextField().setFocusedFromKey(focused, key); + } + + @Override + default void tick() { + delegateTextField().tick(); + } +} diff --git a/runtime-frontend/overlay-entries/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/widgets/search/OverlaySearchField.java b/runtime-frontend/overlay-entries/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/widgets/search/OverlaySearchField.java new file mode 100644 index 000000000..6484f82e2 --- /dev/null +++ b/runtime-frontend/overlay-entries/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/widgets/search/OverlaySearchField.java @@ -0,0 +1,430 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020, 2021, 2022 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.overlay.widgets.search; + +import com.google.common.collect.Lists; +import com.mojang.blaze3d.platform.InputConstants; +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.*; +import com.mojang.datafixers.util.Pair; +import com.mojang.math.Matrix4f; +import me.shedaniel.clothconfig2.api.animator.NumberAnimator; +import me.shedaniel.clothconfig2.api.animator.ValueAnimator; +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.config.SyntaxHighlightingMode; +import me.shedaniel.rei.api.client.gui.widgets.*; +import me.shedaniel.rei.api.client.search.SearchFilter; +import me.shedaniel.rei.api.common.util.CollectionUtils; +import me.shedaniel.rei.api.common.util.EntryStacks; +import me.shedaniel.rei.impl.client.gui.hints.HintProvider; +import me.shedaniel.rei.impl.client.gui.menu.MenuAccess; +import me.shedaniel.rei.impl.client.gui.overlay.widgets.search.OverlaySearchFieldSyntaxHighlighter.HighlightInfo; +import me.shedaniel.rei.impl.client.gui.overlay.widgets.search.OverlaySearchFieldSyntaxHighlighter.PartHighlightInfo; +import me.shedaniel.rei.impl.client.gui.overlay.widgets.search.OverlaySearchFieldSyntaxHighlighter.QuoteHighlightInfo; +import me.shedaniel.rei.impl.client.gui.overlay.widgets.search.OverlaySearchFieldSyntaxHighlighter.SplitterHighlightInfo; +import me.shedaniel.rei.impl.client.util.TextTransformations; +import net.minecraft.ChatFormatting; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen; +import net.minecraft.client.renderer.GameRenderer; +import net.minecraft.client.resources.language.I18n; +import net.minecraft.client.resources.sounds.SimpleSoundInstance; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.Style; +import net.minecraft.network.chat.TextColor; +import net.minecraft.sounds.SoundEvents; +import net.minecraft.util.FormattedCharSequence; +import net.minecraft.util.Tuple; +import net.minecraft.world.inventory.Slot; +import org.jetbrains.annotations.ApiStatus; +import org.lwjgl.glfw.GLFW; + +import java.util.List; +import java.util.Objects; +import java.util.OptionalDouble; +import java.util.function.Consumer; + +@SuppressWarnings("UnstableApiUsage") +@ApiStatus.Internal +public class OverlaySearchField extends DelegateWidget implements DelegateTextField, TextField.TextFormatter, TextField.SuggestionRenderer, TextField.BorderColorProvider { + public static boolean isHighlighting = false; + private static final Style SPLITTER_STYLE = Style.EMPTY.withColor(ChatFormatting.GRAY); + private static final Style QUOTES_STYLE = Style.EMPTY.withColor(ChatFormatting.GOLD); + private static final Style ERROR_STYLE = Style.EMPTY.withColor(TextColor.fromRgb(0xff5555)); + private final TextField textField; + private final MenuAccess access; + private boolean previouslyClicking = false; + private final OverlaySearchFieldSyntaxHighlighter highlighter; + public long keybindFocusTime = -1; + public int keybindFocusKey = -1; + public boolean isMain = true; + protected Tuple<Long, Point> lastClickedDetails = null; + private List<String> history = Lists.newArrayListWithCapacity(100); + private final NumberAnimator<Double> progress = ValueAnimator.ofDouble(); + + public OverlaySearchField(MenuAccess access) { + super(Widgets.noOp()); + this.access = access; + this.textField = Widgets.createTextField(new Rectangle()); + this.textField.setMaxLength(1000); + this.textField.setFormatter(this); + this.textField.setSuggestionRenderer(this); + this.textField.setFocusedResponder(this::focused); + this.textField.setBorderColorProvider(this); + this.highlighter = new OverlaySearchFieldSyntaxHighlighter(textField.getText()); + this.textField.setResponder(highlighter); + } + + @Override + protected Widget delegate() { + return this.textField.asWidget(); + } + + @Override + public TextField delegateTextField() { + return this.textField; + } + + @Override + public FormattedCharSequence format(String text, int index) { + boolean isPlain = ConfigObject.getInstance().getSyntaxHighlightingMode() == SyntaxHighlightingMode.PLAIN || ConfigObject.getInstance().getSyntaxHighlightingMode() == SyntaxHighlightingMode.PLAIN_UNDERSCORED; + boolean hasUnderscore = ConfigObject.getInstance().getSyntaxHighlightingMode() == SyntaxHighlightingMode.PLAIN_UNDERSCORED || ConfigObject.getInstance().getSyntaxHighlightingMode() == SyntaxHighlightingMode.COLORFUL_UNDERSCORED; + return TextTransformations.forwardWithTransformation(text, (s, charIndex, c) -> { + HighlightInfo arg = highlighter.highlighted[charIndex + index]; + Style style = Style.EMPTY; + if (isMain && REIRuntime.getInstance().getOverlay().get().getEntryList().getEntries().findAny().isEmpty() && !textField.getText().isEmpty()) { + style = ERROR_STYLE; + } + if (arg instanceof PartHighlightInfo part) { + if (!isPlain) { + style = part.style(); + } + if (part.style() != Style.EMPTY && hasUnderscore && part.grammar()) { + style = style.withUnderlined(true); + } + } else if (!isPlain) { + if (arg == SplitterHighlightInfo.INSTANCE) { + style = SPLITTER_STYLE; + } else if (arg == QuoteHighlightInfo.INSTANCE) { + style = QUOTES_STYLE; + } + } + + if (containsMouse(PointHelper.ofMouse()) || textField.isFocused()) { + return style; + } + return style.withColor(TextColor.fromRgb(Color.ofOpaque(style.getColor() == null ? -1 : style.getColor().getValue()).brighter(0.75).getColor())); + }); + } + + public void focused(boolean focused) { + if (textField.isFocused() != focused && isMain) + addToHistory(textField.getText()); + } + + @ApiStatus.Internal + public void addToHistory(String text) { + if (!text.isEmpty()) { + history.removeIf(str -> str.equalsIgnoreCase(text)); + if (history.size() > 100) + history.remove(0); + history.add(text); + } + } + + private void drawHint(PoseStack poses, int mouseX, int mouseY) { + boolean mouseDown = GLFW.glfwGetMouseButton(Minecraft.getInstance().getWindow().getWindow(), GLFW.GLFW_MOUSE_BUTTON_LEFT) != 0; + boolean clicking = false; + if (mouseDown != previouslyClicking) { + previouslyClicking = mouseDown; + clicking = mouseDown; + } + + List<HintProvider> hintProviders = HintProvider.PROVIDERS; + List<Pair<HintProvider, Component>> hints = CollectionUtils.flatMap(hintProviders, provider -> + CollectionUtils.map(provider.provide(), component -> new Pair<>(provider, component))); + if (hints.isEmpty()) return; + int width = getBounds().getWidth() - 4; + List<Pair<HintProvider, FormattedCharSequence>> sequences = CollectionUtils.flatMap(hints, pair -> + CollectionUtils.map(font.split(pair.getSecond(), width - 6), sequence -> new Pair<>(pair.getFirst(), s |
