diff options
| author | shedaniel <daniel@shedaniel.me> | 2022-09-11 02:32:57 +0800 |
|---|---|---|
| committer | shedaniel <daniel@shedaniel.me> | 2022-09-11 02:32:57 +0800 |
| commit | 229b1fecdac427d3debe68f52ed7276e54a11cd0 (patch) | |
| tree | dad0bbe34d45fd2ec3424890f3f4085f116ad584 /runtime-frontend/overlay/src/main/java/me | |
| parent | fb91ed996b01f986492de4007cb86be5e68ad192 (diff) | |
| download | RoughlyEnoughItems-229b1fecdac427d3debe68f52ed7276e54a11cd0.tar.gz RoughlyEnoughItems-229b1fecdac427d3debe68f52ed7276e54a11cd0.tar.bz2 RoughlyEnoughItems-229b1fecdac427d3debe68f52ed7276e54a11cd0.zip | |
Improve Overlay Menus
Diffstat (limited to 'runtime-frontend/overlay/src/main/java/me')
7 files changed, 229 insertions, 62 deletions
diff --git a/runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/ScreenOverlayImpl.java b/runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/ScreenOverlayImpl.java index ba55096b4..f4d8a1875 100644 --- a/runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/ScreenOverlayImpl.java +++ b/runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/ScreenOverlayImpl.java @@ -24,56 +24,36 @@ package me.shedaniel.rei.impl.client.gui.overlay; import com.mojang.blaze3d.platform.InputConstants; -import com.mojang.blaze3d.platform.Window; import me.shedaniel.math.Rectangle; import me.shedaniel.rei.api.client.REIRuntime; import me.shedaniel.rei.api.client.config.ConfigObject; -import me.shedaniel.rei.api.client.gui.config.SearchFieldLocation; import me.shedaniel.rei.api.client.gui.widgets.DelegateWidget; import me.shedaniel.rei.api.client.gui.widgets.TextField; import me.shedaniel.rei.api.client.gui.widgets.Widget; import me.shedaniel.rei.api.client.gui.widgets.Widgets; import me.shedaniel.rei.api.client.overlay.OverlayListWidget; -import me.shedaniel.rei.api.client.overlay.ScreenOverlay; -import me.shedaniel.rei.api.client.registry.screen.ScreenRegistry; import me.shedaniel.rei.api.client.search.SearchFilter; -import me.shedaniel.rei.impl.client.ClientInternals; +import me.shedaniel.rei.api.common.display.Display; import me.shedaniel.rei.impl.client.gui.overlay.entries.EntryListProvider; import me.shedaniel.rei.impl.client.gui.overlay.entries.EntryListWidget; import me.shedaniel.rei.impl.client.gui.overlay.entries.FavoritesListProvider; import me.shedaniel.rei.impl.client.gui.overlay.entries.FavoritesListWidget; import me.shedaniel.rei.impl.client.gui.overlay.widgets.OverlayWidgetProvider; import me.shedaniel.rei.impl.common.InternalLogger; -import net.minecraft.client.Minecraft; import net.minecraft.client.gui.components.events.GuiEventListener; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Nullable; -import java.util.List; import java.util.Objects; import java.util.Optional; +import java.util.function.BooleanSupplier; @ApiStatus.Internal public final class ScreenOverlayImpl extends AbstractScreenOverlay { - private static final List<EntryListProvider> ENTRY_LIST_PROVIDERS = ClientInternals.resolveServices(EntryListProvider.class); - private static final List<FavoritesListProvider> FAVORITES_LIST_PROVIDERS = ClientInternals.resolveServices(FavoritesListProvider.class); - private static final List<OverlayWidgetProvider> OVERLAY_WIDGET_PROVIDERS = ClientInternals.resolveServices(OverlayWidgetProvider.class); private EntryListWidget entryListWidget = null; private FavoritesListWidget favoritesListWidget = null; private TextField searchField = null; - - public static EntryListWidget getEntryListWidget() { - return getInstanceInternal().getEntryList(); - } - - @Nullable - public static FavoritesListWidget getFavoritesListWidget() { - return getInstanceInternal().getFavoritesListNullable(); - } - - private static ScreenOverlayImpl getInstanceInternal() { - return (ScreenOverlayImpl) ScreenOverlay.getInstance().orElseThrow(); - } + private BooleanSupplier isHighlighted = null; public ScreenOverlayImpl() { this.init(); @@ -84,27 +64,29 @@ public final class ScreenOverlayImpl extends AbstractScreenOverlay { super.init(); this.searchField = null; + this.isHighlighted = null; - FavoritesListWidget favoritesListWidget = getFavoritesListWidget(); + FavoritesListWidget favoritesListWidget = getFavoritesListNullable(); if (favoritesListWidget != null) { this.children().add(favoritesListWidget.asWidget()); } - EntryListWidget entryListWidget = getEntryListWidget(); + EntryListWidget entryListWidget = getEntryList(); entryListWidget.initBounds(this.getBounds()); entryListWidget.initSearch(searchField.getText(), true); this.children().add(entryListWidget.asWidget()); searchField.setResponder(s -> entryListWidget.initSearch(s, false)); entryListWidget.init(this); - for (OverlayWidgetProvider provider : OVERLAY_WIDGET_PROVIDERS) { - provider.provide(this, menuAccess(), textField -> this.searchField = textField, - LateRenderableWidget::new); + for (OverlayWidgetProvider provider : OverlayWidgetProvider.PROVIDERS) { + provider.provide(this, menuAccess(), (textField, isHighlighted) -> { + this.searchField = textField; + this.isHighlighted = isHighlighted; + }, LateRenderableWidget::new); } if (this.searchField != null) { - this.searchField.asWidget().getBounds().setBounds(getSearchFieldArea()); this.children().add(this.searchField.asWidget()); } else { InternalLogger.getInstance().warn("Search Field is not found! This might cause problems!"); @@ -117,36 +99,9 @@ public final class ScreenOverlayImpl extends AbstractScreenOverlay { } } - private Rectangle getSearchFieldArea() { - int widthRemoved = 1; - if (ConfigObject.getInstance().isCraftableFilterEnabled()) widthRemoved += 22; - if (ConfigObject.getInstance().isLowerConfigButton()) widthRemoved += 22; - SearchFieldLocation searchFieldLocation = REIRuntime.getInstance().getContextualSearchFieldLocation(); - return switch (searchFieldLocation) { - case TOP_SIDE -> getTopSideSearchFieldArea(widthRemoved); - case BOTTOM_SIDE -> getBottomSideSearchFieldArea(widthRemoved); - case CENTER -> getCenterSearchFieldArea(widthRemoved); - }; - } - - private Rectangle getTopSideSearchFieldArea(int widthRemoved) { - return new Rectangle(getBounds().x + 2, 4, getBounds().width - 6 - widthRemoved, 18); - } - - private Rectangle getBottomSideSearchFieldArea(int widthRemoved) { - Window window = Minecraft.getInstance().getWindow(); - return new Rectangle(getBounds().x + 2, window.getGuiScaledHeight() - 22, getBounds().width - 6 - widthRemoved, 18); - } - - private Rectangle getCenterSearchFieldArea(int widthRemoved) { - Window window = Minecraft.getInstance().getWindow(); - Rectangle screenBounds = ScreenRegistry.getInstance().getScreenBounds(minecraft.screen); - return new Rectangle(screenBounds.x, window.getGuiScaledHeight() - 22, screenBounds.width - widthRemoved, 18); - } - @Override protected void updateSearch() { - getEntryListWidget().initSearch(getSearchField().getText(), true); + getEntryList().initSearch(getSearchField().getText(), true); } @Override @@ -184,7 +139,7 @@ public final class ScreenOverlayImpl extends AbstractScreenOverlay { @Override public EntryListWidget getEntryList() { EntryListWidget current = null; - for (EntryListProvider provider : ENTRY_LIST_PROVIDERS) { + for (EntryListProvider provider : EntryListProvider.PROVIDERS) { current = provider.getEntryList(); if (current != null) break; } @@ -205,7 +160,7 @@ public final class ScreenOverlayImpl extends AbstractScreenOverlay { private FavoritesListWidget getFavoritesListNullable() { if (ConfigObject.getInstance().isFavoritesEnabled()) { FavoritesListWidget current = null; - for (FavoritesListProvider provider : FAVORITES_LIST_PROVIDERS) { + for (FavoritesListProvider provider : FavoritesListProvider.PROVIDERS) { current = provider.getFavoritesList(); if (current != null) break; } @@ -230,4 +185,21 @@ public final class ScreenOverlayImpl extends AbstractScreenOverlay { public SearchFilter getCurrentSearchFilter() { return getEntryList().getSearchFilter(); } + + @Override + public boolean isHighlighting() { + return this.isHighlighted != null && this.isHighlighted.getAsBoolean(); + } + + @Override + public boolean submitDisplayHistory(Display display, @Nullable Rectangle fromBounds) { + FavoritesListWidget favoritesListWidget = getFavoritesListNullable(); + + if (favoritesListWidget != null) { + favoritesListWidget.submitDisplayHistory(display, fromBounds); + return true; + } else { + return false; + } + } } diff --git a/runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/entries/EntryListProvider.java b/runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/entries/EntryListProvider.java index 0e736a595..7e47f29e7 100644 --- a/runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/entries/EntryListProvider.java +++ b/runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/entries/EntryListProvider.java @@ -23,11 +23,16 @@ package me.shedaniel.rei.impl.client.gui.overlay.entries; +import me.shedaniel.rei.impl.client.ClientInternals; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Nullable; +import java.util.List; + @ApiStatus.Internal public interface EntryListProvider { + List<EntryListProvider> PROVIDERS = ClientInternals.resolveServices(EntryListProvider.class); + @Nullable EntryListWidget getEntryList(); } diff --git a/runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/entries/FavoritesListProvider.java b/runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/entries/FavoritesListProvider.java index ca88d3934..66b43975b 100644 --- a/runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/entries/FavoritesListProvider.java +++ b/runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/entries/FavoritesListProvider.java @@ -23,12 +23,16 @@ package me.shedaniel.rei.impl.client.gui.overlay.entries; -import me.shedaniel.rei.api.client.overlay.OverlayListWidget; +import me.shedaniel.rei.impl.client.ClientInternals; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Nullable; +import java.util.List; + @ApiStatus.Internal public interface FavoritesListProvider { + List<FavoritesListProvider> PROVIDERS = ClientInternals.resolveServices(FavoritesListProvider.class); + @Nullable FavoritesListWidget getFavoritesList(); } diff --git a/runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/entries/FavoritesListWidget.java b/runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/entries/FavoritesListWidget.java index ee75003eb..f81c751fa 100644 --- a/runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/entries/FavoritesListWidget.java +++ b/runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/entries/FavoritesListWidget.java @@ -26,6 +26,9 @@ package me.shedaniel.rei.impl.client.gui.overlay.entries; import me.shedaniel.math.Rectangle; import me.shedaniel.rei.api.client.gui.widgets.Widget; import me.shedaniel.rei.api.client.overlay.OverlayListWidget; +import me.shedaniel.rei.api.common.display.Display; + +import javax.annotation.Nullable; public interface FavoritesListWidget extends OverlayListWidget { void initBounds(); @@ -33,4 +36,6 @@ public interface FavoritesListWidget extends OverlayListWidget { Widget asWidget(); Rectangle getFavoritesBounds(); + + void submitDisplayHistory(Display display, @Nullable Rectangle fromBounds); } diff --git a/runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/hints/InputMethodWatcher.java b/runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/hints/InputMethodWatcher.java new file mode 100644 index 000000000..005d367ef --- /dev/null +++ b/runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/hints/InputMethodWatcher.java @@ -0,0 +1,172 @@ +/* + * 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.hints; + +import me.shedaniel.math.Color; +import me.shedaniel.math.Point; +import me.shedaniel.rei.api.client.config.ConfigObject; +import me.shedaniel.rei.api.client.favorites.FavoriteMenuEntry; +import me.shedaniel.rei.api.client.gui.widgets.Tooltip; +import me.shedaniel.rei.api.client.gui.widgets.TooltipContext; +import me.shedaniel.rei.api.client.overlay.ScreenOverlay; +import me.shedaniel.rei.api.client.search.method.InputMethod; +import me.shedaniel.rei.api.client.search.method.InputMethodRegistry; +import me.shedaniel.rei.api.common.plugins.PluginManager; +import me.shedaniel.rei.api.common.util.CollectionUtils; +import me.shedaniel.rei.impl.client.config.ConfigManagerInternal; +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.menu.entries.SubMenuEntry; +import me.shedaniel.rei.impl.client.gui.overlay.menu.entries.ToggleMenuEntry; +import me.shedaniel.rei.impl.client.gui.overlay.menu.provider.OverlayMenuEntryProvider; +import me.shedaniel.rei.impl.client.gui.screen.ConfigReloadingScreen; +import me.shedaniel.rei.impl.common.InternalLogger; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.network.chat.TextComponent; +import net.minecraft.network.chat.TranslatableComponent; +import net.minecraft.resources.ResourceLocation; +import org.jetbrains.annotations.Nullable; + +import java.util.*; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +public class InputMethodWatcher implements HintProvider, OverlayMenuEntryProvider { + public static final UUID MENU_UUID = UUID.fromString("b93cc166-d06f-4c5f-9bf0-334d18b4adaf"); + + @Override + public List<Component> provide() { + if (PluginManager.areAnyReloading() || ScreenOverlay.getInstance().orElseThrow().isHighlighting()) return Collections.emptyList(); + ResourceLocation id = ConfigObject.getInstance().getInputMethodId(); + if (id == null) { + String languageCode = Minecraft.getInstance().options.languageCode; + MutableComponent component = new TextComponent(""); + int match = 0; + for (Map.Entry<ResourceLocation, InputMethod<?>> entry : InputMethodRegistry.getInstance().getAll().entrySet()) { + InputMethod<?> method = entry.getValue(); + if (entry.getKey().equals(new ResourceLocation("rei:default"))) continue; + if (CollectionUtils.anyMatch(method.getMatchingLocales(), locale -> locale.code().equals(languageCode))) { + if (!component.getString().isEmpty()) { + component.append(", "); + } + + component.append(method.getName()); + match++; + } + } + if (match > 0) { + return List.of(new TranslatableComponent("text.rei.input.methods.hint"), + new TextComponent(" "), component); + } + } + + return Collections.emptyList(); + } + + @Override + @Nullable + public Tooltip provideTooltip(Point mouse) { + return null; + } + + @Override + public Color getColor() { + return Color.ofTransparent(0x50ffadca); + } + + @Override + public List<HintButton> getButtons(MenuAccess access) { + return List.of( + new HintButton(new TranslatableComponent("text.rei.input.methods.hint.configure"), bounds -> { + access.openOrClose(MENU_UUID, bounds.clone(), + () -> createInputMethodEntries(getApplicableInputMethods())); + }), + new HintButton(new TranslatableComponent("text.rei.input.methods.hint.ignore"), bounds -> { + ConfigManagerInternal.getInstance().set("functionality.inputMethod", new ResourceLocation("rei:default")); + }) + ); + } + + @Override + public List<FavoriteMenuEntry> provide(Type type) { + if (type != Type.CRAFTABLE_FILTER) return List.of(); + + List<Map.Entry<ResourceLocation, InputMethod<?>>> applicableInputMethods = getApplicableInputMethods(); + if (applicableInputMethods.size() > 1) { + return List.of(new SubMenuEntry(new TranslatableComponent("text.rei.config.menu.search_field.input_method"), createInputMethodEntries(applicableInputMethods))); + } + + return List.of(); + } + + public static List<Map.Entry<ResourceLocation, InputMethod<?>>> getApplicableInputMethods() { + String languageCode = Minecraft.getInstance().options.languageCode; + return InputMethodRegistry.getInstance().getAll().entrySet().stream() + .filter(entry -> CollectionUtils.anyMatch(entry.getValue().getMatchingLocales(), locale -> locale.code().equals(languageCode))) + .toList(); + } + + public static List<FavoriteMenuEntry> createInputMethodEntries(List<Map.Entry<ResourceLocation, InputMethod<?>>> applicableInputMethods) { + ConfigManagerInternal manager = ConfigManagerInternal.getInstance(); + ConfigObject config = ConfigObject.getInstance(); + return applicableInputMethods.stream() + .<FavoriteMenuEntry>map(pair -> ToggleMenuEntry.of(pair.getValue().getName(), + () -> Objects.equals(config.getInputMethodId(), pair.getKey()), + bool -> { + ExecutorService service = Executors.newSingleThreadExecutor(); + InputMethod<?> active = InputMethod.active(); + active.dispose(service).whenComplete((unused, throwable) -> { + if (throwable != null) { + InternalLogger.getInstance().error("Failed to dispose input method", throwable); + } + + manager.set("functionality.inputMethod", new ResourceLocation("rei:default")); + }).join(); + CompletableFuture<Void> future = pair.getValue().prepare(service).whenComplete((unused, throwable) -> { + if (throwable != null) { + InternalLogger.getInstance().error("Failed to prepare input method", throwable); + manager.set("functionality.inputMethod", new ResourceLocation("rei:default")); + } else { + manager.set("functionality.inputMethod", pair.getKey()); + } + }); + Screen screen = Minecraft.getInstance().screen; + Minecraft.getInstance().setScreen(new ConfigReloadingScreen(new TranslatableComponent("text.rei.input.methods.initializing"), + () -> !future.isDone(), () -> { + Minecraft.getInstance().setScreen(screen); + })); + future.whenComplete((unused, throwable) -> { + service.shutdown(); + }); + }) + .withActive(() -> !Objects.equals(config.getInputMethodId(), pair.getKey())) + .withTooltip(() -> Tooltip.create(TooltipContext.ofMouse(), pair.getValue().getDescription())) + ) + .toList(); + } +} diff --git a/runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/menu/provider/OverlayMenuEntryProvider.java b/runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/menu/provider/OverlayMenuEntryProvider.java index 401659300..367f16c46 100644 --- a/runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/menu/provider/OverlayMenuEntryProvider.java +++ b/runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/menu/provider/OverlayMenuEntryProvider.java @@ -2,9 +2,11 @@ package me.shedaniel.rei.impl.client.gui.overlay.menu.provider; import me.shedaniel.rei.api.client.favorites.FavoriteMenuEntry; import me.shedaniel.rei.impl.client.ClientInternals; +import org.jetbrains.annotations.ApiStatus; import java.util.List; +@ApiStatus.Internal public interface OverlayMenuEntryProvider { List<OverlayMenuEntryProvider> PROVIDERS = ClientInternals.resolveServices(OverlayMenuEntryProvider.class); diff --git a/runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/widgets/OverlayWidgetProvider.java b/runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/widgets/OverlayWidgetProvider.java index e89e4e98f..3c19aa6b7 100644 --- a/runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/widgets/OverlayWidgetProvider.java +++ b/runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/widgets/OverlayWidgetProvider.java @@ -26,12 +26,19 @@ 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.ClientInternals; import me.shedaniel.rei.impl.client.gui.menu.MenuAccess; import java.util.List; -import java.util.function.Consumer; +import java.util.function.BooleanSupplier; import java.util.function.UnaryOperator; public interface OverlayWidgetProvider { - List<Widget> provide(ScreenOverlay overlay, MenuAccess access, Consumer<TextField> textFieldSink, UnaryOperator<Widget> lateRenderable); + List<OverlayWidgetProvider> PROVIDERS = ClientInternals.resolveServices(OverlayWidgetProvider.class); + + List<Widget> provide(ScreenOverlay overlay, MenuAccess access, TextFieldSink textFieldSink, UnaryOperator<Widget> lateRenderable); + + interface TextFieldSink { + void accept(TextField textField, BooleanSupplier isHighlighted); + } } |
