Просмотр исходного кода

Close #72

Signed-off-by: shedaniel <daniel@shedaniel.me>
shedaniel 4 лет назад
Родитель
Сommit
8ba610c615

+ 14 - 0
common/src/main/java/me/shedaniel/clothconfig2/ClothConfigDemo.java

@@ -26,12 +26,19 @@ import me.shedaniel.clothconfig2.gui.entries.MultiElementListEntry;
 import me.shedaniel.clothconfig2.gui.entries.NestedListListEntry;
 import me.shedaniel.clothconfig2.impl.builders.DropdownMenuBuilder;
 import me.shedaniel.clothconfig2.impl.builders.SubCategoryBuilder;
+import net.fabricmc.loader.api.FabricLoader;
+import net.minecraft.ChatFormatting;
+import net.minecraft.Util;
 import net.minecraft.core.Registry;
+import net.minecraft.network.chat.ClickEvent;
+import net.minecraft.network.chat.HoverEvent;
 import net.minecraft.network.chat.TextComponent;
 import net.minecraft.network.chat.TranslatableComponent;
 import net.minecraft.resources.ResourceLocation;
 import net.minecraft.world.item.Item;
+import net.minecraft.world.item.ItemStack;
 import net.minecraft.world.item.Items;
+import net.minecraft.world.item.enchantment.Enchantments;
 
 import java.util.*;
 import java.util.stream.Collectors;
@@ -147,6 +154,13 @@ public class ClothConfigDemo {
                     }
                 }
         ));
+        testing.addEntry(entryBuilder.startTextDescription(
+                new TranslatableComponent("text.cloth-config.testing.1",
+                        new TextComponent("ClothConfig").withStyle(s -> s.withBold(true).withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_ITEM, new HoverEvent.ItemStackInfo(Util.make(new ItemStack(Items.PINK_WOOL), stack -> stack.setHoverName(new TextComponent("(\u30FB\u2200\u30FB)")).enchant(Enchantments.BLOCK_EFFICIENCY, 10)))))),
+                        new TranslatableComponent("text.cloth-config.testing.2").withStyle(s -> s.withColor(ChatFormatting.BLUE).withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new TextComponent("https://shedaniel.gitbook.io/cloth-config/"))).withClickEvent(new ClickEvent(ClickEvent.Action.OPEN_URL, "https://shedaniel.gitbook.io/cloth-config/"))),
+                        new TranslatableComponent("text.cloth-config.testing.3").withStyle(s -> s.withColor(ChatFormatting.GREEN).withClickEvent(new ClickEvent(ClickEvent.Action.OPEN_FILE, FabricLoader.getInstance().getConfigDir().resolve("modmenu.json").toString())))
+                )
+        ).build());
         builder.transparentBackground();
         return builder;
     }

+ 46 - 0
common/src/main/java/me/shedaniel/clothconfig2/gui/AbstractConfigScreen.java

@@ -28,22 +28,30 @@ import com.mojang.blaze3d.vertex.PoseStack;
 import com.mojang.blaze3d.vertex.Tesselator;
 import com.mojang.math.Matrix4f;
 import it.unimi.dsi.fastutil.booleans.BooleanConsumer;
+import me.shedaniel.clothconfig2.ClothConfigInitializer;
 import me.shedaniel.clothconfig2.api.*;
 import me.shedaniel.clothconfig2.gui.entries.KeyCodeEntry;
 import me.shedaniel.math.Rectangle;
+import net.minecraft.Util;
 import net.minecraft.client.Minecraft;
 import net.minecraft.client.gui.components.AbstractWidget;
 import net.minecraft.client.gui.components.events.GuiEventListener;
+import net.minecraft.client.gui.screens.ConfirmLinkScreen;
 import net.minecraft.client.gui.screens.ConfirmScreen;
 import net.minecraft.client.gui.screens.Screen;
+import net.minecraft.network.chat.ClickEvent;
 import net.minecraft.network.chat.Component;
+import net.minecraft.network.chat.Style;
 import net.minecraft.network.chat.TranslatableComponent;
 import net.minecraft.resources.ResourceLocation;
 import net.minecraft.world.level.block.entity.TickableBlockEntity;
 import org.jetbrains.annotations.ApiStatus;
 import org.jetbrains.annotations.Nullable;
 
+import java.net.URI;
+import java.net.URISyntaxException;
 import java.util.List;
+import java.util.Locale;
 import java.util.Map;
 import java.util.Optional;
 import java.util.function.Consumer;
@@ -402,4 +410,42 @@ public abstract class AbstractConfigScreen extends Screen implements ConfigScree
         buffer.vertex(matrix, rect.getMinX(), rect.getMinY(), 0.0F).uv(rect.getMinX() / 32.0F, rect.getMinY() / 32.0F).color(red, green, blue, startAlpha).endVertex();
         tessellator.end();
     }
+    
+    @Override   // override to expose this protected method to config entries
+    public void renderComponentHoverEffect(PoseStack matrices, Style style, int x, int y) {
+        super.renderComponentHoverEffect(matrices, style, x, y);
+    }
+    
+    @Override
+    public boolean handleComponentClicked(@Nullable Style style) {
+        if (style == null) return false;
+        
+        ClickEvent clickEvent = style.getClickEvent();
+        
+        if (clickEvent != null && clickEvent.getAction() == ClickEvent.Action.OPEN_URL) {
+            try {
+                URI uri = new URI(clickEvent.getValue());
+                String string = uri.getScheme();
+                if (string == null) {
+                    throw new URISyntaxException(clickEvent.getValue(), "Missing protocol");
+                }
+                
+                if (!(string.equalsIgnoreCase("http") || string.equalsIgnoreCase("https"))) {
+                    throw new URISyntaxException(clickEvent.getValue(), "Unsupported protocol: " + string.toLowerCase(Locale.ROOT));
+                }
+                
+                Minecraft.getInstance().setScreen(new ConfirmLinkScreen(openInBrowser -> {
+                    if (openInBrowser) {
+                        Util.getPlatform().openUri(uri);
+                    }
+    
+                    Minecraft.getInstance().setScreen(this);
+                }, clickEvent.getValue(), true));
+            } catch (URISyntaxException e) {
+                ClothConfigInitializer.LOGGER.error("Can't open url for {}", clickEvent, e);
+            }
+            return true;
+        }
+        return super.handleComponentClicked(style);
+    }
 }

+ 60 - 11
common/src/main/java/me/shedaniel/clothconfig2/gui/entries/TextListEntry.java

@@ -20,13 +20,18 @@
 package me.shedaniel.clothconfig2.gui.entries;
 
 import com.mojang.blaze3d.vertex.PoseStack;
+import me.shedaniel.clothconfig2.gui.AbstractConfigScreen;
 import net.fabricmc.api.EnvType;
 import net.fabricmc.api.Environment;
 import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.Font;
 import net.minecraft.client.gui.components.events.GuiEventListener;
 import net.minecraft.network.chat.Component;
+import net.minecraft.network.chat.Style;
 import net.minecraft.util.FormattedCharSequence;
+import net.minecraft.util.Mth;
 import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.Nullable;
 
 import java.util.Collections;
 import java.util.List;
@@ -35,10 +40,14 @@ import java.util.function.Supplier;
 
 @Environment(EnvType.CLIENT)
 public class TextListEntry extends TooltipListEntry<Object> {
-    
-    private int savedWidth = -1;
+    public static final int LINE_HEIGHT = 12;
+    private final Font textRenderer = Minecraft.getInstance().font;
     private final int color;
     private final Component text;
+    private int savedWidth = -1;
+    private int savedX = -1;
+    private int savedY = -1;
+    private List<FormattedCharSequence> wrappedLines;
     
     @ApiStatus.Internal
     @Deprecated
@@ -58,28 +67,68 @@ public class TextListEntry extends TooltipListEntry<Object> {
         super(fieldName, tooltipSupplier);
         this.text = text;
         this.color = color;
+        this.wrappedLines = Collections.emptyList();
     }
     
     @Override
     public void render(PoseStack matrices, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean isHovered, float delta) {
         super.render(matrices, index, y, x, entryWidth, entryHeight, mouseX, mouseY, isHovered, delta);
-        this.savedWidth = entryWidth;
+        if (this.savedWidth != entryWidth || this.savedX != x || this.savedY != y) {
+            this.wrappedLines = this.textRenderer.split(this.text, entryWidth);
+            this.savedWidth = entryWidth;
+            this.savedX = x;
+            this.savedY = y;
+        }
         int yy = y + 4;
-        List<FormattedCharSequence> strings = Minecraft.getInstance().font.split(text, savedWidth);
-        for (FormattedCharSequence string : strings) {
+        for (FormattedCharSequence string : wrappedLines) {
             Minecraft.getInstance().font.drawShadow(matrices, string, x, yy, color);
             yy += Minecraft.getInstance().font.lineHeight + 3;
         }
+    
+        Style style = this.getTextAt(mouseX, mouseY);
+        AbstractConfigScreen configScreen = this.getConfigScreen();
+    
+        if (style != null && configScreen != null) {
+            configScreen.renderComponentHoverEffect(matrices, style, mouseX, mouseY);
+        }
     }
     
     @Override
     public int getItemHeight() {
-        if (savedWidth == -1)
-            return 12;
-        List<FormattedCharSequence> strings = Minecraft.getInstance().font.split(text, savedWidth);
-        if (strings.isEmpty())
-            return 0;
-        return 15 + strings.size() * 12;
+        if (savedWidth == -1) return LINE_HEIGHT;
+        int lineCount = this.wrappedLines.size();
+        return lineCount == 0 ? 0 : 15 + lineCount * LINE_HEIGHT;
+    }
+    
+    @Override
+    public boolean mouseClicked(double mouseX, double mouseY, int button) {
+        if (button == 0) {
+            Style style = this.getTextAt(mouseX, mouseY);
+            AbstractConfigScreen configScreen = this.getConfigScreen();
+            if (configScreen != null && configScreen.handleComponentClicked(style)) {
+                return true;
+            }
+        }
+        
+        return super.mouseClicked(mouseX, mouseY, button);
+    }
+    
+    @Nullable
+    private Style getTextAt(double x, double y) {
+        int lineCount = this.wrappedLines.size();
+        
+        if (lineCount > 0) {
+            int textX = Mth.floor(x - this.savedX);
+            int textY = Mth.floor(y - 4 - this.savedY);
+            if (textX >= 0 && textY >= 0 && textX <= this.savedWidth && textY < LINE_HEIGHT * lineCount + lineCount) {
+                int line = textY / LINE_HEIGHT;
+                if (line < this.wrappedLines.size()) {
+                    FormattedCharSequence orderedText = this.wrappedLines.get(line);
+                    return this.textRenderer.getSplitter().componentStyleAtWidth(orderedText, textX);
+                }
+            }
+        }
+        return null;
     }
     
     @Override

+ 48 - 45
common/src/main/resources/assets/cloth-config2/lang/en_us.json

@@ -1,47 +1,50 @@
 {
-  "text.cloth-config.save_and_done": "Save & Quit",
-  "text.cloth-config.apply": "Apply Changes",
-  "text.cloth-config.quit_config": "Changes Not Saved",
-  "text.cloth-config.quit_config_sure": "Are you sure you want to quit editing the config? Changes will not be saved!",
-  "text.cloth-config.cancel_discard": "Discard Changes",
-  "text.cloth-config.quit_discard": "Quit & Discard Changes",
-  "text.cloth-config.config": "Config",
-  "text.cloth-config.multi_error": "Multiple Issues!",
-  "text.cloth-config.not_editable": "Not Editable!",
-  "text.cloth-config.error.not_valid_number_int": "Not a valid number! (Integer)",
-  "text.cloth-config.error.not_valid_number_long": "Not a valid number! (Long)",
-  "text.cloth-config.error.not_valid_number_float": "Not a valid number! (Float)",
-  "text.cloth-config.error.not_valid_number_double": "Not a valid number! (Double)",
-  "text.cloth-config.error.too_large": "Too Large! (Maximum: %d)",
-  "text.cloth-config.error.too_small": "Too Small! (Minimum: %d)",
-  "text.cloth-config.error.color.no_alpha_allowed": "No Alpha Allowed!",
-  "text.cloth-config.error.color.invalid_alpha": "Not a valid value! (Alpha)",
-  "text.cloth-config.error.color.invalid_red": "Not a valid value! (Red)",
-  "text.cloth-config.error.color.invalid_green": "Not a valid value! (Green)",
-  "text.cloth-config.error.color.invalid_blue": "Not a valid value! (Blue)",
-  "text.cloth-config.error.color.invalid_color": "Not a valid color!",
-  "text.cloth-config.error.color.no_hash": "Not a valid color! (Missing #)",
-  "text.cloth-config.list.add": "Insert New",
-  "text.cloth-config.list.remove": "Delete Selected",
-  "text.cloth-config.error_cannot_save": "Error!",
-  "text.cloth-config.reset_value": "Reset",
-  "text.cloth.reset_value": "Reset",
-  "text.cloth-config.restart_required": "Restart Required",
-  "text.cloth-config.restart_required_sub": "One of your modified settings requires Minecraft to be restarted. Do you want to proceed?",
-  "text.cloth-config.exit_minecraft": "Exit Minecraft",
-  "text.cloth-config.ignore_restart": "Ignore Restart",
-  "text.cloth-config.boolean.value.true": "§aYes",
-  "text.cloth-config.boolean.value.false": "§cNo",
-  "text.cloth-config.dropdown.value.unknown": "§cNo suggestions",
-  "modifier.cloth-config.alt": "Alt + %s",
-  "modifier.cloth-config.ctrl": "Ctrl + %s",
-  "modifier.cloth-config.shift": "Shift + %s",
-  "title.cloth-config.config": "Cloth Mod Config Config",
-  "category.cloth-config.scrolling": "Scrolling",
-  "category.cloth-config.testing": "Config Demo",
-  "option.cloth-config.scrollDuration": "Scroll Duration",
-  "option.cloth-config.scrollStep": "Scroll Step",
-  "option.cloth-config.bounceBackMultiplier": "Bounce Multiplier",
-  "option.cloth-config.setDefaultSmoothScroll": "Set Default Smooth Scroll",
-  "option.cloth-config.disableSmoothScroll": "Disable Smooth Scroll"
+    "text.cloth-config.save_and_done": "Save & Quit",
+    "text.cloth-config.apply": "Apply Changes",
+    "text.cloth-config.quit_config": "Changes Not Saved",
+    "text.cloth-config.quit_config_sure": "Are you sure you want to quit editing the config? Changes will not be saved!",
+    "text.cloth-config.cancel_discard": "Discard Changes",
+    "text.cloth-config.quit_discard": "Quit & Discard Changes",
+    "text.cloth-config.config": "Config",
+    "text.cloth-config.multi_error": "Multiple Issues!",
+    "text.cloth-config.not_editable": "Not Editable!",
+    "text.cloth-config.error.not_valid_number_int": "Not a valid number! (Integer)",
+    "text.cloth-config.error.not_valid_number_long": "Not a valid number! (Long)",
+    "text.cloth-config.error.not_valid_number_float": "Not a valid number! (Float)",
+    "text.cloth-config.error.not_valid_number_double": "Not a valid number! (Double)",
+    "text.cloth-config.error.too_large": "Too Large! (Maximum: %d)",
+    "text.cloth-config.error.too_small": "Too Small! (Minimum: %d)",
+    "text.cloth-config.error.color.no_alpha_allowed": "No Alpha Allowed!",
+    "text.cloth-config.error.color.invalid_alpha": "Not a valid value! (Alpha)",
+    "text.cloth-config.error.color.invalid_red": "Not a valid value! (Red)",
+    "text.cloth-config.error.color.invalid_green": "Not a valid value! (Green)",
+    "text.cloth-config.error.color.invalid_blue": "Not a valid value! (Blue)",
+    "text.cloth-config.error.color.invalid_color": "Not a valid color!",
+    "text.cloth-config.error.color.no_hash": "Not a valid color! (Missing #)",
+    "text.cloth-config.list.add": "Insert New",
+    "text.cloth-config.list.remove": "Delete Selected",
+    "text.cloth-config.error_cannot_save": "Error!",
+    "text.cloth-config.reset_value": "Reset",
+    "text.cloth.reset_value": "Reset",
+    "text.cloth-config.restart_required": "Restart Required",
+    "text.cloth-config.restart_required_sub": "One of your modified settings requires Minecraft to be restarted. Do you want to proceed?",
+    "text.cloth-config.exit_minecraft": "Exit Minecraft",
+    "text.cloth-config.ignore_restart": "Ignore Restart",
+    "text.cloth-config.boolean.value.true": "§aYes",
+    "text.cloth-config.boolean.value.false": "§cNo",
+    "text.cloth-config.dropdown.value.unknown": "§cNo suggestions",
+    "modifier.cloth-config.alt": "Alt + %s",
+    "modifier.cloth-config.ctrl": "Ctrl + %s",
+    "modifier.cloth-config.shift": "Shift + %s",
+    "title.cloth-config.config": "Cloth Mod Config Config",
+    "category.cloth-config.scrolling": "Scrolling",
+    "category.cloth-config.testing": "Config Demo",
+    "option.cloth-config.scrollDuration": "Scroll Duration",
+    "option.cloth-config.scrollStep": "Scroll Step",
+    "option.cloth-config.bounceBackMultiplier": "Bounce Multiplier",
+    "option.cloth-config.setDefaultSmoothScroll": "Set Default Smooth Scroll",
+    "option.cloth-config.disableSmoothScroll": "Disable Smooth Scroll",
+    "text.cloth-config.testing.1": "You are a mod developer and you want to use %1$s? Go on the %2$s to get started. You can also %3$s.",
+    "text.cloth-config.testing.2": "Cloth Config Wiki",
+    "text.cloth-config.testing.3": "click here to open ModMenu's config file for no specific reason"
 }

+ 1 - 1
gradle.properties

@@ -6,7 +6,7 @@ supported_version=1.16.4/5
 
 archives_base_name=cloth-config
 archives_base_name_snapshot=cloth-config-snapshot
-base_version=4.9
+base_version=4.10
 maven_group=me.shedaniel.cloth
 
 jankson_version=1.2.0