diff --git a/src/main/java/dev/isxander/yacl3/gui/SearchFieldWidget.java b/src/main/java/dev/isxander/yacl3/gui/SearchFieldWidget.java index 1017982f..c84607e7 100644 --- a/src/main/java/dev/isxander/yacl3/gui/SearchFieldWidget.java +++ b/src/main/java/dev/isxander/yacl3/gui/SearchFieldWidget.java @@ -15,6 +15,7 @@ public class SearchFieldWidget extends EditBox { private final Consumer updateConsumer; private boolean isEmpty = true; + private boolean doNotUpdate = false; public SearchFieldWidget(YACLScreen yaclScreen, Font font, int x, int y, int width, int height, Component text, Component emptyText, Consumer updateConsumer) { super(font, x, y, width, height, text); @@ -33,6 +34,12 @@ public void extractWidgetRenderState(@NonNull GuiGraphicsExtractor graphics, int } } + public void setValueDoNotUpdate(String value) { + doNotUpdate = true; + setValue(value); + doNotUpdate = false; + } + private void update(String query) { boolean wasEmpty = isEmpty; isEmpty = query.isEmpty(); @@ -40,6 +47,7 @@ private void update(String query) { if (isEmpty && wasEmpty) return; + if (doNotUpdate) return; updateConsumer.accept(query); } diff --git a/src/main/java/dev/isxander/yacl3/gui/YACLScreen.java b/src/main/java/dev/isxander/yacl3/gui/YACLScreen.java index 9c7db1fc..97c593eb 100644 --- a/src/main/java/dev/isxander/yacl3/gui/YACLScreen.java +++ b/src/main/java/dev/isxander/yacl3/gui/YACLScreen.java @@ -19,6 +19,8 @@ import net.minecraft.client.gui.components.Button; import net.minecraft.client.gui.components.MultiLineLabel; import net.minecraft.client.gui.components.Tooltip; +import net.minecraft.client.gui.components.events.GuiEventListener; +import net.minecraft.client.gui.components.tabs.Tab; import net.minecraft.client.gui.components.tabs.TabManager; import net.minecraft.client.gui.navigation.ScreenRectangle; import net.minecraft.client.gui.screens.Screen; @@ -27,6 +29,7 @@ import net.minecraft.client.renderer.RenderPipelines; import net.minecraft.network.chat.CommonComponents; import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.MutableComponent; import net.minecraft.resources.Identifier; import org.jetbrains.annotations.Nullable; @@ -54,6 +57,11 @@ public class YACLScreen extends Screen { public ControllerPopupWidget currentPopupController = null; public boolean popupControllerVisible = false; + /** + * The tab where the user started searching + */ + private @Nullable CategoryTab preferredTab = null; + public YACLScreen(YetAnotherConfigLib config, Screen parent) { super(config.title()); this.config = config; @@ -284,6 +292,43 @@ public static void renderMultilineTooltip(GuiGraphicsExtractor graphics, Font fo } } + public void updateGlobalSearch(String search) { + Tab nextTabWithSearch = null; + if (preferredTab != null) { + preferredTab.optionList.getType().updateSearchQuery(search); + if (preferredTab.hasSearch()) nextTabWithSearch = preferredTab; + } + Tab currentTab = tabNavigationBar.getTabManager().getCurrentTab(); + int cursorPos = currentTab instanceof CategoryTab categoryTab ? categoryTab.searchField.getCursorPosition() : -1; + + for (int i = 0; i < tabNavigationBar.getTabs().size(); i++) { + Tab tab = tabNavigationBar.getTabs().get(i); + if (tab == preferredTab) continue; + if (tab instanceof CategoryTab categoryTab) { + categoryTab.optionList.getType().updateSearchQuery(search); + categoryTab.searchField.setValueDoNotUpdate(search); + if (cursorPos != -1) categoryTab.searchField.setCursorPosition(cursorPos); + if (nextTabWithSearch == null && categoryTab.hasSearch()) { + nextTabWithSearch = categoryTab; + } + } + } + // switch if the next tab is the preferred one or switch if the current tab does not have the search + if (nextTabWithSearch != null && nextTabWithSearch != currentTab && (nextTabWithSearch == preferredTab || !(currentTab instanceof CategoryTab categoryTab && categoryTab.hasSearch()))) { + tabManager.setCurrentTab(nextTabWithSearch, false); + if (nextTabWithSearch instanceof CategoryTab newTab) { + setFocused(newTab.searchField); + } + } + tabNavigationBar.updateTabNames(); + } + + @Override + public void setFocused(@Nullable GuiEventListener focused) { + super.setFocused(focused); + if (focused != null && !(focused instanceof SearchFieldWidget)) preferredTab = null; + } + public static class CategoryTab implements TabExt { private static final Identifier DARKER_BG = YACLPlatform.mcRl("textures/gui/menu_list_background.png"); @@ -338,7 +383,11 @@ public CategoryTab(YACLScreen screen, ConfigCategory category, ScreenRectangle t paddedWidth - 2, 18, Component.translatable("gui.recipebook.search_hint"), Component.translatable("gui.recipebook.search_hint"), - searchQuery -> optionList.getType().updateSearchQuery(searchQuery) + s -> { + if (screen.preferredTab == null) screen.preferredTab = this; + screen.updateGlobalSearch(s); + + } ); this.optionList = YACLSelectionList.asWidget( @@ -360,9 +409,17 @@ public CategoryTab(YACLScreen screen, ConfigCategory category, ScreenRectangle t updateButtons(); } + public boolean hasSearch() { + return optionList.getType().children().stream().anyMatch(o -> o.searchQueryMatches); + } + @Override public Component getTabTitle() { - return category.name(); + MutableComponent copy = category.name().copy(); + if (!hasSearch()) { + copy.withStyle(ChatFormatting.DARK_GRAY, ChatFormatting.STRIKETHROUGH); + } + return copy; } @Override diff --git a/src/main/java/dev/isxander/yacl3/gui/tab/ScrollableNavigationBar.java b/src/main/java/dev/isxander/yacl3/gui/tab/ScrollableNavigationBar.java index 0c91ca7c..33cff48a 100644 --- a/src/main/java/dev/isxander/yacl3/gui/tab/ScrollableNavigationBar.java +++ b/src/main/java/dev/isxander/yacl3/gui/tab/ScrollableNavigationBar.java @@ -153,6 +153,12 @@ protected void ensureVisible(TabButton tabButton) { } } + public void updateTabNames() { + for (TabButton tabButton : accessor.yacl$getTabButtons()) { + tabButton.setMessage(tabButton.tab().getTabTitle()); + } + } + public ImmutableList getTabs() { return accessor.yacl$getTabs(); }