From 0ff828b4c53079de978824f54d73a6ac340ae9f9 Mon Sep 17 00:00:00 2001 From: shedaniel Date: Fri, 27 Oct 2023 16:14:08 +0800 Subject: Add preview for accessibility tab sizes, and interface themes --- .../rei/impl/client/gui/config/ConfigAccess.java | 34 ++++++ .../impl/client/gui/config/REIConfigScreen.java | 21 +++- .../config/components/ConfigEntriesListWidget.java | 5 +- .../gui/config/components/ConfigGroupWidget.java | 33 +++--- .../config/components/ConfigOptionValueWidget.java | 23 ++-- .../gui/config/components/ConfigOptionWidget.java | 8 +- .../gui/config/options/AllREIConfigOptions.java | 4 +- .../client/gui/config/options/ConfigUtils.java | 2 +- .../preview/AccessibilityDisplayPreviewer.java | 80 +++++++++++++ .../config/options/preview/InterfacePreviewer.java | 107 +++++++++++++++++ .../gui/config/options/preview/ThemePreviewer.java | 65 ----------- .../gui/config/options/preview/TooltipPreview.java | 130 --------------------- .../config/options/preview/TooltipPreviewer.java | 130 +++++++++++++++++++++ .../rei/impl/client/gui/widget/EntryWidget.java | 7 +- .../impl/client/gui/widget/TabContainerWidget.java | 79 +++++++------ .../rei/impl/client/gui/widget/TabWidget.java | 4 +- .../client/gui/widget/basewidgets/ArrowWidget.java | 8 +- 17 files changed, 465 insertions(+), 275 deletions(-) create mode 100644 runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/ConfigAccess.java create mode 100644 runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/options/preview/AccessibilityDisplayPreviewer.java create mode 100644 runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/options/preview/InterfacePreviewer.java delete mode 100644 runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/options/preview/ThemePreviewer.java delete mode 100644 runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/options/preview/TooltipPreview.java create mode 100644 runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/options/preview/TooltipPreviewer.java (limited to 'runtime/src/main/java') diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/ConfigAccess.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/ConfigAccess.java new file mode 100644 index 000000000..3c6391f69 --- /dev/null +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/ConfigAccess.java @@ -0,0 +1,34 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020, 2021, 2022, 2023 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.config; + +import me.shedaniel.rei.impl.client.gui.config.options.CompositeOption; + +public interface ConfigAccess { + T get(CompositeOption option); + + void set(CompositeOption option, T value); + + T getDefault(CompositeOption option); +} diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/REIConfigScreen.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/REIConfigScreen.java index 89bd772e3..3a0566b8e 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/REIConfigScreen.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/REIConfigScreen.java @@ -52,7 +52,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -public class REIConfigScreen extends Screen { +public class REIConfigScreen extends Screen implements ConfigAccess { private final Screen parent; private final List categories; private final List widgets = new ArrayList<>(); @@ -97,12 +97,12 @@ public class REIConfigScreen extends Screen { int sideWidth = (int) (width / 4.2); boolean singlePane = width - 20 - sideWidth <= 330; int singleSideWidth = 32 + 6 + 4; - Widget[] list = {ConfigEntriesListWidget.create(new Rectangle(singlePane ? 8 + singleSideWidth : 12 + sideWidth, 32, singlePane ? width - 16 - singleSideWidth : width - 20 - sideWidth, height - 32 - 32), activeCategory.getGroups())}; + Widget[] list = {ConfigEntriesListWidget.create(this, new Rectangle(singlePane ? 8 + singleSideWidth : 12 + sideWidth, 32, singlePane ? width - 16 - singleSideWidth : width - 20 - sideWidth, height - 32 - 32), activeCategory.getGroups())}; IntValue selectedCategory = new IntValue() { @Override public void accept(int i) { REIConfigScreen.this.activeCategory = categories.get(i); - list[0] = ConfigEntriesListWidget.create(new Rectangle(singlePane ? 8 + singleSideWidth : 12 + sideWidth, 32, singlePane ? width - 16 - singleSideWidth : width - 20 - sideWidth, height - 32 - 32), activeCategory.getGroups()); + list[0] = ConfigEntriesListWidget.create(REIConfigScreen.this, new Rectangle(singlePane ? 8 + singleSideWidth : 12 + sideWidth, 32, singlePane ? width - 16 - singleSideWidth : width - 20 - sideWidth, height - 32 - 32), activeCategory.getGroups()); } @Override @@ -202,4 +202,19 @@ public class REIConfigScreen extends Screen { this.widgets.remove(menu); this.menu = null; } + + @Override + public T get(CompositeOption option) { + return (T) getOptions().get(option); + } + + @Override + public void set(CompositeOption option, T value) { + ((Map, Object>) getOptions()).put(option, value); + } + + @Override + public T getDefault(CompositeOption option) { + return (T) getDefaultOptions().get(option); + } } diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/components/ConfigEntriesListWidget.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/components/ConfigEntriesListWidget.java index de05300eb..b1ecca932 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/components/ConfigEntriesListWidget.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/components/ConfigEntriesListWidget.java @@ -26,6 +26,7 @@ package me.shedaniel.rei.impl.client.gui.config.components; import me.shedaniel.math.Rectangle; import me.shedaniel.rei.api.client.gui.widgets.Widget; import me.shedaniel.rei.api.client.gui.widgets.WidgetWithBounds; +import me.shedaniel.rei.impl.client.gui.config.ConfigAccess; import me.shedaniel.rei.impl.client.gui.config.options.OptionGroup; import me.shedaniel.rei.impl.client.gui.widget.ListWidget; import me.shedaniel.rei.impl.client.gui.widget.ScrollableViewWidget; @@ -34,9 +35,9 @@ import me.shedaniel.rei.impl.common.util.RectangleUtils; import java.util.List; public class ConfigEntriesListWidget { - public static Widget create(Rectangle bounds, List groups) { + public static Widget create(ConfigAccess access, Rectangle bounds, List groups) { WidgetWithBounds list = ListWidget.builderOf(RectangleUtils.inset(bounds, 6, 6), groups, - (index, entry) -> ConfigGroupWidget.create(entry, bounds.width - 12 - 6)) + (index, entry) -> ConfigGroupWidget.create(access, entry, bounds.width - 12 - 6)) .gap(7) .calculateTotalHeightDynamically(true) .build(); diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/components/ConfigGroupWidget.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/components/ConfigGroupWidget.java index e23924ac7..bf9f48c55 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/components/ConfigGroupWidget.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/components/ConfigGroupWidget.java @@ -30,10 +30,13 @@ import me.shedaniel.rei.api.client.gui.widgets.Widget; import me.shedaniel.rei.api.client.gui.widgets.WidgetWithBounds; import me.shedaniel.rei.api.client.gui.widgets.Widgets; import me.shedaniel.rei.api.client.util.MatrixUtils; +import me.shedaniel.rei.impl.client.gui.config.ConfigAccess; import me.shedaniel.rei.impl.client.gui.config.options.AllREIConfigGroups; import me.shedaniel.rei.impl.client.gui.config.options.CompositeOption; import me.shedaniel.rei.impl.client.gui.config.options.OptionGroup; -import me.shedaniel.rei.impl.client.gui.config.options.preview.TooltipPreview; +import me.shedaniel.rei.impl.client.gui.config.options.preview.AccessibilityDisplayPreviewer; +import me.shedaniel.rei.impl.client.gui.config.options.preview.InterfacePreviewer; +import me.shedaniel.rei.impl.client.gui.config.options.preview.TooltipPreviewer; import net.minecraft.client.gui.GuiComponent; import org.apache.commons.lang3.tuple.Pair; import org.apache.commons.lang3.tuple.Triple; @@ -47,14 +50,16 @@ public class ConfigGroupWidget { private static final Map> SPECIAL_GROUPS = new HashMap<>(); static { - addPreview(AllREIConfigGroups.APPEARANCE_TOOLTIPS, PreviewLocation.RIGHT, (entry, width, height) -> TooltipPreview.create(width, height)); + addPreview(AllREIConfigGroups.APPEARANCE_INTERFACE, PreviewLocation.RIGHT, (access, entry, width, height) -> InterfacePreviewer.create(access, width, height)); + addPreview(AllREIConfigGroups.APPEARANCE_TOOLTIPS, PreviewLocation.RIGHT, (access, entry, width, height) -> TooltipPreviewer.create(access, width, height)); + addPreview(AllREIConfigGroups.ACCESSIBILITY_DISPLAY, PreviewLocation.BOTTOM, (access, entry, width, height) -> AccessibilityDisplayPreviewer.create(access, width)); } public static void addPreview(OptionGroup group, PreviewLocation location, SpecialGroupConstructor constructor) { SPECIAL_GROUPS.put(group, Pair.of(location, constructor)); } - public static WidgetWithBounds create(OptionGroup entry, int width) { + public static WidgetWithBounds create(ConfigAccess access, OptionGroup entry, int width) { WidgetWithBounds groupTitle = Widgets.createLabel(new Point(0, 3), entry.getGroupName().copy().withStyle(style -> style.withColor(0xFFC0C0C0).withUnderlined(true))) .leftAligned() .withPadding(0, 0, 0, 6); @@ -64,30 +69,30 @@ public class ConfigGroupWidget { Pair pair = SPECIAL_GROUPS.get(entry); PreviewLocation location = pair.getLeft(); int halfWidth = width * 6 / 10 - 2; - if (halfWidth <= 200) location = PreviewLocation.TOP; + if (halfWidth <= 200 && location == PreviewLocation.RIGHT) location = PreviewLocation.TOP; if (location == PreviewLocation.RIGHT) { - WidgetWithBounds original = _create(entry, halfWidth); + WidgetWithBounds original = _create(access, entry, halfWidth); Widget background = createBackgroundSlot(() -> new Rectangle(halfWidth + 2, 0, width - halfWidth - 4, original.getBounds().height)); - Widget right = Widgets.withTranslate(pair.getRight().create(entry, () -> width - halfWidth - 4, () -> original.getBounds().height), halfWidth + 2, 0, 0); + Widget right = Widgets.withTranslate(pair.getRight().create(access, entry, width - halfWidth - 4, () -> original.getBounds().height), halfWidth + 2, 0, 0); contents = Widgets.concatWithBounds(() -> new Rectangle(0, 0, width, original.getBounds().height), original, background, right); } else { - WidgetWithBounds original = _create(entry, width); + WidgetWithBounds original = _create(access, entry, width); if (location == PreviewLocation.TOP) { - WidgetWithBounds widget = pair.getRight().create(entry, () -> width, null); + WidgetWithBounds widget = pair.getRight().create(access, entry, width, null); Widget background = createBackgroundSlot(widget::getBounds); WidgetWithBounds translatedOriginal = Widgets.withTranslate(original, () -> Matrix4f.createTranslateMatrix(0, widget.getBounds().height + 4, 0)); contents = Widgets.concatWithBounds(() -> new Rectangle(0, 0, width, widget.getBounds().height + 4 + translatedOriginal.getBounds().height), translatedOriginal, background, widget); } else { - WidgetWithBounds widget = pair.getRight().create(entry, () -> width, null); + WidgetWithBounds widget = pair.getRight().create(access, entry, width, null); Widget background = createBackgroundSlot(widget::getBounds); - contents = Widgets.concatWithBounds(() -> new Rectangle(0, 0, width, original.getBounds().getMaxY() + 4 + widget.getBounds().height), original, + contents = Widgets.concatWithBounds(() -> new Rectangle(0, 0, width, original.getBounds().getMaxY() + 2 + widget.getBounds().height), original, Widgets.withTranslate(Widgets.concat(background, widget), () -> Matrix4f.createTranslateMatrix(0, original.getBounds().getMaxY() + 4, 0))); } } } else { - contents = _create(entry, width); + contents = _create(access, entry, width); } return Widgets.concatWithBounds( @@ -97,13 +102,13 @@ public class ConfigGroupWidget { ); } - private static WidgetWithBounds _create(OptionGroup entry, int width) { + private static WidgetWithBounds _create(ConfigAccess access, OptionGroup entry, int width) { List, Matrix4f[]>> widgets = new ArrayList<>(); int[] height = {0}; for (CompositeOption option : entry.getOptions()) { Matrix4f[] translation = new Matrix4f[]{Matrix4f.createTranslateMatrix(0, height[0], 0)}; - WidgetWithBounds widget = Widgets.withTranslate(ConfigOptionWidget.create(option, width), () -> translation[0]); + WidgetWithBounds widget = Widgets.withTranslate(ConfigOptionWidget.create(access, option, width), () -> translation[0]); widgets.add(Triple.of(widget, () -> MatrixUtils.transform(translation[0], widget.getBounds()), translation)); height[0] = Math.max(height[0], widget.getBounds().getMaxY()); @@ -143,7 +148,7 @@ public class ConfigGroupWidget { @FunctionalInterface public interface SpecialGroupConstructor { - WidgetWithBounds create(OptionGroup entry, IntSupplier width, @Nullable IntSupplier height); + WidgetWithBounds create(ConfigAccess access, OptionGroup entry, int width, @Nullable IntSupplier height); } public enum PreviewLocation { diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/components/ConfigOptionValueWidget.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/components/ConfigOptionValueWidget.java index e2d62eed3..fa7b6ea22 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/components/ConfigOptionValueWidget.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/components/ConfigOptionValueWidget.java @@ -23,7 +23,6 @@ package me.shedaniel.rei.impl.client.gui.config.components; -import com.google.common.base.MoreObjects; import com.mojang.math.Matrix4f; import me.shedaniel.math.Point; import me.shedaniel.math.Rectangle; @@ -33,6 +32,7 @@ import me.shedaniel.rei.api.client.gui.widgets.WidgetWithBounds; import me.shedaniel.rei.api.client.gui.widgets.Widgets; import me.shedaniel.rei.api.client.util.MatrixUtils; import me.shedaniel.rei.api.common.util.CollectionUtils; +import me.shedaniel.rei.impl.client.gui.config.ConfigAccess; import me.shedaniel.rei.impl.client.gui.config.REIConfigScreen; import me.shedaniel.rei.impl.client.gui.config.options.CompositeOption; import me.shedaniel.rei.impl.client.gui.config.options.OptionValueEntry; @@ -43,18 +43,15 @@ import net.minecraft.client.Minecraft; import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceLocation; -import java.util.Map; import java.util.Objects; import static me.shedaniel.rei.impl.client.gui.config.options.ConfigUtils.literal; import static me.shedaniel.rei.impl.client.gui.config.options.ConfigUtils.translatable; public class ConfigOptionValueWidget { - public static WidgetWithBounds create(CompositeOption option) { - Map, ?> defaultOptions = ((REIConfigScreen) Minecraft.getInstance().screen).getDefaultOptions(); - Map, ?> options = ((REIConfigScreen) Minecraft.getInstance().screen).getOptions(); + public static WidgetWithBounds create(ConfigAccess access, CompositeOption option) { OptionValueEntry entry = option.getEntry(); - T value = (T) options.get(option); + T value = access.get(option); Component[] text = new Component[1]; if (entry instanceof OptionValueEntry.Selection selection) { @@ -63,7 +60,7 @@ public class ConfigOptionValueWidget { text[0] = literal(value.toString()); } - if (value.equals(Objects.requireNonNullElseGet(option.getDefaultValue(), () -> (T) defaultOptions.get(option)))) { + if (value.equals(Objects.requireNonNullElseGet(option.getDefaultValue(), () -> access.getDefault(option)))) { text[0] = translatable("config.rei.value.default", text[0]); } @@ -83,10 +80,10 @@ public class ConfigOptionValueWidget { int noOfOptions = selection.getOptions().size(); if (noOfOptions == 2) { label.clickable().onClick($ -> { - ((Map, Object>) options).put(option, selection.getOptions().get((selection.getOptions().indexOf((T) options.get(option)) + 1) % 2)); - text[0] = selection.getOption((T) options.get(option)); + access.set(option, selection.getOptions().get((selection.getOptions().indexOf(access.get(option)) + 1) % 2)); + text[0] = selection.getOption(access.get(option)); - if (options.get(option).equals(Objects.requireNonNullElseGet(option.getDefaultValue(), () -> (T) defaultOptions.get(option)))) { + if (access.get(option).equals(Objects.requireNonNullElseGet(option.getDefaultValue(), () -> access.getDefault(option)))) { text[0] = translatable("config.rei.value.default", text[0]); } }); @@ -94,16 +91,16 @@ public class ConfigOptionValueWidget { label.clickable().onClick($ -> { Menu menu = new Menu(MatrixUtils.transform(matrix[0], label.getBounds()), CollectionUtils.map(selection.getOptions(), opt -> { Component selectionOption = selection.getOption(opt); - if (opt.equals(defaultOptions.get(option))) { + if (opt.equals(access.getDefault(option))) { selectionOption = translatable("config.rei.value.default", selectionOption); } return ToggleMenuEntry.of(selectionOption, () -> false, o -> { ((REIConfigScreen) Minecraft.getInstance().screen).closeMenu(); - ((Map, Object>) options).put(option, opt); + access.set(option, opt); text[0] = selection.getOption(opt); - if (options.get(option).equals(defaultOptions.get(option))) { + if (access.get(option).equals(access.getDefault(option))) { text[0] = translatable("config.rei.value.default", text[0]); } }); diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/components/ConfigOptionWidget.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/components/ConfigOptionWidget.java index a8060b520..ba546edd1 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/components/ConfigOptionWidget.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/components/ConfigOptionWidget.java @@ -35,7 +35,7 @@ import me.shedaniel.rei.api.client.gui.widgets.Widget; import me.shedaniel.rei.api.client.gui.widgets.WidgetWithBounds; import me.shedaniel.rei.api.client.gui.widgets.Widgets; import me.shedaniel.rei.api.client.util.MatrixUtils; -import me.shedaniel.rei.impl.client.gui.config.REIConfigScreen; +import me.shedaniel.rei.impl.client.gui.config.ConfigAccess; import me.shedaniel.rei.impl.client.gui.config.options.CompositeOption; import me.shedaniel.rei.impl.client.gui.config.options.ConfigUtils; import net.minecraft.client.Minecraft; @@ -50,13 +50,13 @@ import java.util.List; import static me.shedaniel.rei.impl.client.gui.config.options.ConfigUtils.translatable; public class ConfigOptionWidget { - public static WidgetWithBounds create(CompositeOption option, int width) { + public static WidgetWithBounds create(ConfigAccess access, CompositeOption option, int width) { List widgets = new ArrayList<>(); int[] stableHeight = {12}; int[] height = {12}; widgets.add(Widgets.createLabel(new Point(0, 0), option.getName().copy().withStyle(style -> style.withColor(0xFFC0C0C0))) .leftAligned()); - WidgetWithBounds optionValue = ConfigOptionValueWidget.create(option); + WidgetWithBounds optionValue = ConfigOptionValueWidget.create(access, option); widgets.add(Widgets.withTranslate(optionValue, () -> Matrix4f.createTranslateMatrix(width - optionValue.getBounds().width - optionValue.getBounds().x, 0, 0))); widgets.add(new WidgetWithBounds() { final MutableComponent description = option.getDescription().copy().withStyle(style -> style.withColor(0xFF757575)); @@ -123,7 +123,7 @@ public class ConfigOptionWidget { private void clickPreview() { if (this.preview == null) { - this.preview = option.getPreviewer().preview(width, () -> (T) ((REIConfigScreen) Minecraft.getInstance().screen).getOptions().get(option)); + this.preview = option.getPreviewer().preview(width, () -> access.get(option)); this.preview = Widgets.withTranslate(this.preview, () -> this.previewTranslation); } 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 bcd3617fd..257088865 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 @@ -26,7 +26,6 @@ package me.shedaniel.rei.impl.client.gui.config.options; import me.shedaniel.rei.api.client.gui.config.*; import me.shedaniel.rei.impl.client.config.ConfigObjectImpl; import me.shedaniel.rei.impl.client.gui.config.REIConfigScreen; -import me.shedaniel.rei.impl.client.gui.config.options.preview.ThemePreviewer; import net.minecraft.client.Minecraft; import java.util.function.BiConsumer; @@ -43,8 +42,7 @@ public interface AllREIConfigOptions { } CompositeOption THEME = make("appearance.theme", i -> i.appearance.theme, (i, v) -> i.appearance.theme = v) - .enumOptions() - .previewer(ThemePreviewer.INSTANCE); + .enumOptions(); CompositeOption RECIPE_BORDER = make("appearance.recipe_border", i -> i.appearance.recipeBorder, (i, v) -> i.appearance.recipeBorder = v) .enumOptions(); CompositeOption REDUCED_MOTION = make("appearance.reduced_motion", i -> i.basics.reduceMotion, (i, v) -> i.basics.reduceMotion = v) diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/options/ConfigUtils.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/options/ConfigUtils.java index b65826f23..539be5526 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/options/ConfigUtils.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/options/ConfigUtils.java @@ -33,7 +33,7 @@ import net.minecraft.network.chat.TranslatableComponent; public interface ConfigUtils { static boolean isReducedMotion() { if (Minecraft.getInstance().screen instanceof REIConfigScreen screen) { - return ((Boolean) screen.getOptions().get(AllREIConfigOptions.REDUCED_MOTION)).booleanValue(); + return screen.get(AllREIConfigOptions.REDUCED_MOTION); } else { return ConfigObject.getInstance().isReducedMotion(); } diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/options/preview/AccessibilityDisplayPreviewer.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/options/preview/AccessibilityDisplayPreviewer.java new file mode 100644 index 000000000..ccebdab45 --- /dev/null +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/options/preview/AccessibilityDisplayPreviewer.java @@ -0,0 +1,80 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020, 2021, 2022, 2023 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.config.options.preview; + +import com.google.common.base.MoreObjects; +import me.shedaniel.math.Rectangle; +import me.shedaniel.rei.api.client.gui.widgets.Widget; +import me.shedaniel.rei.api.client.gui.widgets.WidgetWithBounds; +import me.shedaniel.rei.api.client.gui.widgets.Widgets; +import me.shedaniel.rei.api.common.entry.EntryStack; +import me.shedaniel.rei.api.common.util.EntryStacks; +import me.shedaniel.rei.impl.client.gui.config.ConfigAccess; +import me.shedaniel.rei.impl.client.gui.config.options.AllREIConfigOptions; +import me.shedaniel.rei.impl.client.gui.widget.TabContainerWidget; +import me.shedaniel.rei.impl.client.gui.widget.TabWidget; +import net.minecraft.world.item.Items; + +public class AccessibilityDisplayPreviewer { + public static WidgetWithBounds create(ConfigAccess access, int width) { + int[] selected = {0}; + TabWidget[] tabs = new TabWidget[4]; + Widget[] buttons = {null}; + return Widgets.concatWithBounds(() -> new Rectangle(width, 36 + 17), + Widgets.delegate(() -> MoreObjects.firstNonNull(tabs[0], Widgets.noOp())), + Widgets.delegate(() -> MoreObjects.firstNonNull(tabs[1], Widgets.noOp())), + Widgets.delegate(() -> MoreObjects.firstNonNull(tabs[2], Widgets.noOp())), + Widgets.delegate(() -> MoreObjects.firstNonNull(tabs[3], Widgets.noOp())), + Widgets.scissored(new Rectangle(1, 1, width - 2, 34 + 17), Widgets.createCategoryBase(new Rectangle(width / 2 - 28 * 3 / 2 - 10, 30 + 17, 28 * 3 + 20, 28))), + Widgets.delegate(() -> MoreObjects.firstNonNull(selected[0] < 4 ? tabs[selected[0]] : null, Widgets.noOp())), + Widgets.delegate(() -> MoreObjects.firstNonNull(buttons[0], Widgets.noOp())), + Widgets.createDrawableWidget((helper, matrices, mouseX, mouseY, delta) -> { + boolean largerTabs = access.get(AllREIConfigOptions.LARGER_TABS); + boolean largerArrowButtons = access.get(AllREIConfigOptions.LARGER_ARROW_BUTTONS); + int tabSize = largerTabs ? 28 : 24; + for (int i = 0; i < 4; i++) { + tabs[i] = null; + } + for (int i = 0; i < (largerTabs ? 3 : 4); i++) { + int finalI = i; + tabs[i] = TabWidget.create(i, tabSize, width / 2 - tabSize * (largerTabs ? 3 : 4) / 2, 30 + 17, 0, !largerTabs ? 166 : 192, tabWidget -> { + selected[0] = finalI; + return true; + }); + EntryStack stack = i == 0 ? EntryStacks.of(Items.CRAFTING_TABLE) : + i == 1 ? EntryStacks.of(Items.FURNACE) : + i == 2 ? EntryStacks.of(Items.SMOKER) : + EntryStacks.of(Items.BLAST_FURNACE); + tabs[i].setRenderer(null, stack, null, selected[0] == i); + } + if (selected[0] >= (largerTabs ? 3 : 4)) selected[0] = 0; + + buttons[0] = Widgets.concat(TabContainerWidget.getCategoryButtons(new Rectangle(width / 2 - 28 * 3 / 2 - 10, 2 + 16, 28 * 3 + 20, 28), + !largerArrowButtons, tabSize, largerArrowButtons ? 16 : 10, () -> { + }, () -> { + })); + }) + ); + } +} diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/options/preview/InterfacePreviewer.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/options/preview/InterfacePreviewer.java new file mode 100644 index 000000000..80e493784 --- /dev/null +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/options/preview/InterfacePreviewer.java @@ -0,0 +1,107 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020, 2021, 2022, 2023 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.config.options.preview; + +import com.mojang.math.Matrix4f; +import me.shedaniel.clothconfig2.api.animator.NumberAnimator; +import me.shedaniel.clothconfig2.api.animator.ValueAnimator; +import me.shedaniel.math.Point; +import me.shedaniel.math.Rectangle; +import me.shedaniel.rei.api.client.gui.config.AppearanceTheme; +import me.shedaniel.rei.api.client.gui.config.RecipeBorderType; +import me.shedaniel.rei.api.client.gui.widgets.Panel; +import me.shedaniel.rei.api.client.gui.widgets.Widget; +import me.shedaniel.rei.api.client.gui.widgets.WidgetWithBounds; +import me.shedaniel.rei.api.client.gui.widgets.Widgets; +import me.shedaniel.rei.api.common.util.EntryIngredients; +import me.shedaniel.rei.api.common.util.EntryStacks; +import me.shedaniel.rei.impl.client.gui.config.ConfigAccess; +import me.shedaniel.rei.impl.client.gui.config.options.AllREIConfigOptions; +import me.shedaniel.rei.impl.client.gui.widget.EntryWidget; +import me.shedaniel.rei.impl.client.gui.widget.basewidgets.ArrowWidget; +import me.shedaniel.rei.impl.client.gui.widget.basewidgets.PanelWidget; +import net.minecraft.Util; +import net.minecraft.world.item.Items; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.IntSupplier; + +public class InterfacePreviewer { + public static WidgetWithBounds create(ConfigAccess access, int width, @Nullable IntSupplier height) { + WidgetWithBounds widget = _create(access, width); + if (height == null) { + Widget background = Widgets.createCategoryBase(new Rectangle(2, 2, width - 4, widget.getBounds().height - 4)); + return Widgets.concatWithBounds(widget::getBounds, background, widget); + } + Panel base = Widgets.createCategoryBase(new Rectangle(2, 2, width - 4, height.getAsInt() - 4)); + ((PanelWidget) base).setDarkBackgroundAlpha(ValueAnimator.ofFloat() + .withConvention(() -> access.get(AllREIConfigOptions.THEME) == AppearanceTheme.DARK ? 1.0F : 0.0F, ValueAnimator.typicalTransitionTime()) + .asFloat()); + return Widgets.concatWithBounds(() -> new Rectangle(width, height.getAsInt()), + Widgets.delegate(() -> { + base.getBounds().setBounds(2, 2, width - 4, height.getAsInt() - 4); + return base; + }), + Widgets.withTranslate(widget, () -> Matrix4f.createTranslateMatrix(0, (height.getAsInt() - widget.getBounds().height) / 2, 0)) + ); + } + + private static WidgetWithBounds _create(ConfigAccess access, int width) { + List widgets = new ArrayList<>(); + int displayWidth = 124, displayHeight = 66; + Rectangle displayBounds = new Rectangle((width - displayWidth) / 2, (80 - displayHeight) / 2, displayWidth, displayHeight); + NumberAnimator themeAlpha = ValueAnimator.ofFloat() + .withConvention(() -> access.get(AllREIConfigOptions.THEME) == AppearanceTheme.DARK ? 1.0F : 0.0F, ValueAnimator.typicalTransitionTime()) + .asFloat(); + widgets.add(Util.make(Widgets.createRecipeBase(displayBounds), panel -> { + ((PanelWidget) panel).setDarkBackgroundAlpha(themeAlpha); + }).rendering(panel -> { + RecipeBorderType type = access.get(AllREIConfigOptions.RECIPE_BORDER); + panel.yTextureOffset(type.getYOffset()); + return type.isRendering(); + })); + Point startingPoint = new Point(displayBounds.x + 6, displayBounds.y + 6); + widgets.add(Util.make(Widgets.createArrow(new Point(startingPoint.x + 58, startingPoint.y + 18)), arrow -> { + ((ArrowWidget) arrow).setDarkBackgroundAlpha(themeAlpha); + })); + widgets.add(Util.make(Widgets.createResultSlotBackground(new Point(startingPoint.x + 91, startingPoint.y + 19)), panel -> { + ((PanelWidget) panel).setDarkBackgroundAlpha(themeAlpha); + })); + for (int y = 0; y < 3; y++) + for (int x = 0; x < 3; x++) + widgets.add(Util.make(Widgets.createSlot(new Point(startingPoint.x + 1 + x * 18, startingPoint.y + 1 + y * 18)) + .notInteractable() + .entries(x == 1 && y == 1 ? List.of() : EntryIngredients.of(Items.COBBLESTONE)), slot -> { + ((EntryWidget) slot).setDarkBackgroundAlpha(themeAlpha); + })); + widgets.add(Util.make(Widgets.createSlot(new Point(startingPoint.x + 91, startingPoint.y + 19)).disableBackground() + .notInteractable() + .entry(EntryStacks.of(Items.FURNACE)), slot -> { + ((EntryWidget) slot).setDarkBackgroundAlpha(themeAlpha); + })); + return Widgets.concatWithBounds(new Rectangle(width, 80), widgets); + } +} diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/options/preview/ThemePreviewer.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/options/preview/ThemePreviewer.java deleted file mode 100644 index 1a1670862..000000000 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/options/preview/ThemePreviewer.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * This file is licensed under the MIT License, part of Roughly Enough Items. - * Copyright (c) 2018, 2019, 2020, 2021, 2022, 2023 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.config.options.preview; - -import me.shedaniel.clothconfig2.api.animator.ValueAnimator; -import me.shedaniel.math.Color; -import me.shedaniel.math.Point; -import me.shedaniel.math.Rectangle; -import me.shedaniel.rei.api.client.gui.config.AppearanceTheme; -import me.shedaniel.rei.api.client.gui.widgets.Label; -import me.shedaniel.rei.api.client.gui.widgets.Panel; -import me.shedaniel.rei.api.client.gui.widgets.WidgetWithBounds; -import me.shedaniel.rei.api.client.gui.widgets.Widgets; -import me.shedaniel.rei.impl.client.gui.config.options.ConfigPreviewer; -import me.shedaniel.rei.impl.client.gui.config.options.ConfigUtils; -import me.shedaniel.rei.impl.client.gui.widget.basewidgets.PanelWidget; - -import java.util.List; -import java.util.function.Supplier; - -public enum ThemePreviewer implements ConfigPreviewer { - INSTANCE; - - @Override - public WidgetWithBounds preview(int width, Supplier value) { - Panel base = Widgets.createCategoryBase(new Rectangle(width * 5 / 20, 3, width * 5 / 10, 50)); - ((PanelWidget) base).setDarkBackgroundAlpha(ValueAnimator.ofFloat() - .withConvention(() -> value.get() == AppearanceTheme.DARK ? 1.0F : 0.0F, ValueAnimator.typicalTransitionTime()) - .asFloat()); - ValueAnimator labelColor = ValueAnimator.ofColor(value.get() == AppearanceTheme.LIGHT ? Color.ofTransparent(0xFF404040) : Color.ofTransparent(0xFFBBBBBB)) - .withConvention(() -> value.get() == AppearanceTheme.LIGHT ? Color.ofTransparent(0xFF404040) : Color.ofTransparent(0xFFBBBBBB), ValueAnimator.typicalTransitionTime()); - Label label = Widgets.createLabel(new Point(width / 2, 24), ConfigUtils.literal("Preview")) - .centered() - .noShadow() - .color(labelColor.value().getColor()); - return Widgets.concatWithBounds(new Rectangle(0, 0, width, 56), List.of(base, label, Widgets.createDrawableWidget((helper, matrices, mouseX, mouseY, delta) -> { - labelColor.update(delta); - if (ConfigUtils.isReducedMotion()) { - labelColor.completeImmediately(); - } - label.color(labelColor.value().getColor()); - }))); - } -} diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/options/preview/TooltipPreview.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/options/preview/TooltipPreview.java deleted file mode 100644 index b55ba666b..000000000 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/options/preview/TooltipPreview.java +++ /dev/null @@ -1,130 +0,0 @@ -/* - * This file is licensed under the MIT License, part of Roughly Enough Items. - * Copyright (c) 2018, 2019, 2020, 2021, 2022, 2023 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.config.options.preview; - -import com.mojang.blaze3d.systems.RenderSystem; -import com.mojang.blaze3d.vertex.*; -import com.mojang.math.Matrix4f; -import me.shedaniel.math.Rectangle; -import me.shedaniel.rei.api.client.config.ConfigObject; -import me.shedaniel.rei.api.client.gui.widgets.Tooltip; -import me.shedaniel.rei.api.client.gui.widgets.WidgetWithBounds; -import me.shedaniel.rei.api.client.gui.widgets.Widgets; -import me.shedaniel.rei.api.common.entry.EntryStack; -import me.shedaniel.rei.api.common.util.EntryStacks; -import me.shedaniel.rei.impl.client.gui.config.REIConfigScreen; -import me.shedaniel.rei.impl.client.gui.config.options.AllREIConfigOptions; -import net.minecraft.ChatFormatting; -import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.GameRenderer; -import net.minecraft.client.resources.language.I18n; -import net.minecraft.network.chat.TextComponent; -import net.minecraft.network.chat.TranslatableComponent; -import net.minecraft.util.FormattedCharSequence; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.Items; - -import javax.annotation.Nullable; -import java.util.ArrayList; -import java.util.List; -import java.util.function.IntSupplier; -import java.util.stream.Stream; - -public class TooltipPreview { - public static WidgetWithBounds create(IntSupplier width, @Nullable IntSupplier height) { - Rectangle bounds = new Rectangle(); - return Widgets.withBounds(Widgets.createDrawableWidget((helper, matrices, mouseX, mouseY, delta) -> { - EntryStack stack = EntryStacks.of(Items.OAK_PLANKS); - boolean appendModNames = (Boolean) ((REIConfigScreen) Minecraft.getInstance().screen).getOptions().get(AllREIConfigOptions.APPEND_MOD_NAMES); - boolean appendFavorites = (Boolean) ((REIConfigScreen) Minecraft.getInstance().screen).getOptions().get(AllREIConfigOptions.APPEND_FAVORITES_HINT); - List entries = new ArrayList<>(); - entries.add(Tooltip.entry(new TranslatableComponent("block.minecraft.oak_planks"))); - if (appendModNames) { - entries.add(Tooltip.entry(new TextComponent("Minecraft").withStyle(ChatFormatting.BLUE, ChatFormatting.ITALIC))); - } - if (appendFavorites) { - String name = ConfigObject.getInstance().getFavoriteKeyCode().getLocalizedName().getString(); - entries.addAll(Stream.of(I18n.get("text.rei.favorites_tooltip", name).split("\n")) - .map(TextComponent::new).map(Tooltip::entry).toList()); - } - List components = entries.stream().flatMap(entry -> Minecraft.getInstance().font.split(entry.getAsText(), width.getAsInt() - 12 - 4).stream()).toList(); - int minWidth = components.stream().mapToInt(component -> Minecraft.getInstance().font.width(component)).max().orElse(0) + 4; - int minHeight = components.stream().mapToInt(component -> components.get(0) == component && components.size() >= 2 ? 2 + 10 : 10).sum() + 4; - - int tX = Math.max(6, (width.getAsInt() - minWidth) / 2), tWidth = Math.min(width.getAsInt() - 12, minWidth), tY = 24 + 4, tHeight = Math.min(minHeight, height == null ? 100000 : height.getAsInt() - tY - 4); - matrices.pushPose(); - matrices.translate(0, height == null ? 4 : Math.max(0, (height.getAsInt() - (tY + tHeight)) / 2), 400); - bounds.setBounds(0, 0, width.getAsInt(), height == null ? tY + tHeight + 12 : height.getAsInt()); - stack.getRenderer().render(stack, matrices, new Rectangle(width.getAsInt() / 2 - 12, 0, 24, 24), mouseX, mouseY, delta); - - matrices.translate(0, 0, -400); - Tesselator tesselator = Tesselator.getInstance(); - BufferBuilder bufferBuilder = tesselator.getBuilder(); - RenderSystem.setShader(GameRenderer::getPositionColorShader); - bufferBuilder.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_COLOR); - Matrix4f matrix4f = matrices.last().pose(); - fillGradient(matrix4f, bufferBuilder, tX - 3, tY - 4, tX + tWidth + 3, tY - 3, 400, -267386864, -267386864); - fillGradient(matrix4f, bufferBuilder, tX - 3, tY + tHeight + 3, tX + tWidth + 3, tY + tHeight + 4, 400, -267386864, -267386864); - fillGradient(matrix4f, bufferBuilder, tX - 3, tY - 3, tX + tWidth + 3, tY + tHeight + 3, 400, -267386864, -267386864); - fillGradient(matrix4f, bufferBuilder, tX - 4, tY - 3, tX - 3, tY + tHeight + 3, 400, -267386864, -267386864); - fillGradient(matrix4f, bufferBuilder, tX + tWidth + 3, tY - 3, tX + tWidth + 4, tY + tHeight + 3, 400, -267386864, -267386864); - fillGradient(matrix4f, bufferBuilder, tX - 3, tY - 3 + 1, tX - 3 + 1, tY + tHeight + 3 - 1, 400, 1347420415, 1344798847); - fillGradient(matrix4f, bufferBuilder, tX + tWidth + 2, tY - 3 + 1, tX + tWidth + 3, tY + tHeight + 3 - 1, 400, 1347420415, 1344798847); - fillGradient(matrix4f, bufferBuilder, tX - 3, tY - 3, tX + tWidth + 3, tY - 3 + 1, 400, 1347420415, 1347420415); - fillGradient(matrix4f, bufferBuilder, tX - 3, tY + tHeight + 2, tX + tWidth + 3, tY + tHeight + 3, 400, 1344798847, 1344798847); - RenderSystem.enableDepthTest(); - RenderSystem.disableTexture(); - RenderSystem.enableBlend(); - RenderSystem.defaultBlendFunc(); - bufferBuilder.end(); - BufferUploader.end(bufferBuilder); - RenderSystem.disableBlend(); - RenderSystem.enableTexture(); - - matrices.translate(0, 0, 400); - - for (int i = 0; i < components.size(); i++) { - Minecraft.getInstance().font.draw(matrices, components.get(i), tX + 2, tY + 2, -1); - tY += 10 + (i == 0 ? 2 : 0); - } - - matrices.popPose(); - }), bounds); - } - - private static void fillGradient(Matrix4f pose, BufferBuilder builder, int x1, int y1, int x2, int y2, int blitOffset, int color1, int color2) { - float f = (float) (color1 >> 24 & 0xFF) / 255.0F; - float g = (float) (color1 >> 16 & 0xFF) / 255.0F; - float h = (float) (color1 >> 8 & 0xFF) / 255.0F; - float i = (float) (color1 & 0xFF) / 255.0F; - float j = (float) (color2 >> 24 & 0xFF) / 255.0F; - float k = (float) (color2 >> 16 & 0xFF) / 255.0F; - float l = (float) (color2 >> 8 & 0xFF) / 255.0F; - float m = (float) (color2 & 0xFF) / 255.0F; - builder.vertex(pose, (float) x2, (float) y1, (float) blitOffset).color(g, h, i, f).endVertex(); - builder.vertex(pose, (float) x1, (float) y1, (float) blitOffset).color(g, h, i, f).endVertex(); - builder.vertex(pose, (float) x1, (float) y2, (float) blitOffset).color(k, l, m, j).endVertex(); - builder.vertex(pose, (float) x2, (float) y2, (float) blitOffset).color(k, l, m, j).endVertex(); - } -} diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/options/preview/TooltipPreviewer.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/options/preview/TooltipPreviewer.java new file mode 100644 index 000000000..9b2e86b1b --- /dev/null +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/options/preview/TooltipPreviewer.java @@ -0,0 +1,130 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020, 2021, 2022, 2023 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.config.options.preview; + +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.*; +import com.mojang.math.Matrix4f; +import me.shedaniel.math.Rectangle; +import me.shedaniel.rei.api.client.config.ConfigObject; +import me.shedaniel.rei.api.client.gui.widgets.Tooltip; +import me.shedaniel.rei.api.client.gui.widgets.WidgetWithBounds; +import me.shedaniel.rei.api.client.gui.widgets.Widgets; +import me.shedaniel.rei.api.common.entry.EntryStack; +import me.shedaniel.rei.api.common.util.EntryStacks; +import me.shedaniel.rei.impl.client.gui.config.ConfigAccess; +import me.shedaniel.rei.impl.client.gui.config.options.AllREIConfigOptions; +import net.minecraft.ChatFormatting; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.GameRenderer; +import net.minecraft.client.resources.language.I18n; +import net.minecraft.network.chat.TextComponent; +import net.minecraft.network.chat.TranslatableComponent; +import net.minecraft.util.FormattedCharSequence; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Items; + +import javax.annotation.Nullable; +import java.util.ArrayList; +import java.util.List; +import java.util.function.IntSupplier; +import java.util.stream.Stream; + +public class TooltipPreviewer { + public static WidgetWithBounds create(ConfigAccess access, int width, @Nullable IntSupplier height) { + Rectangle bounds = new Rectangle(); + return Widgets.withBounds(Widgets.createDrawableWidget((helper, matrices, mouseX, mouseY, delta) -> { + EntryStack stack = EntryStacks.of(Items.OAK_PLANKS); + boolean appendModNames = access.get(AllREIConfigOptions.APPEND_MOD_NAMES); + boolean appendFavorites = access.get(AllREIConfigOptions.APPEND_FAVORITES_HINT); + List entries = new ArrayList<>(); + entries.add(Tooltip.entry(new TranslatableComponent("block.minecraft.oak_planks"))); + if (appendModNames) { + entries.add(Tooltip.entry(new TextComponent("Minecraft").withStyle(ChatFormatting.BLUE, ChatFormatting.ITALIC))); + } + if (appendFavorites) { + String name = ConfigObject.getInstance().getFavoriteKeyCode().getLocalizedName().getString(); + entries.addAll(Stream.of(I18n.get("text.rei.favorites_tooltip", name).split("\n")) + .map(TextComponent::new).map(Tooltip::entry).toList()); + } + List components = entries.stream().flatMap(entry -> Minecraft.getInstance().font.split(entry.getAsText(), width - 12 - 4).stream()).toList(); + int minWidth = components.stream().mapToInt(component -> Minecraft.getInstance().font.width(component)).max().orElse(0) + 4; + int minHeight = components.stream().mapToInt(component -> components.get(0) == component && components.size() >= 2 ? 2 + 10 : 10).sum() + 4; + + int tX = Math.max(6, (width - minWidth) / 2), tWidth = Math.min(width - 12, minWidth), tY = 24 + 4, tHeight = Math.min(minHeight, height == null ? 100000 : height.getAsInt() - tY - 4); + matrices.pushPose(); + matrices.translate(0, height == null ? 4 : Math.max(0, (height.getAsInt() - (tY + tHeight)) / 2), 400); + bounds.setSize(width, height == null ? tY + tHeight + 12 : height.getAsInt()); + stack.getRenderer().render(stack, matrices, new Rectangle(width / 2 - 12, 0, 24, 24), mouseX, mouseY, delta); + + matrices.translate(0, 0, -400); + Tesselator tesselator = Tesselator.getInstance(); + BufferBuilder bufferBuilder = tesselator.getBuilder(); + RenderSystem.setShader(GameRenderer::getPositionColorShader); + bufferBuilder.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_COLOR); + Matrix4f matrix4f = matrices.last().pose(); + fillGradient(matrix4f, bufferBuilder, tX - 3, tY - 4, tX + tWidth + 3, tY - 3, 400, -267386864, -267386864); + fillGradient(matrix4f, bufferBuilder, tX - 3, tY + tHeight + 3, tX + tWidth + 3, tY + tHeight + 4, 400, -267386864, -267386864); + fillGradient(matrix4f, bufferBuilder, tX - 3, tY - 3, tX + tWidth + 3, tY + tHeight + 3, 400, -267386864, -267386864); + fillGradient(matrix4f, bufferBuilder, tX - 4, tY - 3, tX - 3, tY + tHeight + 3, 400, -267386864, -267386864); + fillGradient(matrix4f, bufferBuilder, tX + tWidth + 3, tY - 3, tX + tWidth + 4, tY + tHeight + 3, 400, -267386864, -267386864); + fillGradient(matrix4f, bufferBuilder, tX - 3, tY - 3 + 1, tX - 3 + 1, tY + tHeight + 3 - 1, 400, 1347420415, 1344798847); + fillGradient(matrix4f, bufferBuilder, tX + tWidth + 2, tY - 3 + 1, tX + tWidth + 3, tY + tHeight + 3 - 1, 400, 1347420415, 1344798847); + fillGradient(matrix4f, bufferBuilder, tX - 3, tY - 3, tX + tWidth + 3, tY - 3 + 1, 400, 1347420415, 1347420415); + fillGradient(matrix4f, bufferBuilder, tX - 3, tY + tHeight + 2, tX + tWidth + 3, tY + tHeight + 3, 400, 1344798847, 1344798847); + RenderSystem.enableDepthTest(); + RenderSystem.disableTexture(); + RenderSystem.enableBlend(); + RenderSystem.defaultBlendFunc(); + bufferBuilder.end(); + BufferUploader.end(bufferBuilder); + RenderSystem.disableBlend(); + RenderSystem.enableTexture(); + + matrices.translate(0, 0, 400); + + for (int i = 0; i < components.size(); i++) { + Minecraft.getInstance().font.draw(matrices, components.get(i), tX + 2, tY + 2, -1); + tY += 10 + (i == 0 ? 2 : 0); + } + + matrices.popPose(); + }), bounds); + } + + private static void fillGradient(Matrix4f pose, BufferBuilder builder, int x1, int y1, int x2, int y2, int blitOffset, int color1, int color2) { + float f = (float) (color1 >> 24 & 0xFF) / 255.0F; + float g = (float) (color1 >> 16 & 0xFF) / 255.0F; + float h = (float) (color1 >> 8 & 0xFF) / 255.0F; + float i = (float) (color1 & 0xFF) / 255.0F; + float j = (float) (color2 >> 24 & 0xFF) / 255.0F; + float k = (float) (color2 >> 16 & 0xFF) / 255.0F; + float l = (float) (color2 >> 8 & 0xFF) / 255.0F; + float m = (float) (color2 & 0xFF) / 255.0F; + builder.vertex(pose, (float) x2, (float) y1, (float) blitOffset).color(g, h, i, f).endVertex(); + builder.vertex(pose, (float) x1, (float) y1, (float) blitOffset).color(g, h, i, f).endVertex(); + builder.vertex(pose, (float) x1, (float) y2, (float) blitOffset).color(k, l, m, j).endVertex(); + builder.vertex(pose, (float) x2, (float) y2, (float) blitOffset).color(k, l, m, j).endVertex(); + } +} diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/EntryWidget.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/EntryWidget.java index 3f4b9e769..2c6b31874 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/EntryWidget.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/EntryWidget.java @@ -402,10 +402,15 @@ public class EntryWidget extends Slot implements DraggableStackProviderWidget { return isHighlightEnabled(); } - private final NumberAnimator darkBackgroundAlpha = ValueAnimator.ofFloat() + private NumberAnimator darkBackgroundAlpha = ValueAnimator.ofFloat() .withConvention(() -> REIRuntime.getInstance().isDarkThemeEnabled() ? 1.0F : 0.0F, ValueAnimator.typicalTransitionTime()) .asFloat(); + @ApiStatus.Internal + public void setDarkBackgroundAlpha(NumberAnimator darkBackgroundAlpha) { + this.darkBackgroundAlpha = darkBackgroundAlpha; + } + protected void drawBackground(PoseStack matrices, int mouseX, int mouseY, float delta) { if (background) { darkBackgroundAlpha.update(delta); diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/TabContainerWidget.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/TabContainerWidget.java index 1498e70c7..9103e1130 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/TabContainerWidget.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/TabContainerWidget.java @@ -97,42 +97,17 @@ public class TabContainerWidget extends GuiComponent { } if (categories.size() > tabsPerPage) { - Button tabLeft, tabRight; - this.widgets.add(tabLeft = Widgets.createButton(new Rectangle(bounds.x, bounds.getMaxY() - tabSize + 1 - tabButtonsSize, tabButtonsSize, tabButtonsSize), Component.empty()) - .onClick(button -> { - int currentCategoryPage = selectedCategory.getAsInt() / tabsPerPage(); - currentCategoryPage = Math.floorMod(currentCategoryPage - 1, categories.size() / tabsPerPage() + 1); - selectedCategory.accept(Mth.clamp(currentCategoryPage * tabsPerPage() + tabsPerPage() / 2, - tabsPerPage() / 2, categories.size() - (int) Math.ceil(tabsPerPage() / 2.0))); - }) - .tooltipLine(Component.translatable("text.rei.previous_page"))); - this.widgets.add(tabRight = Widgets.createButton(new Rectangle(bounds.x + bounds.width - tabButtonsSize - (isCompactTabButtons ? 0 : 1), bounds.getMaxY() - tabSize + 1 - tabButtonsSize, tabButtonsSize, tabButtonsSize), Component.empty()) - .onClick(button -> { - int currentCategoryPage = selectedCategory.getAsInt() / tabsPerPage(); - currentCategoryPage = Math.floorMod(currentCategoryPage + 1, categories.size() / tabsPerPage() + 1); - selectedCategory.accept(Mth.clamp(currentCategoryPage * tabsPerPage() + tabsPerPage() / 2, - tabsPerPage() / 2, categories.size() - (int) Math.ceil(tabsPerPage() / 2.0))); - }) - .tooltipLine(Component.translatable("text.rei.next_page"))); - - this.widgets.add(Widgets.withTranslate(Widgets.createDrawableWidget((helper, matrices, mouseX, mouseY, delta) -> { - Rectangle tabLeftBounds = tabLeft.getBounds(); - Rectangle tabRightBounds = tabRight.getBounds(); - if (isCompactTabButtons) { - matrices.pushPose(); - matrices.translate(0, 0.5, 0); - RenderSystem.setShaderTexture(0, InternalTextures.ARROW_LEFT_SMALL_TEXTURE); - blit(matrices, tabLeftBounds.x + 2, tabLeftBounds.y + 2, 0, 0, 6, 6, 6, 6); - RenderSystem.setShaderTexture(0, InternalTextures.ARROW_RIGHT_SMALL_TEXTURE); - blit(matrices, tabRightBounds.x + 2, tabRightBounds.y + 2, 0, 0, 6, 6, 6, 6); - matrices.popPose(); - } else { - RenderSystem.setShaderTexture(0, InternalTextures.ARROW_LEFT_TEXTURE); - blit(matrices, tabLeftBounds.x + 4, tabLeftBounds.y + 4, 0, 0, 8, 8, 8, 8); - RenderSystem.setShaderTexture(0, InternalTextures.ARROW_RIGHT_TEXTURE); - blit(matrices, tabRightBounds.x + 4, tabRightBounds.y + 4, 0, 0, 8, 8, 8, 8); - } - }), 0, 0, 1)); + this.widgets.addAll(getCategoryButtons(bounds, isCompactTabButtons, tabSize, tabButtonsSize, () -> { + int currentCategoryPage = selectedCategory.getAsInt() / tabsPerPage(); + currentCategoryPage = Math.floorMod(currentCategoryPage - 1, categories.size() / tabsPerPage() + 1); + selectedCategory.accept(Mth.clamp(currentCategoryPage * tabsPerPage() + tabsPerPage() / 2, + tabsPerPage() / 2, categories.size() - (int) Math.ceil(tabsPerPage() / 2.0))); + }, () -> { + int currentCategoryPage = selectedCategory.getAsInt() / tabsPerPage(); + currentCategoryPage = Math.floo