From 47501412b83fb0507e1e7fe3884255fff24eec2e Mon Sep 17 00:00:00 2001 From: shedaniel Date: Tue, 1 Jul 2025 14:49:29 +0800 Subject: WIP Calculator --- .../rei/impl/client/config/ConfigObjectImpl.java | 6 + .../rei/impl/client/gui/ScreenOverlayImpl.java | 2 +- .../gui/config/options/AllREIConfigGroups.java | 3 +- .../gui/config/options/AllREIConfigOptions.java | 2 + .../gui/widget/favorites/FavoritesListWidget.java | 45 ++++--- .../widget/favorites/panel/CalculatorPanel.java | 124 ++++++++++++++++++ .../panel/FadingFavoritesPanelButton.java | 13 +- .../widget/favorites/panel/FavoritesAddPanel.java | 143 +++++++++++++++++++++ .../gui/widget/favorites/panel/FavoritesPanel.java | 130 +++---------------- .../panel/FavoritesTogglePanelButton.java | 110 ++++++++++++---- .../panel/rows/FavoritesPanelEmptyRow.java | 2 +- .../panel/rows/FavoritesPanelEntriesRow.java | 10 +- .../favorites/panel/rows/FavoritesPanelRow.java | 2 +- .../panel/rows/FavoritesPanelSectionRow.java | 6 +- .../panel/rows/FavoritesPanelSeparatorRow.java | 4 +- .../gui/widget/favorites/trash/TrashWidget.java | 4 +- .../gui/widget/search/CalculatorDisplay.java | 130 +------------------ .../gui/widget/search/CalculatorDisplayUtils.java | 139 ++++++++++++++++++++ .../gui/widget/search/OverlaySearchField.java | 40 +++++- .../OverlaySearchFieldSyntaxHighlighter.java | 11 +- .../shedaniel/rei/impl/client/util/ColorUtils.java | 19 +++ 21 files changed, 628 insertions(+), 317 deletions(-) create mode 100644 runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/panel/CalculatorPanel.java create mode 100644 runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/panel/FavoritesAddPanel.java create mode 100644 runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/search/CalculatorDisplayUtils.java create mode 100644 runtime/src/main/java/me/shedaniel/rei/impl/client/util/ColorUtils.java (limited to 'runtime') diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/config/ConfigObjectImpl.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/config/ConfigObjectImpl.java index 4b500fa1f..627cb2981 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/config/ConfigObjectImpl.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/config/ConfigObjectImpl.java @@ -328,6 +328,11 @@ public class ConfigObjectImpl implements ConfigObject, ConfigData { return advanced.layout.favoriteAddWidgetMode; } + @Override + public boolean isCalculatorPanelEnabled() { + return advanced.layout.calculatorPanel; + } + @Override public ModifierKeyCode getFavoriteKeyCode() { return basics.keyBindings.favoriteKeybind == null ? ModifierKeyCode.unknown() : basics.keyBindings.favoriteKeybind; @@ -693,6 +698,7 @@ public class ConfigObjectImpl implements ConfigObject, ConfigData { @Comment("Merges displays with equal contents under 1 display.") public boolean mergeDisplayUnderOne = true; public FavoriteAddWidgetMode favoriteAddWidgetMode = FavoriteAddWidgetMode.ALWAYS_VISIBLE; + public boolean calculatorPanel = true; } public static class Accessibility { diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/ScreenOverlayImpl.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/ScreenOverlayImpl.java index fe905b5cc..369d084af 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/ScreenOverlayImpl.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/ScreenOverlayImpl.java @@ -428,7 +428,7 @@ public abstract class ScreenOverlayImpl extends ScreenOverlay { if (REIRuntimeImpl.getSearchField().keyReleased(keyCode, scanCode, modifiers)) return true; for (GuiEventListener listener : widgets) - if (listener != REIRuntimeImpl.getSearchField() && listener == getFocused() && listener.keyPressed(keyCode, scanCode, modifiers)) + if (listener != REIRuntimeImpl.getSearchField() && listener == getFocused() && listener.keyReleased(keyCode, scanCode, modifiers)) return true; } } diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/options/AllREIConfigGroups.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/options/AllREIConfigGroups.java index bdb5a8168..8fe6cd45d 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/options/AllREIConfigGroups.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/options/AllREIConfigGroups.java @@ -90,7 +90,8 @@ public interface AllREIConfigGroups { .add(COLLAPSIBLE_ENTRIES); OptionGroup FAVORITES_FAVORITES = make("favorites.favorites") .add(FAVORITES_MODE) - .add(NEW_FAVORITES_BUTTON_VISIBILITY); + .add(NEW_FAVORITES_BUTTON_VISIBILITY) + .add(CALCULATOR_MODE); OptionGroup FAVORITES_ADVANCED = make("favorites.advanced") .add(GAME_MODE_COMMAND) .add(TIME_COMMAND) diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/options/AllREIConfigOptions.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/options/AllREIConfigOptions.java index 30a673e38..f0bff705b 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/options/AllREIConfigOptions.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/options/AllREIConfigOptions.java @@ -222,6 +222,8 @@ public interface AllREIConfigOptions { .enabledDisabled(); CompositeOption NEW_FAVORITES_BUTTON_VISIBILITY = make("favorites.new_favorites_button_visibility", i -> i.advanced.layout.favoriteAddWidgetMode, (i, v) -> i.advanced.layout.favoriteAddWidgetMode = v) .enumOptions(); + CompositeOption CALCULATOR_MODE = make("favorites.calculator_mode", i -> i.advanced.layout.calculatorPanel, (i, v) -> i.advanced.layout.calculatorPanel = v) + .enabledDisabled(); CompositeOption GAME_MODE_COMMAND = make("favorites.game_mode_command", i -> i.advanced.commands.gamemodeCommand, (i, v) -> i.advanced.commands.gamemodeCommand = v) .string(); CompositeOption TIME_COMMAND = make("favorites.time_command", i -> i.advanced.commands.timeCommand, (i, v) -> i.advanced.commands.timeCommand = v) diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/FavoritesListWidget.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/FavoritesListWidget.java index 63d2d8dd6..fed2d31a9 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/FavoritesListWidget.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/FavoritesListWidget.java @@ -55,7 +55,8 @@ import me.shedaniel.rei.impl.client.gui.widget.favorites.history.DisplayHistoryM import me.shedaniel.rei.impl.client.gui.widget.favorites.history.DisplayHistoryWidget; import me.shedaniel.rei.impl.client.gui.widget.favorites.listeners.FavoritesRegionListener; import me.shedaniel.rei.impl.client.gui.widget.favorites.listeners.FavoritesSystemRegionListener; -import me.shedaniel.rei.impl.client.gui.widget.favorites.panel.FavoritesPanel; +import me.shedaniel.rei.impl.client.gui.widget.favorites.panel.CalculatorPanel; +import me.shedaniel.rei.impl.client.gui.widget.favorites.panel.FavoritesAddPanel; import me.shedaniel.rei.impl.client.gui.widget.favorites.panel.FavoritesTogglePanelButton; import me.shedaniel.rei.impl.client.gui.widget.favorites.trash.TrashWidget; import me.shedaniel.rei.impl.client.gui.widget.region.EntryStacksRegionWidget; @@ -64,7 +65,6 @@ import me.shedaniel.rei.impl.client.gui.widget.region.RegionDraggableStack; import me.shedaniel.rei.impl.common.util.RectangleUtils; import net.minecraft.client.gui.GuiGraphics; import net.minecraft.client.gui.screens.Screen; -import net.minecraft.network.chat.Component; import org.apache.commons.lang3.mutable.MutableLong; import org.apache.commons.lang3.tuple.Triple; import org.jetbrains.annotations.ApiStatus; @@ -85,20 +85,13 @@ public class FavoritesListWidget extends WidgetWithBounds implements DraggableCo private EntryStacksRegionWidget region = new EntryStacksRegionWidget<>(new FavoritesRegionListener(this)); private List lastSystemEntries = new ArrayList<>(); - public final FavoritesPanel favoritePanel = new FavoritesPanel(this); + public final FavoritesAddPanel favoritePanel = new FavoritesAddPanel(this); + public final CalculatorPanel calculatorPanel = new CalculatorPanel(this); public final TrashWidget trash = new TrashWidget(this); public final DisplayHistoryWidget displayHistory = new DisplayHistoryWidget(this); - public final FavoritesTogglePanelButton togglePanelButton = new FavoritesTogglePanelButton(this, 0, Component.translatable("text.rei.add_favorite_widget"), - favoritePanel.expendState, () -> { - favoritePanel.expendState.setTo(!favoritePanel.expendState.target(), ConfigObject.getInstance().isReducedMotion() ? 0 : 1500); - favoritePanel.resetRows(); - }); - public final FavoritesTogglePanelButton calculatorPanelButton = new FavoritesTogglePanelButton(this, 1, Component.translatable("text.rei.calculator_widget"), - favoritePanel.expendState, () -> { - favoritePanel.expendState.setTo(!favoritePanel.expendState.target(), ConfigObject.getInstance().isReducedMotion() ? 0 : 1500); - favoritePanel.resetRows(); - }); - private final List children = ImmutableList.of(favoritePanel, togglePanelButton, calculatorPanelButton, systemRegion, region); + public final FavoritesTogglePanelButton togglePanelButton = new FavoritesTogglePanelButton.ToggleAdd(this); + public final FavoritesTogglePanelButton calculatorPanelButton = new FavoritesTogglePanelButton.ToggleCalculator(this); + private final List children = ImmutableList.of(favoritePanel, calculatorPanel, togglePanelButton, calculatorPanelButton, systemRegion, region); @Override public boolean mouseScrolled(double mouseX, double mouseY, double amountX, double amountY) { @@ -213,12 +206,12 @@ public class FavoritesListWidget extends WidgetWithBounds implements DraggableCo displayHistory.render(graphics, mouseX, mouseY, delta); - if (favoritePanel.getBounds().height > 20) { - // Opened favorites panel - region.getBounds().setBounds(this.favoritesBounds.x, this.favoritesBounds.y + topOffsetHeight, this.favoritesBounds.width, this.favoritesBounds.height - topOffsetHeight - (this.favoritesBounds.getMaxY() - this.favoritePanel.getBounds().y) - 4 - (Math.round(trashHeight) <= 0 ? 0 : trashHeight)); - } else { - region.getBounds().setBounds(this.favoritesBounds.x, this.favoritesBounds.y + topOffsetHeight, this.favoritesBounds.width, this.favoritesBounds.height - topOffsetHeight - (Math.round(trashHeight) <= 0 ? 0 : trashHeight + 24)); - } + int removeExtraHeight = 0; + + if (favoritePanel.getBounds().height > 20) removeExtraHeight += this.favoritesBounds.getMaxY() - this.favoritePanel.getBounds().y + 4; + if (calculatorPanel.getBounds().height > 20) removeExtraHeight += this.favoritesBounds.getMaxY() - this.calculatorPanel.getBounds().y + 4; + + region.getBounds().setBounds(this.favoritesBounds.x, this.favoritesBounds.y + topOffsetHeight, this.favoritesBounds.width, this.favoritesBounds.height - topOffsetHeight - removeExtraHeight - (Math.round(trashHeight) <= 0 ? 0 : trashHeight)); systemRegion.render(graphics, mouseX, mouseY, delta); region.render(graphics, mouseX, mouseY, delta); @@ -269,6 +262,7 @@ public class FavoritesListWidget extends WidgetWithBounds implements DraggableCo private void renderAddFavorite(GuiGraphics graphics, int mouseX, int mouseY, float delta) { this.favoritePanel.render(graphics, mouseX, mouseY, delta); + this.calculatorPanel.render(graphics, mouseX, mouseY, delta); this.togglePanelButton.render(graphics, mouseX, mouseY, delta); this.calculatorPanelButton.render(graphics, mouseX, mouseY, delta); } @@ -324,4 +318,15 @@ public class FavoritesListWidget extends WidgetWithBounds implements DraggableCo return true; return false; } + + @Override + public boolean charTyped(char character, int modifiers) { + if (containsMouse(mouse())) + for (Widget widget : children()) + if (widget.charTyped(character, modifiers)) + return true; + if (displayHistory.charTyped(character, modifiers)) + return true; + return false; + } } diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/panel/CalculatorPanel.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/panel/CalculatorPanel.java new file mode 100644 index 000000000..17da10aff --- /dev/null +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/panel/CalculatorPanel.java @@ -0,0 +1,124 @@ +package me.shedaniel.rei.impl.client.gui.widget.favorites.panel; + +import me.shedaniel.clothconfig2.api.animator.NumberAnimator; +import me.shedaniel.clothconfig2.api.animator.ProgressValueAnimator; +import me.shedaniel.clothconfig2.api.animator.ValueAnimator; +import me.shedaniel.math.Rectangle; +import me.shedaniel.rei.api.client.config.ConfigObject; +import me.shedaniel.rei.impl.client.gui.widget.favorites.FavoritesListWidget; +import me.shedaniel.rei.impl.client.gui.widget.search.CalculatorDisplayUtils; +import me.shedaniel.rei.impl.client.gui.widget.search.OverlaySearchField; +import me.shedaniel.rei.impl.client.gui.widget.search.TextCalculator; +import me.shedaniel.rei.impl.client.util.ColorUtils; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.components.events.GuiEventListener; +import net.minecraft.network.chat.Component; + +import java.util.ArrayList; +import java.util.List; + +public class CalculatorPanel extends FavoritesPanel { + private final List rows = new ArrayList<>(); + private final OverlaySearchField textField = new OverlaySearchField(0, 0, 0, 0, null); + private final NumberAnimator previewHeight = ValueAnimator.ofDouble().asInt(); + private CalculatorDisplayUtils utils = new CalculatorDisplayUtils(7); + private double eval; + + public CalculatorPanel(FavoritesListWidget parent) { + super(parent); + this.textField.setHasBorder(false); + this.textField.isMain = false; + this.textField.setAutoPrefixEquals(true); + this.textField.setSuggestion(Component.empty()); + this.textField.setResponder(text -> { + if (!text.isBlank() && TextCalculator.isValid('=' + text)) { + this.eval = new TextCalculator('=' + text).eval(); + this.previewHeight.setTo(Minecraft.getInstance().font.lineHeight + 1, ConfigObject.getInstance().isReducedMotion() ? 0 : 400); + } else { + this.previewHeight.setTo(0, ConfigObject.getInstance().isReducedMotion() ? 0 : 400); + } + }); + } + + @Override + public void render(GuiGraphics graphics, int mouseX, int mouseY, float delta) { + this.previewHeight.update(delta); + super.render(graphics, mouseX, mouseY, delta); + this.innerBounds.setBounds(bounds.x + 4, bounds.y + 4, bounds.width - 8, bounds.height - 8); + + int previewLength = Math.max(7, (this.innerBounds.width - 4) / font.width("=")); + if (previewLength != this.utils.maxLength()) this.utils = new CalculatorDisplayUtils(previewLength); + + int buttonColor = 0xFFFFFF | (Math.round(0x34 * Math.min((float) expendState.progress() * 2, 1)) << 24); + graphics.fillGradient(bounds.x, bounds.y, bounds.getMaxX(), bounds.getMaxY(), buttonColor, buttonColor); + + if (expendState.progress() > 0.05f) { + Rectangle availableFullBounds = parent.favoritesBounds.clone(); + availableFullBounds.height -= 20; + Rectangle scissorBounds = new Rectangle(innerBounds.x - 1, innerBounds.y - 1, innerBounds.width + 2, innerBounds.height + 2).intersection(availableFullBounds); + graphics.enableScissor(scissorBounds.x, scissorBounds.y, scissorBounds.getMaxX(), scissorBounds.getMaxY()); + graphics.pose().pushPose(); + + // Text Field Background + Rectangle textFieldBorder = new Rectangle(innerBounds.x, innerBounds.getMaxY() - 9 - 5, innerBounds.width, 9 + 5); + boolean textFieldFocused = textFieldBorder.contains(mouseX, mouseY) || this.textField.isFocused(); + int borderColor = ColorUtils.withAlpha(textFieldFocused ? 0x77FFFFFF : 0x77A0A0A0, expendState.progress()); + int backgroundColor = ColorUtils.withAlpha(textFieldFocused ? 0xFF000000 : 0xC0000000, expendState.progress()); + graphics.fillGradient(textFieldBorder.x - 1, textFieldBorder.y - 1, textFieldBorder.getMaxX() + 1, textFieldBorder.getMaxY() + 1, borderColor, borderColor); + graphics.fillGradient(textFieldBorder.x, textFieldBorder.y, textFieldBorder.getMaxX(), textFieldBorder.getMaxY(), backgroundColor, backgroundColor); + int leftPad = font.width("="); + + // Equals + graphics.pose().pushPose(); + graphics.pose().translate(-0.5, 0, 0); + graphics.drawString(font, "=", innerBounds.x + 2, innerBounds.getMaxY() - 9 - 2, ColorUtils.withAlpha(0xFFAAAAAA, expendState.progress())); + graphics.pose().popPose(); + + // Text Field + this.textField.getBounds().setBounds(innerBounds.x + 2 + leftPad, innerBounds.getMaxY() - 9 - 2, innerBounds.width - 4 - leftPad, 9); + this.textField.render(graphics, mouseX, mouseY, delta); + + // Preview + if (this.previewHeight.value() > 0) { + int previewTop = textFieldBorder.y - 1 - this.previewHeight.value(); + graphics.enableScissor(textFieldBorder.x - 1, previewTop, textFieldBorder.getMaxX() + 1, textFieldBorder.y - 1); + graphics.fillGradient(textFieldBorder.x - 1, previewTop, textFieldBorder.getMaxX() + 1, textFieldBorder.y - 1, borderColor, borderColor); + graphics.drawString(font, this.utils.fmt(this.eval), textFieldBorder.x + 2, previewTop + 2, 0xFF000000, false); + graphics.disableScissor(); + } + + graphics.pose().popPose(); + graphics.disableScissor(); + } else { + this.textField.getBounds().setBounds(0, 0, 0, 0); + } + } + + @Override + protected Rectangle getButtonArea() { + return this.parent.calculatorPanelButton.getBounds(); + } + + @Override + protected Rectangle getTargetArea(Rectangle fullArea) { + return new Rectangle( + fullArea.x + 4, + fullArea.getMaxY() - 4 - 16 - fullArea.height * 0.4f, + fullArea.width - 8, + fullArea.height * 0.4f + ); + } + + @Override + public List children() { + return List.of(this.textField); + } + + private record Row(String equation, double result, ProgressValueAnimator set) { + public Row(String equation, double result) { + this(equation, result, ValueAnimator.ofBoolean(false)); + this.set().setTo(true, ConfigObject.getInstance().isReducedMotion() ? 0 : 500); + } + } +} diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/panel/FadingFavoritesPanelButton.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/panel/FadingFavoritesPanelButton.java index 284d9fc0c..1297243fa 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/panel/FadingFavoritesPanelButton.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/panel/FadingFavoritesPanelButton.java @@ -27,11 +27,11 @@ import me.shedaniel.clothconfig2.api.animator.NumberAnimator; import me.shedaniel.clothconfig2.api.animator.ValueAnimator; import me.shedaniel.math.Rectangle; import me.shedaniel.rei.api.client.config.ConfigObject; +import me.shedaniel.rei.api.client.gui.config.FavoriteAddWidgetMode; import me.shedaniel.rei.api.client.gui.widgets.WidgetWithBounds; import me.shedaniel.rei.impl.client.gui.widget.favorites.FavoritesListWidget; import net.minecraft.client.gui.GuiGraphics; import net.minecraft.client.gui.components.events.GuiEventListener; -import net.minecraft.client.renderer.MultiBufferSource; import java.util.Collections; import java.util.List; @@ -51,8 +51,9 @@ public abstract class FadingFavoritesPanelButton extends WidgetWithBounds { @Override public void render(GuiGraphics graphics, int mouseX, int mouseY, float delta) { this.bounds.setBounds(updateArea(parent.favoritesBounds)); - boolean hovered = containsMouse(mouseX, mouseY); - switch (ConfigObject.getInstance().getFavoriteAddWidgetMode()) { + boolean hovered = containsMouse(mouseX, mouseY) & isVisible(); + if (isOtherActive()) this.alpha.setTo(0, ConfigObject.getInstance().isReducedMotion() ? 0 : 750); + else switch (getFavoriteAddWidgetMode()) { case ALWAYS_INVISIBLE: this.alpha.setAs(0); break; @@ -60,7 +61,7 @@ public abstract class FadingFavoritesPanelButton extends WidgetWithBounds { this.alpha.setTo(hovered ? 1f : isAvailable(mouseX, mouseY) ? 0.5f : 0f, ConfigObject.getInstance().isReducedMotion() ? 0 : 260); break; case ALWAYS_VISIBLE: - this.alpha.setAs(hovered ? 1f : 0.5f); + this.alpha.setTo(hovered ? 1f : 0.5f, ConfigObject.getInstance().isReducedMotion() ? 0 : 750); break; } this.alpha.update(delta); @@ -74,6 +75,10 @@ public abstract class FadingFavoritesPanelButton extends WidgetWithBounds { } } + protected abstract boolean isOtherActive(); + + protected abstract FavoriteAddWidgetMode getFavoriteAddWidgetMode(); + protected abstract boolean isAvailable(int mouseX, int mouseY); protected abstract void renderContents(GuiGraphics graphics); diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/panel/FavoritesAddPanel.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/panel/FavoritesAddPanel.java new file mode 100644 index 000000000..1f39b1d8a --- /dev/null +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/panel/FavoritesAddPanel.java @@ -0,0 +1,143 @@ +package me.shedaniel.rei.impl.client.gui.widget.favorites.panel; + +import me.shedaniel.clothconfig2.ClothConfigInitializer; +import me.shedaniel.clothconfig2.api.LazyResettable; +import me.shedaniel.clothconfig2.api.scroll.ScrollingContainer; +import me.shedaniel.math.Point; +import me.shedaniel.math.Rectangle; +import me.shedaniel.rei.api.client.favorites.FavoriteEntry; +import me.shedaniel.rei.api.client.favorites.FavoriteEntryType; +import me.shedaniel.rei.api.client.gui.drag.component.DraggableComponent; +import me.shedaniel.rei.api.common.entry.EntryStack; +import me.shedaniel.rei.api.common.util.CollectionUtils; +import me.shedaniel.rei.impl.client.gui.widget.favorites.FavoritesListWidget; +import me.shedaniel.rei.impl.client.gui.widget.favorites.panel.rows.*; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.components.events.GuiEventListener; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.List; + +public class FavoritesAddPanel extends FavoritesPanel { + private final LazyResettable> rows = new LazyResettable<>(() -> { + List rows = new ArrayList<>(); + for (FavoriteEntryType.Section section : FavoriteEntryType.registry().sections()) { + rows.add(new FavoritesPanelSectionRow(section.getText(), section.getText().copy().withStyle(style -> style.withUnderlined(true)))); + rows.add(new FavoritesPanelEntriesRow(this, CollectionUtils.map(section.getEntries(), FavoriteEntry::copy))); + rows.add(new FavoritesPanelSeparatorRow()); + } + if (!rows.isEmpty()) rows.remove(rows.size() - 1); + rows.add(new FavoritesPanelEmptyRow(4)); + return rows; + }); + private final ScrollingContainer scroller = new ScrollingContainer() { + @Override + public Rectangle getBounds() { + return innerBounds; + } + + @Override + public int getMaxScrollHeight() { + return Math.max(1, rows.get().stream().mapToInt(FavoritesPanelRow::getRowHeight).sum()); + } + }; + + public FavoritesAddPanel(FavoritesListWidget parent) { + super(parent); + } + + public void resetRows() { + this.rows.reset(); + } + + @Override + public void render(GuiGraphics graphics, int mouseX, int mouseY, float delta) { + super.render(graphics, mouseX, mouseY, delta); + this.innerBounds.setBounds(bounds.x + 4, bounds.y + 4, bounds.width - 8, bounds.height - 20); + + int buttonColor = 0xFFFFFF | (Math.round(0x34 * Math.min((float) expendState.progress() * 2, 1)) << 24); + graphics.fillGradient(bounds.x, bounds.y, bounds.getMaxX(), bounds.getMaxY(), buttonColor, buttonColor); + scroller.updatePosition(delta); + + if (expendState.progress() > 0.05f) { + graphics.enableScissor(innerBounds.x, innerBounds.y, innerBounds.getMaxX(), innerBounds.getMaxY()); + graphics.pose().pushPose(); + graphics.pose().translate(0, -scroller.scrollAmount(), 0); + int y = innerBounds.y; + for (FavoritesPanelRow row : rows.get()) { + row.render(graphics, innerBounds, innerBounds.x, y, innerBounds.width, row.getRowHeight(), mouseX, mouseY + scroller.scrollAmountInt(), delta, (float) expendState.progress()); + y += row.getRowHeight(); + } + graphics.pose().popPose(); + graphics.disableScissor(); + } + } + + @Override + protected Rectangle getButtonArea() { + return this.parent.togglePanelButton.getBounds(); + } + + @Override + protected Rectangle getTargetArea(Rectangle fullArea) { + return new Rectangle( + fullArea.x + 4, + fullArea.getMaxY() - 4 - fullArea.height * 0.4f, + fullArea.width - 8, + fullArea.height * 0.4f + ); + } + + @Override + public boolean mouseScrolled(double d, double e, double amountX, double amountY) { + if (innerBounds.contains(d, e) && amountY != 0) { + scroller.offset(ClothConfigInitializer.getScrollStep() * -amountY, true); + return true; + } + return super.mouseScrolled(d, e, amountX, amountY); + } + + @Override + public List children() { + return rows.get(); + } + + public double getScrolledAmount() { + return scroller.scrollAmount(); + } + + public int getScrolledAmountInt() { + return scroller.scrollAmountInt(); + } + + @Nullable + public DraggableComponent getHoveredStack(double mouseX, double mouseY) { + for (FavoritesPanelRow row : rows.get()) { + if (row instanceof FavoritesPanelEntriesRow entriesRow) { + DraggableComponent hoveredStack = entriesRow.getHoveredStack(mouseX, mouseY); + + if (hoveredStack != null) { + return hoveredStack; + } + } + } + + return null; + } + + @Nullable + public EntryStack getFocusedStack(Point mouse) { + for (FavoritesPanelRow row : rows.get()) { + if (row instanceof FavoritesPanelEntriesRow entriesRow) { + EntryStack focusedStack = entriesRow.getFocusedStack(mouse); + + if (focusedStack != null) { + return focusedStack; + } + } + } + + return null; + } +} diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/panel/FavoritesPanel.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/panel/FavoritesPanel.java index 3cd7be721..c0b868ee5 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/panel/FavoritesPanel.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/panel/FavoritesPanel.java @@ -23,105 +23,39 @@ package me.shedaniel.rei.impl.client.gui.widget.favorites.panel; -import me.shedaniel.clothconfig2.ClothConfigInitializer; -import me.shedaniel.clothconfig2.api.LazyResettable; import me.shedaniel.clothconfig2.api.animator.ProgressValueAnimator; import me.shedaniel.clothconfig2.api.animator.ValueAnimator; -import me.shedaniel.clothconfig2.api.scroll.ScrollingContainer; -import me.shedaniel.math.Point; import me.shedaniel.math.Rectangle; -import me.shedaniel.rei.api.client.favorites.FavoriteEntry; -import me.shedaniel.rei.api.client.favorites.FavoriteEntryType; -import me.shedaniel.rei.api.client.gui.drag.component.DraggableComponent; import me.shedaniel.rei.api.client.gui.widgets.WidgetWithBounds; -import me.shedaniel.rei.api.common.entry.EntryStack; -import me.shedaniel.rei.api.common.util.CollectionUtils; import me.shedaniel.rei.impl.client.gui.widget.favorites.FavoritesListWidget; -import me.shedaniel.rei.impl.client.gui.widget.favorites.panel.rows.*; import net.minecraft.client.gui.GuiGraphics; -import net.minecraft.client.gui.components.events.GuiEventListener; -import org.jetbrains.annotations.Nullable; +import net.minecraft.util.Mth; -import java.util.ArrayList; -import java.util.List; - -public class FavoritesPanel extends WidgetWithBounds { - private final FavoritesListWidget parent; +public abstract class FavoritesPanel extends WidgetWithBounds { public final ProgressValueAnimator expendState = ValueAnimator.ofBoolean(0.1, false); - private final Rectangle bounds = new Rectangle(); - private final Rectangle innerBounds = new Rectangle(); - private final LazyResettable> rows = new LazyResettable<>(() -> { - List rows = new ArrayList<>(); - for (FavoriteEntryType.Section section : FavoriteEntryType.registry().sections()) { - rows.add(new FavoritesPanelSectionRow(section.getText(), section.getText().copy().withStyle(style -> style.withUnderlined(true)))); - rows.add(new FavoritesPanelEntriesRow(this, CollectionUtils.map(section.getEntries(), FavoriteEntry::copy))); - rows.add(new FavoritesPanelSeparatorRow()); - } - if (!rows.isEmpty()) rows.remove(rows.size() - 1); - rows.add(new FavoritesPanelEmptyRow(4)); - return rows; - }); - private final ScrollingContainer scroller = new ScrollingContainer() { - @Override - public Rectangle getBounds() { - return innerBounds; - } - - @Override - public int getMaxScrollHeight() { - return Math.max(1, rows.get().stream().mapToInt(FavoritesPanelRow::getRowHeight).sum()); - } - }; + protected final FavoritesListWidget parent; + protected final Rectangle bounds = new Rectangle(); + protected final Rectangle innerBounds = new Rectangle(); public FavoritesPanel(FavoritesListWidget parent) { this.parent = parent; } - public void resetRows() { - this.rows.reset(); - } - @Override public void render(GuiGraphics graphics, int mouseX, int mouseY, float delta) { this.bounds.setBounds(updatePanelArea(parent.favoritesBounds)); - this.innerBounds.setBounds(bounds.x + 4, bounds.y + 4, bounds.width - 8, bounds.height - 20); this.expendState.update(delta); - int buttonColor = 0xFFFFFF | (Math.round(0x34 * Math.min((float) expendState.progress() * 2, 1)) << 24); - graphics.fillGradient(bounds.x, bounds.y, bounds.getMaxX(), bounds.getMaxY(), buttonColor, buttonColor); - scroller.updatePosition(delta); - - if (expendState.value()) { - graphics.enableScissor(innerBounds.x, innerBounds.y, innerBounds.getMaxX(), innerBounds.getMaxY()); - graphics.pose().pushPose(); - graphics.pose().translate(0, -scroller.scrollAmount(), 0); - int y = innerBounds.y; - for (FavoritesPanelRow row : rows.get()) { - row.render(graphics, innerBounds, innerBounds.x, y, innerBounds.width, row.getRowHeight(), mouseX, mouseY + scroller.scrollAmountInt(), delta); - y += row.getRowHeight(); - } - graphics.pose().popPose(); - graphics.disableScissor(); - } } private Rectangle updatePanelArea(Rectangle fullArea) { - int currentWidth = 16 + Math.round(Math.min((float) expendState.progress(), 1) * (fullArea.getWidth() - 16 - 8)); - int currentHeight = 16 + Math.round((float) expendState.progress() * (fullArea.getHeight() * 0.4f - 16 - 8 + 4)); - return new Rectangle(fullArea.x + 4, fullArea.getMaxY() - currentHeight - 4, currentWidth, currentHeight); - } - - @Override - public boolean mouseScrolled(double d, double e, double amountX, double amountY) { - if (innerBounds.contains(d, e) && amountY != 0) { - scroller.offset(ClothConfigInitializer.getScrollStep() * -amountY, true); - return true; - } - return super.mouseScrolled(d, e, amountX, amountY); - } - - @Override - public List children() { - return rows.get(); + float progress = (float) this.expendState.progress(); + Rectangle buttonArea = getButtonArea(); + Rectangle targetArea = getTargetArea(fullArea); + int x1 = Mth.lerpInt(progress, buttonArea.x, targetArea.x); + int y1 = Mth.lerpInt(progress, buttonArea.y, targetArea.y); + int x2 = Mth.lerpInt(progress, buttonArea.getMaxX(), targetArea.getMaxX()); + int y2 = Mth.lerpInt(progress, buttonArea.getMaxY(), targetArea.getMaxY()); + return new Rectangle(x1, y1, x2 - x1, y2 - y1); } @Override @@ -137,41 +71,7 @@ public class FavoritesPanel extends WidgetWithBounds { return innerBounds; } - public double getScrolledAmount() { - return scroller.scrollAmount(); - } - - public int getScrolledAmountInt() { - return scroller.scrollAmountInt(); - } + protected abstract Rectangle getButtonArea(); - @Nullable - public DraggableComponent getHoveredStack(double mouseX, double mouseY) { - for (FavoritesPanelRow row : rows.get()) { - if (row instanceof FavoritesPanelEntriesRow entriesRow) { - DraggableComponent hoveredStack = entriesRow.getHoveredStack(mouseX, mouseY); - - if (hoveredStack != null) { - return hoveredStack; - } - } - } - - return null; - } - - @Nullable - public EntryStack getFocusedStack(Point mouse) { - for (FavoritesPanelRow row : rows.get()) { - if (row instanceof FavoritesPanelEntriesRow entriesRow) { - EntryStack focusedStack = entriesRow.getFocusedStack(mouse); - - if (focusedStack != null) { - return focusedStack; - } - } - } - - return null; - } + protected abstract Rectangle getTargetArea(Rectangle fullArea); } diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/panel/FavoritesTogglePanelButton.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/panel/FavoritesTogglePanelButton.java index 1aea6832e..6af7a013a 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/panel/FavoritesTogglePanelButton.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/panel/FavoritesTogglePanelButton.java @@ -27,23 +27,21 @@ import me.shedaniel.clothconfig2.api.animator.ProgressValueAnimator; import me.shedaniel.math.Point; 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.FavoriteAddWidgetMode; import me.shedaniel.rei.api.client.gui.widgets.Tooltip; import me.shedaniel.rei.impl.client.gui.widget.favorites.FavoritesListWidget; import net.minecraft.client.gui.Font; import net.minecraft.client.gui.GuiGraphics; -import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.network.chat.Component; -@SuppressWarnings("UnstableApiUsage") -public class FavoritesTogglePanelButton extends FadingFavoritesPanelButton { - private final int i; +public abstract class FavoritesTogglePanelButton extends FadingFavoritesPanelButton { private final Component tooltip; - private final ProgressValueAnimator progress; private final Runnable onClick; + protected final ProgressValueAnimator progress; - public FavoritesTogglePanelButton(FavoritesListWidget parent, int i, Component tooltip, ProgressValueAnimator progress, Runnable onClick) { + public FavoritesTogglePanelButton(FavoritesListWidget parent, Component tooltip, ProgressValueAnimator progress, Runnable onClick) { super(parent); - this.i = i; this.tooltip = tooltip; this.progress = progress; this.onClick = onClick; @@ -59,30 +57,90 @@ public class FavoritesTogglePanelButton extends FadingFavoritesPanelButton { Tooltip.create(this.tooltip).queue(); } - @Override - protected Rectangle updateArea(Rectangle fullArea) { - return new Rectangle(fullArea.x + 4 + i * 20, fullArea.getMaxY() - 16 - 4, 16, 16); - } - @Override protected boolean isAvailable(int mouseX, int mouseY) { boolean expended = this.progress.value(); return parent.fullBounds.contains(mouseX, mouseY) || REIRuntime.getInstance().getOverlay().orElseThrow().getEntryList().containsMouse(new Point(mouseX, mouseY)) || expended; } - @Override - protected void renderContents(GuiGraphics graphics) { - graphics.drawSpecial(source -> { - float expendProgress = (float) this.progress.progress(); - if (expendProgress < .9f) { - int textColor = 0xFFFFFF | (Math.round(0xFF * alpha.floatValue() * (1 - expendProgress)) << 24); - font.drawInBatch("+", bounds.getCenterX() - 2.5f, bounds.getCenterY() - 3, textColor, false, graphics.pose().last().pose(), source, Font.DisplayMode.NORMAL, 0, 15728880); - } - if (expendProgress > .1f) { - int textColor = 0xFFFFFF | (Math.round(0xFF * alpha.floatValue() * expendProgress) << 24); - font.drawInBatch("+", bounds.getCenterX() - 2.5f, bounds.getCenterY() - 3, textColor, false, graphics.pose().last().pose(), source, Font.DisplayMode.NORMAL, 0, 15728880); - } - }); - graphics.flush(); + public static class ToggleAdd extends FavoritesTogglePanelButton { + public ToggleAdd(FavoritesListWidget parent) { + super(parent, Component.translatable("text.rei.add_favorite_widget"), parent.favoritePanel.expendState, () -> { + parent.favoritePanel.expendState.setTo(!parent.favoritePanel.expendState.target(), ConfigObject.getInstance().isReducedMotion() ? 0 : 1500); + parent.favoritePanel.resetRows(); + }); + } + + @Override + protected boolean isOtherActive() { + return parent.calculatorPanel.expendState.progress() > 0.1f; + } + + @Override + protected Rectangle updateArea(Rectangle fullArea) { + return new Rectangle(fullArea.x + 4, fullArea.getMaxY() - 16 - 4, 16, 16); + } + + @Override + protected void renderContents(GuiGraphics graphics) { + graphics.drawSpecial(source -> { + float expendProgress = (float) this.progress.progress(); + if (expendProgress < .9f) { + int textColor = 0xFFFFFF | (Math.round(0xFF * alpha.floatValue() * (1 - expendProgress)) << 24); + font.drawInBatch("+", bounds.getCenterX() - 2.5f, bounds.getCenterY() - 3, textColor, false, graphics.pose().last().pose(), source, Font.DisplayMode.NORMAL, 0, 15728880); + } + if (expendProgress > .1f) { + int textColor = 0xFFFFFF | (Math.round(0xFF * alpha.floatValue() * expendProgress) << 24); + font.drawInBatch("+", bounds.getCenterX() - 2.5f, bounds.getCenterY() - 3, textColor, false, graphics.pose().last().pose(), source, Font.DisplayMode.NORMAL, 0, 15728880); + } + }); + } + + @Override + protected FavoriteAddWidgetMode getFavoriteAddWidgetMode() { + return ConfigObject.getInstance().getFavoriteAddWidgetMode(); + } + } + + public static class ToggleCalculator extends FavoritesTogglePanelButton { + public ToggleCalculator(FavoritesListWidget parent) { + super(parent, Component.translatable("text.rei.calculator_widget"), parent.calculatorPanel.expendState, () -> { + parent.calculatorPanel.expendState.setTo(!parent.calculatorPanel.expendState.target(), ConfigObject.getInstance().isReducedMotion() ? 0 : 1500); + }); + } + + @Override + protected boolean isOtherActive() { + return parent.favoritePanel.expendState.progress() > 0.1f; + } + + @Override + protected Rectangle updateArea(Rectangle fullArea) { + int i = ConfigObject.getInstance().getFavoriteAddWidgetMode() == FavoriteAddWidgetMode.ALWAYS_INVISIBLE ? 0 : 1; + return new Rectangle(fullArea.x + 4 + i * 20, fullArea.getMaxY() - 16 - 4, 16, 16); + } + + @Override + protected void renderContents(GuiGraphics graphics) { + graphics.drawSpecial(source -> { + float expendProgress = (float) this.progress.progress(); + if (expendProgress < .9f) { + int textColor = 0xFFFFFF | (Math.round(0xFF * alpha.floatValue() * (1 - expendProgress)) << 24); + font.drawInBatch("+", bounds.getCenterX() - 2.5f, bounds.getCenterY() - 3, textColor, false, graphics.pose().last().pose(), source, Font.DisplayMode.NORMAL, 0, 15728880); + } + if (expendProgress > .1f) { + int textColor = 0xFFFFFF | (Math.round(0xFF * alpha.floatValue() * expendProgress) << 24); + font.drawInBatch("+", bounds.getCenterX() - 2.5f, bounds.getCenterY() - 3, textColor, false, graphics.pose().last().pose(), source, Font.DisplayMode.NORMAL, 0, 15728880); + } + }); + } + + @Override + protected FavoriteAddWidgetMode getFavoriteAddWidgetMode() { + if (!ConfigObject.getInstance().isCalculatorPanelEnabled()) return FavoriteAddWidgetMode.ALWAYS_INVISIBLE; + FavoriteAddWidgetMode addWidgetMode = ConfigObject.getInstance().getFavoriteAddWidgetMode(); + if (addWidgetMode == FavoriteAddWidgetMode.ALWAYS_INVISIBLE) return FavoriteAddWidgetMode.AUTO_HIDE; + return addWidgetMode; + } } } \ No newline at end of file diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/panel/rows/FavoritesPanelEmptyRow.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/panel/rows/FavoritesPanelEmptyRow.java index c067261b7..7ff247050 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/panel/rows/FavoritesPanelEmptyRow.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/panel/rows/FavoritesPanelEmptyRow.java @@ -43,7 +43,7 @@ public class FavoritesPanelEmptyRow extends FavoritesPanelRow { } @Override - public void render(GuiGraphics graphics, Rectangle innerBounds, int x, int y, int rowWidth, int rowHeight, int mouseX, int mouseY, float delta) { + public void render(GuiGraphics graphics, Rectangle innerBounds, int x, int y, int rowWidth, int rowHeight, int mouseX, int mouseY, float delta, float alpha) { } @Override diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/panel/rows/FavoritesPanelEntriesRow.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/panel/rows/FavoritesPanelEntriesRow.java index 3e05d53f5..bea2a7447 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/panel/rows/FavoritesPanelEntriesRow.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/panel/rows/FavoritesPanelEntriesRow.java @@ -23,7 +23,6 @@ package me.shedaniel.rei.impl.client.gui.widget.favorites.panel.rows; -import com.mojang.blaze3d.vertex.PoseStack; import me.shedaniel.clothconfig2.api.animator.NumberAnimator; import me.shedaniel.clothconfig2.api.animator.ValueAnimator; import me.shedaniel.math.FloatingPoint; @@ -38,7 +37,7 @@ import me.shedaniel.rei.api.client.util.ClientEntryStacks; import me.shedaniel.rei.api.common.entry.EntryStack; import me.shedaniel.rei.api.common.util.CollectionUtils; import me.shedaniel.rei.impl.client.gui.widget.DisplayedEntryWidget; -import me.shedaniel.rei.impl.client.gui.widget.favorites.panel.FavoritesPanel; +import me.shedaniel.rei.impl.client.gui.widget.favorites.panel.FavoritesAddPanel; import me.shedaniel.rei.impl.client.gui.widget.region.EntryStacksRegionWidget; import me.shedaniel.rei.impl.client.gui.widget.region.RealRegionEntry; import me.shedaniel.rei.impl.client.gui.widget.region.RegionDraggableStack; @@ -54,15 +53,14 @@ import java.util.function.Predicate; import static me.shedaniel.rei.impl.client.gui.widget.entrylist.EntryListWidget.entrySize; import static me.shedaniel.rei.impl.client.gui.widget.entrylist.EntryListWidget.notSteppingOnExclusionZones; -@SuppressWarnings("UnstableApiUsage") public class FavoritesPanelEntriesRow extends FavoritesPanelRow { - private final FavoritesPanel panel; + private final FavoritesAddPanel panel; private final List entries; private final List widgets; private int blockedCount; private int lastY; - public FavoritesPanelEntriesRow(FavoritesPanel panel, List entries) { + public FavoritesPanelEntriesRow(FavoritesAddPanel panel, List entries) { this.panel = panel; this.entries = entries; int entrySize = entrySize(); @@ -83,7 +81,7 @@ public class FavoritesPanelEntriesRow extends FavoritesPanelRow { } @Override - public void render(GuiGraphics graphics, Rectangle innerBounds, int x, int y, int rowWidth, int rowHeight, int mouseX, int mouseY, float delta) { + public void render(GuiGraphics graphics, Rectangle innerBounds, int x, int y, int rowWidth, int rowHeight, int mouseX, int mouseY, float delta, float alpha) { this.lastY = y; int entrySize = entrySize(); boolean fastEntryRendering = ConfigObject.getInstance().doesFastEntryRendering(); diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/panel/rows/FavoritesPanelRow.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/panel/rows/FavoritesPanelRow.java index 8f6e8f661..e4a4af1a4 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/panel/rows/FavoritesPanelRow.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/panel/rows/FavoritesPanelRow.java @@ -30,5 +30,5 @@ import net.minecraft.client.gui.GuiGraphics; public abstract class FavoritesPanelRow extends AbstractContainerEventHandler { public abstract int getRowHeight(); - public abstract void render(GuiGraphics graphics, Rectangle innerBounds, int x, int y, int rowWidth, int rowHeight, int mouseX, int mouseY, float delta); + public abstract void render(GuiGraphics graphics, Rectangle innerBounds, int x, int y, int rowWidth, int rowHeight, int mouseX, int mouseY, float delta, float alpha); } \ No newline at end of file diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/panel/rows/FavoritesPanelSectionRow.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/panel/rows/FavoritesPanelSectionRow.java index af6355a2e..a5d5e2022 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/panel/rows/FavoritesPanelSectionRow.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/panel/rows/FavoritesPanelSectionRow.java @@ -48,11 +48,13 @@ public class FavoritesPanelSectionRow extends FavoritesPanelRow { } @Override - public void render(GuiGraphics graphics, Rectangle innerBounds, int x, int y, int rowWidth, int rowHeight, int mouseX, int mouseY, float delta) { + public void render(GuiGraphics graphics, Rectangle innerBounds, int x, int y, int rowWidth, int rowHeight, int mouseX, int mouseY, float delta, float alpha) { if (innerBounds.contains(mouseX, mouseY) && mouseX >= x && mouseY >= y && mouseX <= x + rowWidth && mouseY <= y + rowHeight) { Tooltip.create(sectionText).queue(); } - graphics.drawString(Minecraft.getInstance().font, styledText, x, y + 1, 0xFFFFFFFF, false); + if (alpha > 0.1) { + graphics.drawString(Minecraft.getInstance().font, styledText, x, y + 1, 0xFFFFFF | (Math.round(0xFF * alpha) << 24), false); + } } @Override diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/panel/rows/FavoritesPanelSeparatorRow.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/panel/rows/FavoritesPanelSeparatorRow.java index d98c0b78c..301b02b8f 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/panel/rows/FavoritesPanelSeparatorRow.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/panel/rows/FavoritesPanelSeparatorRow.java @@ -37,8 +37,8 @@ public class FavoritesPanelSeparatorRow extends FavoritesPanelRow { } @Override - public void render(GuiGraphics graphics, Rectangle innerBounds, int x, int y, int rowWidth, int rowHeight, int mouseX, int mouseY, float delta) { - graphics.fillGradient(x, y + 2, x + rowWidth, y + 3, -571806998, -571806998); + public void render(GuiGraphics graphics, Rectangle innerBounds, int x, int y, int rowWidth, int rowHeight, int mouseX, int mouseY, float delta, float alpha) { + graphics.fillGradient(x, y + 2, x + rowWidth, y + 3, 0xEAEAEA | (Math.round(0xDD * alpha) << 24), 0xEAEAEA | (Math.round(0xDD * alpha) << 24)); } @Override diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/trash/TrashWidget.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/trash/TrashWidget.java index b109ba105..58e2e7b19 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/trash/TrashWidget.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/trash/TrashWidget.java @@ -89,10 +89,10 @@ public class TrashWidget extends WidgetWithBounds { double trashBoundsHeight = this.height.value(); if (Math.round(trashBoundsHeight) > 0) { Rectangle fullBounds = parent.favoritesBounds; - FavoritesPanel favoritePanel = parent.favoritePanel; + int favoritePanelHeight = Math.max(parent.favoritePanel.getBounds().height, parent.fullBounds.getMaxY() - parent.calculatorPanel.getBounds().y - 4); double heightTarget = Math.min(150D, fullBounds.height * 0.23D); this.lastProgress = Math.pow(Mth.clamp(trashBoundsHeight / heightTarget, 0, 1), 7); - int y = fullBounds.getMaxY() - 4 - favoritePanel.getBounds().height; + int y = fullBounds.getMaxY() - 4 - favoritePanelHeight; bounds.setBounds(fullBounds.x + 4, (int) Math.round(y - trashBoundsHeight), fullBounds.width - 8, (int) Math.round(trashBoundsHeight - 4)); return true; } else { diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/search/CalculatorDisplay.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/search/CalculatorDisplay.java index 414c8bd72..4a9a0eb91 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/search/CalculatorDisplay.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/search/CalculatorDisplay.java @@ -33,26 +33,10 @@ import net.minecraft.client.gui.GuiGraphics; import net.minecraft.network.chat.Component; import net.minecraft.util.FormattedCharSequence; -import java.math.RoundingMode; -import java.text.DecimalFormat; -import java.text.DecimalFormatSymbols; -import java.util.Locale; import java.util.function.Consumer; public class CalculatorDisplay implements Consumer { - private static final int MAX_LEN = 7; - private static final DecimalFormat DEC; - private static final DecimalFormat SCI; - static { - DecimalFormatSymbols sym = DecimalFormatSymbols.getInstance(Locale.ROOT); - DEC = new DecimalFormat("0.##########", sym); - DEC.setRoundingMode(RoundingMode.HALF_UP); - DEC.setGroupingUsed(false); - SCI = new DecimalFormat("0.##########E0", sym); - SCI.setRoundingMode(RoundingMode.HALF_UP); - SCI.setGroupingUsed(false); - } - + private final CalculatorDisplayUtils utils = new CalculatorDisplayUtils(7); private final OverlaySearchField searchField; private final NumberAnimator width = ValueAnimator.ofDouble().asInt(); private Component fullText = Component.empty(); @@ -94,8 +78,8 @@ public class CalculatorDisplay implements Consumer { if (TextCalculator.isValid(text)) { double eval = new TextCalculator(text).eval(); - this.text = Component.literal(fmt(eval)).getVisualOrderText(); - this.fullText = Component.literal(fmtAccurate(eval)); + this.text = Component.literal(utils.fmt(eval)).getVisualOrderText(); + this.fullText = Component.literal(CalculatorDisplayUtils.fmtAccurate(eval)); } this.width.setTo(Minecraft.getInstance().font.width(this.text) + 6, ConfigObject.getInstance().isReducedMotion() ? 0 : 400); @@ -104,112 +88,4 @@ public class CalculatorDisplay implements Consumer { public int width() { return width.value(); } - - public static String fmt(double x) { - if (Double.isNaN(x) || Double.isInfinite(x)) - return String.valueOf(x); - - boolean neg = x < 0; - double a = Math.abs(x); - - // 1) SMALL <1: decimals to fill WIDTH, else sci - if (a > 0 && a < 1) { - int used = neg ? 1 : 0; - int avail = MAX_LEN - used; // total chars left - // "0" + "." → 2 chars, rest decimals - int dec = avail - 2; - if (dec > 0) { - double minShow = Math.pow(10, -dec); - if (a >= minShow) { - String fmt = "%." + dec + "f"; - String s = String.format(Locale.ROOT, fmt, a) - .replaceFirst("0+$", "") // drop trailing zeros - .replaceFirst("\\.$", ""); // drop trailing dot - // if we got something like ".123", prepend "0" - if (s.startsWith(".")) s = "0" + s; - return neg ? "-" + s : s; - } - } - // too small → scientific - return sciFmt(a, neg); - } - - // 2) exact under threshold - double thresh = neg ? 1_000_000 : 10_000_000; - if (a < thresh) { - String small = (a == Math.rint(a)) - ? String.valueOf((long) a) - : String.format(Locale.ROOT, "%.2f", a) - .replaceFirst("\\.?0+$", ""); - if (small.length() + (neg ? 1 : 0) <= MAX_LEN) - return neg ? "-" + small : small; - } - - // 3) suffix m/b/t - char suf; - double v; - if (a >= 1e12 && a < 1e15) { - suf = 't'; - v = a / 1e12; - } else if (a >= 1e9) { - suf = 'b'; - v = a / 1e9; - } else if (a >= 1e6) { - suf = 'm'; - v = a / 1e6; - } else { - // small ≥1 but <1e6 (or neg ≥1e6) - return sciFmt(a, neg); - } - { - int used = (neg ? 1 : 0) + 1; // sign + suffix - int avail = MAX_LEN - used; - String intP = String.valueOf((long) v); - int ip = intP.length(); - int dec = Math.max(0, avail - ip - 1); // -1 for dot - for (; dec >= 0; dec--) { - String fmt = dec > 0 ? "%." + dec + "f" : "%.0f"; - String man = String.format(Locale.ROOT, fmt, v); - if (man.length() <= avail) - return (neg ? "-" : "") + man + suf; - } - } - - // 4) fallback sci - return sciFmt(a, neg); - } - - private static String sciFmt(double a, boolean neg) { - int exp = (int) Math.floor(Math.log10(a)); - double man = a / Math.pow(10, exp); - String expS = String.valueOf(exp); - int used = (neg ? 1 : 0) + 1 + expS.length(); // sign + 'e'+exp - int avail = MAX_LEN - used; - String intP = String.valueOf((long) man); - int ip = intP.length(); - int dec = Math.max(0, avail - ip - 1); - for (; dec >= 0; dec--) { - String fmt = dec > 0 ? "%." + dec + "f" : "%.0f"; - String mS = String.format(Locale.ROOT, fmt, man); - if (mS.length() <= avail) - return (neg ? "-" : "") + mS + "e" + expS; - } - // worst‐case: truncate integer mantissa - String mS = intP; - if (mS.length() > avail) mS = mS.substring(0, avail); - return (neg ? "-" : "") + mS + "e" + expS; - } - - public static String fmtAccurate(double x) { - if (Double.isNaN(x) || Double.isInfinite(x)) - return String.valueOf(x); - - double a = Math.abs(x); - if (a != 0 && (a < 1e-30 || a >= 1e30)) { - // scientific - return SCI.format(x).replace("E", "e"); - } else { - return DEC.format(x); - } - } } diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/search/CalculatorDisplayUtils.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/search/CalculatorDisplayUtils.java new file mode 100644 index 000000000..fb48a0d0c --- /dev/null +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/search/CalculatorDisplayUtils.java @@ -0,0 +1,139 @@ +package me.shedaniel.rei.impl.client.gui.widget.search; + +import java.math.RoundingMode; +import java.text.DecimalFormat; +import java.text.DecimalFormatSymbols; +import java.util.Locale; + +public class CalculatorDisplayUtils { + private static final DecimalFormat DEC; + private static final DecimalFormat SCI; + + static { + DecimalFormatSymbols sym = DecimalFormatSymbols.getInstance(Locale.ROOT); + DEC = new DecimalFormat("0.##########", sym); + DEC.setRoundingMode(RoundingMode.HALF_UP); + DEC.setGroupingUsed(false); + SCI = new DecimalFormat("0.##########E0", sym); + SCI.setRoundingMode(RoundingMode.HALF_UP); + SCI.setGroupingUsed(false); + } + + private final int maxLength; + + public CalculatorDisplayUtils(int maxLength) { + this.maxLength = maxLength; + } + + public int maxLength() { + return maxLength; + } + + public String fmt(double x) { + if (Double.isNaN(x) || Double.isInfinite(x)) + return String.valueOf(x); + + boolean neg = x < 0; + double a = Math.abs(x); + + // 1) SMALL <1: decimals to fill WIDTH, else sci + if (a > 0 && a < 1) { + int used = neg ? 1 : 0; + int avail = this.maxLength - used; // total chars left + // "0" + "." → 2 chars, rest decimals + int dec = avail - 2; + if (dec > 0) { + double minShow = Math.pow(10, -dec); + if (a >= minShow) { + String fmt = "%." + dec + "f"; + String s = String.format(Locale.ROOT, fmt, a) + .replaceFirst("0+$", "") // drop trailing zeros + .replaceFirst("\\.$", ""); // drop trailing dot + // if we got something like ".123", prepend "0" + if (s.startsWith(".")) s = "0" + s; + return neg ? "-" + s : s; + } + } + // too small → scientific + return sciFmt(a, neg); + } + + // 2) exact under threshold + double thresh = neg ? Math.pow(10, this.maxLength - 2) : Math.pow(10, this.maxLength - 1); + if (a < thresh) { + String small = (a == Math.rint(a)) + ? String.valueOf((long) a) + : String.format(Locale.ROOT, "%.2f", a) + .replaceFirst("\\.?0+$", ""); + if (small.length() + (neg ? 1 : 0) <= this.maxLength) + return neg ? "-" + small : small; + } + + // 3) suffix m/b/t + char suf; + double v; + if (a >= 1e12 && a < 1e15) { + suf = 't'; + v = a / 1e12; + } else if (a >= 1e9) { + suf = 'b'; + v = a / 1e9; + } else if (a >= 1e6) { + suf = 'm'; + v = a / 1e6; + } else { + // small ≥1 but <1e6 (or neg ≥1e6) + return sciFmt(a, neg); + } + { + int used = (neg ? 1 : 0) + 1; // sign + suffix + int avail = this.maxLength - used; + String intP = String.valueOf((long) v); + int ip = intP.length(); + int dec = Math.max(0, avail - ip - 1); // -1 for dot + for (; dec >= 0; dec--) { + String fmt = dec > 0 ? "%." + dec + "f" : "%.0f"; + String man = String.format(Locale.ROOT, fmt, v); + if (man.length() <= avail) + return (neg ? "-" : "") + man + suf; + } + } + + // 4) fallback sci + return sciFmt(a, neg); + } + + private String sciFmt(double a, boolean neg) { + int exp = (int) Math.floor(Math.log10(a)); + double man = a / Math.pow(10, exp); + String expS = String.valueOf(exp); + int used = (neg ? 1 : 0) + 1 + expS.length(); // sign + 'e'+exp + int avail = this.maxLength - used; + String intP = String.valueOf((long) man); + int ip = intP.length(); + int dec = Math.max(0, avail - ip - 1); + for (; dec >= 0; dec--) { + String fmt = dec > 0 ? "%." + dec + "f" : "%.0f"; + String mS = String.format(Locale.R