aboutsummaryrefslogtreecommitdiff
path: root/runtime-frontend/overlay-entries/src/main/java
diff options
context:
space:
mode:
authorshedaniel <daniel@shedaniel.me>2022-08-28 20:48:46 +0900
committershedaniel <daniel@shedaniel.me>2022-08-28 21:14:21 +0900
commitfb91ed996b01f986492de4007cb86be5e68ad192 (patch)
treeb1176be6374ac6d56094c9bcf2b48226b31e68ec /runtime-frontend/overlay-entries/src/main/java
parent94e323f75c17e297c33fba1d3afb5c47ae66a8ad (diff)
downloadRoughlyEnoughItems-fb91ed996b01f986492de4007cb86be5e68ad192.tar.gz
RoughlyEnoughItems-fb91ed996b01f986492de4007cb86be5e68ad192.tar.bz2
RoughlyEnoughItems-fb91ed996b01f986492de4007cb86be5e68ad192.zip
More internal changes
Diffstat (limited to 'runtime-frontend/overlay-entries/src/main/java')
-rw-r--r--runtime-frontend/overlay-entries/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/entries/CollapsedEntriesTooltip.java2
-rw-r--r--runtime-frontend/overlay-entries/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/entries/EntryListStackEntry.java2
-rw-r--r--runtime-frontend/overlay-entries/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/entries/EntryListWidgetImpl.java29
-rw-r--r--runtime-frontend/overlay-entries/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/entries/scrolled/ScrolledEntryListWidget.java2
-rw-r--r--runtime-frontend/overlay-entries/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/widgets/ConfigButtonWidgetProvider.java (renamed from runtime-frontend/overlay-entries/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/widgets/ConfigButtonWidget.java)10
-rw-r--r--runtime-frontend/overlay-entries/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/widgets/CraftableFilterButtonWidgetProvider.java (renamed from runtime-frontend/overlay-entries/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/widgets/CraftableFilterButtonWidget.java)20
-rw-r--r--runtime-frontend/overlay-entries/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/widgets/SearchFieldWidgetProvider.java25
-rw-r--r--runtime-frontend/overlay-entries/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/widgets/search/DelegateTextField.java182
-rw-r--r--runtime-frontend/overlay-entries/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/widgets/search/OverlaySearchField.java430
-rw-r--r--runtime-frontend/overlay-entries/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/widgets/search/OverlaySearchFieldSyntaxHighlighter.java87
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