Skip to content

Commit

Permalink
Improve Overlay Menus
Browse files Browse the repository at this point in the history
  • Loading branch information
shedaniel committed Sep 10, 2022
1 parent fb91ed9 commit 229b1fe
Show file tree
Hide file tree
Showing 23 changed files with 333 additions and 269 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -57,18 +57,18 @@ public abstract class Widget extends AbstractContainerEventHandler implements ne
* The font for rendering text
*/
protected final Font font = minecraft.font;
private static final Stack<Point> mouseStack = new Stack<>();
private static final Stack<Point> MOUSE_STACK = new Stack<>();

public static Point mouse() {
return mouseStack.empty() ? PointHelper.ofMouse() : mouseStack.peek();
return MOUSE_STACK.empty() ? PointHelper.ofMouse() : MOUSE_STACK.peek();
}

public static Point pushMouse(Point mouse) {
return mouseStack.push(mouse);
return MOUSE_STACK.push(mouse);
}

public static Point popMouse() {
return mouseStack.pop();
return MOUSE_STACK.pop();
}

public static Point translateMouse(PoseStack poses) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import me.shedaniel.rei.api.client.gui.widgets.Tooltip;
import me.shedaniel.rei.api.client.gui.widgets.WidgetWithBounds;
import me.shedaniel.rei.api.client.search.SearchFilter;
import me.shedaniel.rei.api.common.display.Display;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import org.jetbrains.annotations.ApiStatus;
Expand Down Expand Up @@ -134,4 +135,14 @@ public boolean isNotInExclusionZones(Rectangle bounds) {
* @param tooltip the tooltip
*/
public abstract void renderTooltip(PoseStack matrices, Tooltip tooltip);

/**
* Returns whether slot highlighting is on for the current search filter.
*
* @return whether slot highlighting is on for the current search filter.
*/
public abstract boolean isHighlighting();

@ApiStatus.Experimental
public abstract boolean submitDisplayHistory(Display display, @Nullable Rectangle fromBounds);
}
1 change: 1 addition & 0 deletions gradle.properties
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
org.gradle.java.home=C:\\Program Files\\OpenJDK\\jdk-17.0.2
org.gradle.jvmargs=-Xmx10G
base_version=8.4
unstable=false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -251,4 +251,9 @@ public Widget asWidget() {
public Rectangle getFavoritesBounds() {
return favoritesBounds;
}

@Override
public void submitDisplayHistory(Display display, @Nullable Rectangle fromBounds) {
displayHistory.addDisplay(fromBounds, display);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@
import me.shedaniel.rei.api.client.gui.config.SyntaxHighlightingMode;
import me.shedaniel.rei.api.client.gui.screen.DisplayScreen;
import me.shedaniel.rei.api.client.gui.widgets.Button;
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.ScreenOverlay;
Expand All @@ -53,14 +52,13 @@
import java.util.Collection;
import java.util.List;
import java.util.UUID;
import java.util.function.Consumer;
import java.util.function.UnaryOperator;

public class ConfigButtonWidgetProvider implements OverlayWidgetProvider {
private static final UUID CONFIG_MENU_UUID = UUID.fromString("4357bc36-0a4e-47d2-8e07-ddc220df4a0f");

@Override
public List<Widget> provide(ScreenOverlay overlay, MenuAccess access, Consumer<TextField> textFieldSink, UnaryOperator<Widget> lateRenderable) {
public List<Widget> provide(ScreenOverlay overlay, MenuAccess access, TextFieldSink textFieldSink, UnaryOperator<Widget> lateRenderable) {
return List.of(create(overlay, access, lateRenderable));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,40 +30,34 @@
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.gui.widgets.Button;
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.search.method.InputMethod;
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.overlay.menu.entries.SeparatorMenuEntry;
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 me.shedaniel.rei.impl.client.gui.overlay.menu.provider.OverlayMenuEntryProvider;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.chat.NarratorChatListener;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.client.renderer.entity.ItemRenderer;
import net.minecraft.network.chat.TextComponent;
import net.minecraft.network.chat.TranslatableComponent;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.block.Blocks;

import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.function.Consumer;
import java.util.function.UnaryOperator;

public class CraftableFilterButtonWidgetProvider implements OverlayWidgetProvider {
public static final UUID FILTER_MENU_UUID = UUID.fromString("2839e998-1679-4f9e-a257-37411d16f1e6");

@Override
public List<Widget> provide(ScreenOverlay overlay, MenuAccess access, Consumer<TextField> textFieldSink, UnaryOperator<Widget> lateRenderable) {
public List<Widget> provide(ScreenOverlay overlay, MenuAccess access, TextFieldSink textFieldSink, UnaryOperator<Widget> lateRenderable) {
if (ConfigObject.getInstance().isCraftableFilterEnabled()) {
return List.of(create(overlay, access, lateRenderable));
} else {
Expand Down Expand Up @@ -111,60 +105,33 @@ private static Collection<FavoriteMenuEntry> menuEntries() {
.toList())
));

List<Map.Entry<ResourceLocation, InputMethod<?>>> applicableInputMethods = getApplicableInputMethods();
if (applicableInputMethods.size() > 1) {
entries.add(new SubMenuEntry(new TranslatableComponent("text.rei.config.menu.search_field.input_method"), createInputMethodEntries(applicableInputMethods)));
List<List<FavoriteMenuEntry>> additionalEntries = new ArrayList<>();

for (OverlayMenuEntryProvider provider : OverlayMenuEntryProvider.PROVIDERS) {
List<FavoriteMenuEntry> provided = provider.provide(OverlayMenuEntryProvider.Type.CRAFTABLE_FILTER);

if (provided != null && !provided.isEmpty()) {
additionalEntries.add(provided);
}
}

for (List<FavoriteMenuEntry> additionalEntryList : additionalEntries) {
if (additionalEntryList.size() > 1) {
entries.add(new SeparatorMenuEntry());
entries.addAll(additionalEntryList);
}
}

List<FavoriteMenuEntry> singleEntries = CollectionUtils.flatMap(CollectionUtils.filterToList(additionalEntries, list -> list.size() == 1), list -> list);

if (!singleEntries.isEmpty()) {
entries.add(new SeparatorMenuEntry());
entries.addAll(singleEntries);
}

return entries;
}

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();
}

private static Rectangle getCraftableFilterBounds() {
Rectangle area = REIRuntime.getInstance().getSearchTextField().asWidget().getBounds().clone();
area.setLocation(area.x + area.width + 4, area.y - 1);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,25 +1,56 @@
package me.shedaniel.rei.impl.client.gui.overlay.widgets;

import me.shedaniel.rei.api.client.gui.widgets.TextField;
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.widgets.Widget;
import me.shedaniel.rei.api.client.overlay.ScreenOverlay;
import me.shedaniel.rei.api.client.registry.screen.ScreenRegistry;
import me.shedaniel.rei.impl.client.gui.menu.MenuAccess;
import me.shedaniel.rei.impl.client.gui.overlay.widgets.search.OverlaySearchField;
import net.minecraft.client.Minecraft;

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) {
public List<Widget> provide(ScreenOverlay overlay, MenuAccess access, TextFieldSink textFieldSink, UnaryOperator<Widget> lateRenderable) {
if (searchField == null) {
searchField = new OverlaySearchField(access);
}

textFieldSink.accept(searchField);
searchField.getBounds().setBounds(getSearchFieldArea(overlay));
textFieldSink.accept(searchField, searchField::isHighlighting);
return List.of(lateRenderable.apply(searchField));
}

private Rectangle getSearchFieldArea(ScreenOverlay overlay) {
int widthRemoved = 1;
if (ConfigObject.getInstance().isCraftableFilterEnabled()) widthRemoved += 22;
if (ConfigObject.getInstance().isLowerConfigButton()) widthRemoved += 22;
return switch (REIRuntime.getInstance().getContextualSearchFieldLocation()) {
case TOP_SIDE -> getTopSideSearchFieldArea(overlay, widthRemoved);
case BOTTOM_SIDE -> getBottomSideSearchFieldArea(overlay, widthRemoved);
case CENTER -> getCenterSearchFieldArea(overlay, widthRemoved);
};
}

private Rectangle getTopSideSearchFieldArea(ScreenOverlay overlay, int widthRemoved) {
return new Rectangle(overlay.getBounds().x + 2, 4, overlay.getBounds().width - 6 - widthRemoved, 18);
}

private Rectangle getBottomSideSearchFieldArea(ScreenOverlay overlay, int widthRemoved) {
Window window = Minecraft.getInstance().getWindow();
return new Rectangle(overlay.getBounds().x + 2, window.getGuiScaledHeight() - 22, overlay.getBounds().width - 6 - widthRemoved, 18);
}

private Rectangle getCenterSearchFieldArea(ScreenOverlay overlay, int widthRemoved) {
Window window = Minecraft.getInstance().getWindow();
Rectangle screenBounds = ScreenRegistry.getInstance().getScreenBounds(Minecraft.getInstance().screen);
return new Rectangle(screenBounds.x, window.getGuiScaledHeight() - 22, screenBounds.width - widthRemoved, 18);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -73,10 +73,10 @@
@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 boolean isHighlighting = false;
private final TextField textField;
private final MenuAccess access;
private boolean previouslyClicking = false;
Expand Down Expand Up @@ -383,7 +383,7 @@ public void render(PoseStack matrices, int mouseX, int mouseY, float delta) {
super.render(matrices, mouseX, mouseY, delta);
RenderSystem.enableDepthTest();
if (isMain && isHighlighting) {
this.renderEntryHighlighting(matrices);
renderEntryHighlighting(matrices);
}
}

Expand Down Expand Up @@ -427,4 +427,8 @@ public static void renderEntryHighlighting(PoseStack matrices) {
RenderSystem.colorMask(true, true, true, true);
RenderSystem.enableDepthTest();
}

public boolean isHighlighting() {
return isHighlighting;
}
}
Loading

0 comments on commit 229b1fe

Please sign in to comment.