diff options
| author | shedaniel <daniel@shedaniel.me> | 2023-10-22 22:32:24 +0800 |
|---|---|---|
| committer | shedaniel <daniel@shedaniel.me> | 2024-04-16 00:38:18 +0900 |
| commit | 03fc341975d5bfe4d09b56fe2523ddc91d702b2a (patch) | |
| tree | c1038c5e7b147c891225acdae81fc2e6a3d0489f | |
| parent | 51d84c0f80e6a459b933add343fc07e9e36a8a7f (diff) | |
| download | RoughlyEnoughItems-03fc341975d5bfe4d09b56fe2523ddc91d702b2a.tar.gz RoughlyEnoughItems-03fc341975d5bfe4d09b56fe2523ddc91d702b2a.tar.bz2 RoughlyEnoughItems-03fc341975d5bfe4d09b56fe2523ddc91d702b2a.zip | |
Implement some of the config ui
18 files changed, 523 insertions, 20 deletions
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 3705e4aeb..f8262de4c 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 @@ -28,26 +28,37 @@ import com.mojang.blaze3d.vertex.PoseStack; import dev.architectury.utils.value.IntValue; import me.shedaniel.math.Point; import me.shedaniel.math.Rectangle; +import me.shedaniel.rei.api.client.gui.widgets.Widget; import me.shedaniel.rei.api.client.gui.widgets.Widgets; +import me.shedaniel.rei.impl.client.config.ConfigManagerImpl; +import me.shedaniel.rei.impl.client.config.ConfigObjectImpl; import me.shedaniel.rei.impl.client.gui.config.components.ConfigCategoriesListWidget; +import me.shedaniel.rei.impl.client.gui.config.components.ConfigEntriesListWidget; import me.shedaniel.rei.impl.client.gui.config.options.AllREIConfigCategories; +import me.shedaniel.rei.impl.client.gui.config.options.CompositeOption; import me.shedaniel.rei.impl.client.gui.config.options.OptionCategory; +import me.shedaniel.rei.impl.client.gui.config.options.OptionGroup; import me.shedaniel.rei.impl.client.gui.credits.CreditsScreen; -import me.shedaniel.rei.impl.client.gui.widget.HoleWidget; +import me.shedaniel.rei.impl.client.gui.modules.Menu; import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.components.Widget; import net.minecraft.client.gui.components.events.GuiEventListener; import net.minecraft.client.gui.screens.Screen; import net.minecraft.network.chat.TranslatableComponent; +import org.jetbrains.annotations.Nullable; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; public class REIConfigScreen extends Screen { private final Screen parent; private final List<OptionCategory> categories; private final List<Widget> widgets = new ArrayList<>(); + private final Map<CompositeOption<?>, ?> options = new HashMap<>(); private OptionCategory activeCategory; + @Nullable + private Menu menu; public REIConfigScreen(Screen parent) { this(parent, AllREIConfigCategories.CATEGORIES); @@ -59,6 +70,15 @@ public class REIConfigScreen extends Screen { this.categories = categories; Preconditions.checkArgument(!categories.isEmpty(), "Categories cannot be empty!"); this.activeCategory = categories.get(0); + + ConfigObjectImpl config = ConfigManagerImpl.getInstance().getConfig(); + for (OptionCategory category : categories) { + for (OptionGroup group : category.getGroups()) { + for (CompositeOption<?> option : group.getOptions()) { + ((Map<CompositeOption<?>, Object>) this.options).put(option, option.getBind().apply(config)); + } + } + } } @Override @@ -71,10 +91,12 @@ public class REIConfigScreen extends Screen { })); this.widgets.add(Widgets.createLabel(new Point(width / 2, 12), this.title)); int sideWidth = (int) (width / 3.8); + Widget[] list = {ConfigEntriesListWidget.create(new Rectangle(12 + sideWidth, 32, width - 20 - sideWidth, height - 32 - 32), activeCategory.getGroups())}; this.widgets.add(ConfigCategoriesListWidget.create(new Rectangle(8, 32, sideWidth, height - 32 - 32), categories, new IntValue() { @Override public void accept(int i) { REIConfigScreen.this.activeCategory = categories.get(i); + list[0] = ConfigEntriesListWidget.create(new Rectangle(12 + sideWidth, 32, width - 20 - sideWidth, height - 32 - 32), activeCategory.getGroups()); } @Override @@ -82,7 +104,11 @@ public class REIConfigScreen extends Screen { return categories.indexOf(activeCategory); } })); - this.widgets.add(HoleWidget.create(new Rectangle(12 + sideWidth, 32, width - 20 - sideWidth, height - 32 - 32), () -> 0, 32)); + this.widgets.add(Widgets.delegate(() -> list[0])); + } + + public Map<CompositeOption<?>, ?> getOptions() { + return options; } @Override @@ -106,6 +132,8 @@ public class REIConfigScreen extends Screen { @Override public boolean charTyped(char character, int modifiers) { + if (menu != null && menu.charTyped(character, modifiers)) + return true; for (GuiEventListener listener : children()) if (listener.charTyped(character, modifiers)) return true; @@ -114,6 +142,8 @@ public class REIConfigScreen extends Screen { @Override public boolean mouseDragged(double mouseX, double mouseY, int button, double deltaX, double deltaY) { + if (menu != null && menu.mouseDragged(mouseX, mouseY, button, deltaX, deltaY)) + return true; for (GuiEventListener entry : children()) if (entry.mouseDragged(mouseX, mouseY, button, deltaX, deltaY)) return true; @@ -121,7 +151,16 @@ public class REIConfigScreen extends Screen { } @Override + public boolean mouseClicked(double mouseX, double mouseY, int button) { + if (menu != null && menu.mouseClicked(mouseX, mouseY, button)) + return true; + return super.mouseClicked(mouseX, mouseY, button); + } + + @Override public boolean mouseReleased(double mouseX, double mouseY, int button) { + if (menu != null && menu.mouseReleased(mouseX, mouseY, button)) + return true; for (GuiEventListener entry : children()) if (entry.mouseReleased(mouseX, mouseY, button)) return true; @@ -130,9 +169,21 @@ public class REIConfigScreen extends Screen { @Override public boolean mouseScrolled(double mouseX, double mouseY, double amount) { + if (menu != null && menu.mouseScrolled(mouseX, mouseY, amount)) + return true; for (GuiEventListener listener : children()) if (listener.mouseScrolled(mouseX, mouseY, amount)) return true; return super.mouseScrolled(mouseX, mouseY, amount); } + + public void openMenu(Menu menu) { + this.menu = menu; + this.widgets.add(menu); + } + + public void closeMenu() { + this.widgets.remove(menu); + this.menu = null; + } } diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/components/ConfigCategoriesListWidget.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/components/ConfigCategoriesListWidget.java index e56e04f5f..cfacac0ac 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/components/ConfigCategoriesListWidget.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/components/ConfigCategoriesListWidget.java @@ -24,7 +24,6 @@ package me.shedaniel.rei.impl.client.gui.config.components; import dev.architectury.utils.value.IntValue; -import me.shedaniel.clothconfig2.api.scroll.ScrollingContainer; import me.shedaniel.math.Rectangle; import me.shedaniel.rei.api.client.gui.widgets.Widget; import me.shedaniel.rei.api.client.gui.widgets.WidgetWithBounds; diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/components/ConfigCategoryEntryWidget.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/components/ConfigCategoryEntryWidget.java index 177c0104d..190d90cf2 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/components/ConfigCategoryEntryWidget.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/components/ConfigCategoryEntryWidget.java @@ -34,7 +34,7 @@ import net.minecraft.client.gui.Font; public class ConfigCategoryEntryWidget { public static WidgetWithBounds create(OptionCategory category) { - Label label = Widgets.createLabel(new Point(21, 7), category.getName().copy().withStyle(style -> style.withColor(0xFFD0D0D0))) + Label label = Widgets.createLabel(new Point(21, 7), category.getName().copy().withStyle(style -> style.withColor(0xFFC0C0C0))) .leftAligned(); Font font = Minecraft.getInstance().font; Rectangle bounds = new Rectangle(0, 0, label.getBounds().getMaxX(), 7 * 3); 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 new file mode 100644 index 000000000..6f580d3a3 --- /dev/null +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/components/ConfigEntriesListWidget.java @@ -0,0 +1,44 @@ +/* + * 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.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.options.OptionGroup; +import me.shedaniel.rei.impl.client.gui.widget.ListWidget; +import me.shedaniel.rei.impl.client.gui.widget.ScrollableViewWidget; +import me.shedaniel.rei.impl.common.util.RectangleUtils; + +import java.util.List; + +public class ConfigEntriesListWidget { + public static Widget create(Rectangle bounds, List<OptionGroup> groups) { + WidgetWithBounds list = ListWidget.builderOf(RectangleUtils.inset(bounds, 6, 6), groups, + (index, entry) -> ConfigGroupWidget.create(entry, bounds.width - 12 - 6)) + .gap(7) + .build(); + return ScrollableViewWidget.create(bounds, list.withPadding(0, 5), true); + } +} 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 new file mode 100644 index 000000000..76d41e4f1 --- /dev/null +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/components/ConfigGroupWidget.java @@ -0,0 +1,67 @@ +/* + * 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.components; + +import me.shedaniel.math.Point; +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.impl.client.gui.config.options.CompositeOption; +import me.shedaniel.rei.impl.client.gui.config.options.OptionGroup; +import net.minecraft.client.gui.GuiComponent; + +import java.util.ArrayList; +import java.util.List; + +public class ConfigGroupWidget { + public static WidgetWithBounds create(OptionGroup entry, int width) { + List<Widget> widgets = new ArrayList<>(); + int height = 0; + WidgetWithBounds groupTitle = Widgets.createLabel(new Point(0, 3), entry.getGroupName().copy().withStyle(style -> style.withColor(0xFFC0C0C0).withUnderlined(true))) + .leftAligned(); + groupTitle = groupTitle.withPadding(0, 0, 0, 6); + widgets.add(groupTitle); + height = Math.max(height, groupTitle.getBounds().getMaxY()); + + for (CompositeOption<?> option : entry.getOptions()) { + WidgetWithBounds widget = ConfigOptionWidget.create(option, width); + widgets.add(Widgets.withTranslate(widget, 0, height, 0)); + height = Math.max(height, height + widget.getBounds().getMaxY()); + + if (entry.getOptions().get(entry.getOptions().size() - 1) != option) { + int y = height; + widgets.add(Widgets.createDrawableWidget((helper, matrices, mouseX, mouseY, delta) -> { + for (int x = 0; x <= width; x += 4) { + GuiComponent.fill(matrices, x, y + 1, x + 2, y + 2, 0xFF757575); + } + })); + height += 7; + } + } + + Rectangle bounds = new Rectangle(0, 0, width, height); + return Widgets.concatWithBounds(bounds, widgets); + } +} 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 new file mode 100644 index 000000000..bfa7d66b7 --- /dev/null +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/components/ConfigOptionValueWidget.java @@ -0,0 +1,94 @@ +/* + * 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.components; + +import com.mojang.math.Matrix4f; +import me.shedaniel.math.Point; +import me.shedaniel.math.Rectangle; +import me.shedaniel.rei.api.client.gui.widgets.Label; +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.REIConfigScreen; +import me.shedaniel.rei.impl.client.gui.config.options.CompositeOption; +import me.shedaniel.rei.impl.client.gui.config.options.OptionValueEntry; +import me.shedaniel.rei.impl.client.gui.modules.Menu; +import me.shedaniel.rei.impl.client.gui.modules.entries.ToggleMenuEntry; +import net.minecraft.client.Minecraft; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceLocation; + +import java.util.Map; + +import static me.shedaniel.rei.impl.client.gui.config.options.ConfigUtils.literal; + +public class ConfigOptionValueWidget { + public static <T> WidgetWithBounds create(CompositeOption<T> option) { + Map<CompositeOption<?>, ?> options = ((REIConfigScreen) Minecraft.getInstance().screen).getOptions(); + OptionValueEntry<T> entry = option.getEntry(); + T value = (T) options.get(option); + Component text; + + if (entry instanceof OptionValueEntry.Selection<T> selection) { + text = selection.getOption(value); + } else { + text = literal(value.toString()); + } + + Label label = Widgets.createLabel(new Point(), text).rightAligned() + .color(0xFFE0E0E0) + .hoveredColor(0xFFE0E0E0); + Matrix4f[] matrix = {new Matrix4f()}; + + if (entry instanceof OptionValueEntry.Selection<T> selection) { + int noOfOptions = selection.getOptions().size(); + if (noOfOptions == 2) { + label.clickable().onClick($ -> { + ((Map<CompositeOption<?>, Object>) options).put(option, selection.getOptions().get((selection.getOptions().indexOf((T) options.get(option)) + 1) % 2)); + label.setMessage(selection.getOption((T) options.get(option))); + }); + } else if (noOfOptions >= 2) { + label.clickable().onClick($ -> { + Menu menu = new Menu(MatrixUtils.transform(matrix[0], label.getBounds()), CollectionUtils.map(selection.getOptions(), + opt -> ToggleMenuEntry.of(selection.getOption(opt), () -> false, o -> { + ((REIConfigScreen) Minecraft.getInstance().screen).closeMenu(); + ((Map<CompositeOption<?>, Object>) options).put(option, opt); + label.setMessage(selection.getOption(opt)); + }) + .withActive(() -> true)), false); + ((REIConfigScreen) Minecraft.getInstance().screen).closeMenu(); + ((REIConfigScreen) Minecraft.getInstance().screen).openMenu(menu); + }); + } + } + + return Widgets.concatWithBounds(() -> new Rectangle(-label.getBounds().width, 0, label.getBounds().width + 8, 14), + label, + Widgets.createDrawableWidget((helper, matrices, mouseX, mouseY, delta) -> matrix[0] = matrices.last().pose()), + Widgets.withTranslate(Widgets.createTexturedWidget(new ResourceLocation("roughlyenoughitems:textures/gui/config/selector.png"), + new Rectangle(1, 1, 4, 6), 0, 0, 1, 1, 1, 1), 0, 0.5, 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 new file mode 100644 index 000000000..9707b3ab7 --- /dev/null +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/components/ConfigOptionWidget.java @@ -0,0 +1,105 @@ +/* + * 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.components; + +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.math.Matrix4f; +import me.shedaniel.math.Point; +import me.shedaniel.math.Rectangle; +import me.shedaniel.rei.api.client.gui.widgets.Label; +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.impl.client.gui.config.options.CompositeOption; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.components.events.GuiEventListener; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.util.FormattedCharSequence; + +import java.util.ArrayList; +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) { + List<Widget> widgets = new ArrayList<>(); + 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); + 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)); + final List<FormattedCharSequence> split = Minecraft.getInstance().font.split(description, width); + final boolean hasPreview = option.hasPreview(); + final Label preview = Widgets.createLabel(new Point(), translatable("config.rei.texts.preview")) + .color(0xFFA5F4FF) + .hoveredColor(0xFFD1FAFF) + .noShadow() + .clickable() + .rightAligned(); + boolean nextLinePreview = false; + + { + height[0] += 12 * split.size(); + if (hasPreview) { + int lastWidth = Minecraft.getInstance().font.width(split.get(split.size() - 1)); + if (lastWidth + preview.getBounds().width + 10 > width) { + nextLinePreview = true; + height[0] += 12; + } + } + } + + @Override + public Rectangle getBounds() { + return new Rectangle(0, 12, width, 12 + 12 * split.size()); + } + + @Override + public void render(PoseStack poses, int mouseX, int mouseY, float delta) { + for (int i = 0; i < split.size(); i++) { + Minecraft.getInstance().font.draw(poses, split.get(i), 0, 12 + 12 * i, -1); + } + + if (hasPreview) { + if (nextLinePreview) { + this.preview.setPoint(new Point(width, 12 + 12 * split.size())); + } else { + this.preview.setPoint(new Point(width, 12 + 12 * split.size() - 12)); + } + + this.preview.render(poses, mouseX, mouseY, delta); + } + } + + @Override + public List<? extends GuiEventListener> children() { + return List.of(preview); + } + }); + return Widgets.concatWithBounds(new Rectangle(0, 0, width, height[0]), widgets); + } +} 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 706d41200..58827c465 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 @@ -25,6 +25,7 @@ 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.options.preview.ThemePreviewer; import java.util.function.BiConsumer; import java.util.function.Function; @@ -35,11 +36,12 @@ interface AllREIConfigOptions { static <T> CompositeOption<T> make(String id, Function<ConfigObjectImpl, T> bind, BiConsumer<ConfigObjectImpl, T> save) { return new CompositeOption<>(translatable("config.rei.options." + id), - translatable("config.rei.options." + id + ".desc"), bind); + translatable("config.rei.options." + id + ".desc"), bind, save); } CompositeOption<AppearanceTheme> THEME = make("appearance.theme", i -> i.appearance.theme, (i, v) -> i.appearance.theme = v) - .enumOptions(); + .enumOptions() + .previewer(ThemePreviewer.INSTANCE); CompositeOption<RecipeBorderType> RECIPE_BORDER = make("appearance.recipe_border", i -> i.appearance.recipeBorder, (i, v) -> i.appearance.recipeBorder = v) .enumOptions(); CompositeOption<Boolean> REDUCED_MOTION = make("appearance.reduced_motion", i -> i.basics.reduceMotion, (i, v) -> i.basics.reduceMotion = v) @@ -53,7 +55,7 @@ interface AllREIConfigOptions { // TODO: NATIVE KEYBINDS CompositeOption<Boolean> USE_NATIVE_KEYBINDS = make("keybinds.use_native_keybinds", i -> i.basics.keyBindings.useNativeKeybinds, (i, v) -> i.basics.keyBindings.useNativeKeybinds = v) .enabledDisabled(); - CompositeOption<CheatingMode> CHEATS_MODE = make("cheats.cheats", i -> i.basics.cheating, (i, v) -> i.basics.cheating = v) + CompositeOption<CheatingMode> CHEATS_MODE = make("cheats.mode", i -> i.basics.cheating, (i, v) -> i.basics.cheating = v) .enumOptions(); CompositeOption<ItemCheatingStyle> CHEATS_METHOD = make("cheats.method", i -> i.basics.cheatingStyle, (i, v) -> i.basics.cheatingStyle = v) .enumOptions(); diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/options/CompositeOption.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/options/CompositeOption.java index 7d7eb46af..11f9126db 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/options/CompositeOption.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/options/CompositeOption.java @@ -25,19 +25,25 @@ package me.shedaniel.rei.impl.client.gui.config.options; import me.shedaniel.rei.impl.client.config.ConfigObjectImpl; import net.minecraft.network.chat.Component; +import org.jetbrains.annotations.Nullable; +import java.util.function.BiConsumer; import java.util.function.Function; public class CompositeOption<T> { private final Component name; private final Component description; private final Function<ConfigObjectImpl, T> bind; + private final BiConsumer<ConfigObjectImpl, T> save; + @Nullable + private ConfigPreviewer<T> previewer; private OptionValueEntry<T> entry; - public CompositeOption(Component name, Component description, Function<ConfigObjectImpl, T> bind) { + public CompositeOption(Component name, Component description, Function<ConfigObjectImpl, T> bind, BiConsumer<ConfigObjectImpl, T> save) { this.name = name; this.description = description; this.bind = bind; + this.save = save; } public CompositeOption<T> entry(OptionValueEntry<T> entry) { @@ -60,4 +66,38 @@ public class CompositeOption<T> { public CompositeOption<T> enumOptions(T... entry) { return this.entry(OptionValueEntry.enumOptions(entry)); } + + public CompositeOption<T> previewer(ConfigPreviewer<T> previewer) { + this.previewer = previewer; + return this; + } + + public Component getName() { + return name; + } + + public Component getDescription() { + return description; + } + + public Function<ConfigObjectImpl, T> getBind() { + return bind; + } + + public BiConsumer<ConfigObjectImpl, T> getSave() { + return save; + } + + public OptionValueEntry<T> getEntry() { + return entry; + } + + @Nullable + public ConfigPreviewer<T> getPreviewer() { + return previewer; + } + + public boolean hasPreview() { + return previewer != null; + } } diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/options/ConfigPreviewer.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/options/ConfigPreviewer.java new file mode 100644 index 000000000..0dfd5cba0 --- /dev/null +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/options/ConfigPreviewer.java @@ -0,0 +1,32 @@ |
