From bb8153f1404056be167b1f06e0c9951aca6c83f2 Mon Sep 17 00:00:00 2001 From: zelophed Date: Tue, 13 Apr 2021 23:54:26 +0200 Subject: [PATCH] texting numbers --- .../config/ui/BaseConfigScreen.java | 4 +- .../foundation/config/ui/ConfigButton.java | 8 + .../foundation/config/ui/ConfigScreen.java | 4 +- .../config/ui/ConfigScreenList.java | 56 ++++- .../config/ui/SubMenuConfigScreen.java | 12 +- .../config/ui/entries/BooleanEntry.java | 13 +- .../config/ui/entries/NumberEntry.java | 197 ++++++++++++++++++ .../config/ui/entries/SubMenuEntry.java | 10 +- .../config/ui/entries/ValueEntry.java | 21 +- .../foundation/gui/TextStencilElement.java | 24 --- 10 files changed, 300 insertions(+), 49 deletions(-) create mode 100644 src/main/java/com/simibubi/create/foundation/config/ui/entries/NumberEntry.java diff --git a/src/main/java/com/simibubi/create/foundation/config/ui/BaseConfigScreen.java b/src/main/java/com/simibubi/create/foundation/config/ui/BaseConfigScreen.java index b2e9a3edd..0e5f61c4a 100644 --- a/src/main/java/com/simibubi/create/foundation/config/ui/BaseConfigScreen.java +++ b/src/main/java/com/simibubi/create/foundation/config/ui/BaseConfigScreen.java @@ -35,7 +35,7 @@ public class BaseConfigScreen extends ConfigScreen { .withCallback(() -> ScreenOpener.transitionTo(new SubMenuConfigScreen(this, AllConfigs.CLIENT.specification))) ); - StencilElement text2 = new TextStencilElement(client.fontRenderer, new StringTextComponent("COMMON CONFIG").formatted(TextFormatting.BOLD)).centered(false, true).at(0, 11, 0); + StencilElement text2 = new TextStencilElement(client.fontRenderer, new StringTextComponent("COMMON CONFIG").formatted(TextFormatting.BOLD)).centered(true, true); widgets.add(commonConfigWidget = ConfigButton.createFromStencilElement( width / 2 - 100, height / 2 - 15, @@ -46,7 +46,7 @@ public class BaseConfigScreen extends ConfigScreen { commonConfigWidget.active = false; commonConfigWidget.updateColorsFromState(); - StencilElement text3 = new TextStencilElement.Centered(client.fontRenderer, new StringTextComponent("SERVER CONFIG").formatted(TextFormatting.BOLD), 200).at(0, 11, 0); + StencilElement text3 = new TextStencilElement(client.fontRenderer, new StringTextComponent("SERVER CONFIG").formatted(TextFormatting.BOLD)).centered(true, true); widgets.add(serverConfigWidget = ConfigButton.createFromStencilElement( width / 2 - 100, height / 2 - 15 + 50, diff --git a/src/main/java/com/simibubi/create/foundation/config/ui/ConfigButton.java b/src/main/java/com/simibubi/create/foundation/config/ui/ConfigButton.java index 4017283d7..7b776bce7 100644 --- a/src/main/java/com/simibubi/create/foundation/config/ui/ConfigButton.java +++ b/src/main/java/com/simibubi/create/foundation/config/ui/ConfigButton.java @@ -104,6 +104,14 @@ public class ConfigButton extends StencilWidget { gradientColor2 = Palette.getColorForButtonState(false, active, hovered); } + public void animateGradientFromState() { + startGradientAnimation( + Palette.getColorForButtonState(true, active, hovered), + Palette.getColorForButtonState(false, active, hovered), + true + ); + } + private void startGradientAnimation(int c1, int c2, boolean positive, double expSpeed) { colorAnimation.startWithValue(positive ? 1 : -1); colorAnimation.chase(0, expSpeed, LerpedFloat.Chaser.EXP); diff --git a/src/main/java/com/simibubi/create/foundation/config/ui/ConfigScreen.java b/src/main/java/com/simibubi/create/foundation/config/ui/ConfigScreen.java index 95a7ea2e8..8f854c63e 100644 --- a/src/main/java/com/simibubi/create/foundation/config/ui/ConfigScreen.java +++ b/src/main/java/com/simibubi/create/foundation/config/ui/ConfigScreen.java @@ -110,8 +110,8 @@ public abstract class ConfigScreen extends NavigatableSimiScreen { protected void renderWindow(MatrixStack ms, int mouseX, int mouseY, float partialTicks) { int x = (int) (width * 0.5f); int y = (int) (height * 0.5f); - this.drawHorizontalLine(ms, x-25, x+25, y, 0xff_807060); - this.drawVerticalLine(ms, x, y-25, y+25, 0xff_90a0b0); + //this.drawHorizontalLine(ms, x-25, x+25, y, 0xff_807060); + //this.drawVerticalLine(ms, x, y-25, y+25, 0xff_90a0b0); //this.testStencil.render(ms); diff --git a/src/main/java/com/simibubi/create/foundation/config/ui/ConfigScreenList.java b/src/main/java/com/simibubi/create/foundation/config/ui/ConfigScreenList.java index b06b70396..9e64a5491 100644 --- a/src/main/java/com/simibubi/create/foundation/config/ui/ConfigScreenList.java +++ b/src/main/java/com/simibubi/create/foundation/config/ui/ConfigScreenList.java @@ -1,12 +1,18 @@ package com.simibubi.create.foundation.config.ui; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + import com.mojang.blaze3d.matrix.MatrixStack; -import com.simibubi.create.foundation.gui.StencilElement; +import com.mojang.blaze3d.systems.RenderSystem; import com.simibubi.create.foundation.gui.TextStencilElement; import com.simibubi.create.foundation.gui.UIRenderHelper; import com.simibubi.create.foundation.gui.widgets.AbstractSimiWidget; +import net.minecraft.client.MainWindow; import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.IGuiEventListener; import net.minecraft.client.gui.widget.list.ExtendedList; import net.minecraft.util.text.IFormattableTextComponent; @@ -17,6 +23,7 @@ public class ConfigScreenList extends ExtendedList { super(client, width, height, top, bottom, elementHeight); func_244605_b(false); func_244606_c(false); + setRenderSelection(false); } @Override @@ -27,6 +34,15 @@ public class ConfigScreenList extends ExtendedList { super.render(ms, mouseX, mouseY, partialTicks); } + @Override + protected void renderList(MatrixStack p_238478_1_, int p_238478_2_, int p_238478_3_, int p_238478_4_, int p_238478_5_, float p_238478_6_) { + MainWindow window = Minecraft.getInstance().getWindow(); + double d0 = window.getGuiScaleFactor(); + RenderSystem.enableScissor((int) (this.left * d0), (int) (window.getFramebufferHeight() - (this.bottom* d0)), (int)(this.width * d0), (int)(this.height * d0)); + super.renderList(p_238478_1_, p_238478_2_, p_238478_3_, p_238478_4_, p_238478_5_, p_238478_6_); + RenderSystem.disableScissor(); + } + @Override public int getRowWidth() { return width-18; @@ -42,10 +58,38 @@ public class ConfigScreenList extends ExtendedList { } public static abstract class Entry extends ExtendedList.AbstractListEntry { + protected List listeners; + + protected Entry() { + listeners = new ArrayList<>(); + } + public void tick() {} + + public List getGuiListeners() { + return listeners; + } + + @Override + public boolean mouseClicked(double x, double y, int button) { + return getGuiListeners().stream().anyMatch(l -> l.mouseClicked(x, y, button)); + } + + @Override + public boolean keyPressed(int code, int keyPressed_2_, int keyPressed_3_) { + return getGuiListeners().stream().anyMatch(l -> l.keyPressed(code, keyPressed_2_, keyPressed_3_)); + } + + @Override + public boolean charTyped(char ch, int code) { + return getGuiListeners().stream().anyMatch(l -> l.charTyped(ch, code)); + } } public static class LabeledEntry extends Entry { + + protected static final float labelWidthMult = 0.4f; + protected TextStencilElement label; public LabeledEntry(String label) { @@ -54,13 +98,17 @@ public class ConfigScreenList extends ExtendedList { @Override public void render(MatrixStack ms, int index, int y, int x, int width, int height, int mouseX, int mouseY, boolean p_230432_9_, float partialTicks) { - UIRenderHelper.streak(ms, 0, x, y+height/2, height, width/2, 0x0); + UIRenderHelper.streak(ms, 0, x, y+height/2, height - 10, width/2, 0x0); IFormattableTextComponent component = label.getComponent(); - if (Minecraft.getInstance().fontRenderer.getWidth(component) > width/2 - 10) { - label.withText(Minecraft.getInstance().fontRenderer.trimToWidth(component, width / 2 - 15).getString() + "..."); + if (Minecraft.getInstance().fontRenderer.getWidth(component) > getLabelWidth(width) - 10) { + label.withText(Minecraft.getInstance().fontRenderer.trimToWidth(component, getLabelWidth(width) - 15).getString() + "..."); } label.at(x + 5, y + height/2 - 4, 0).render(ms); } + + protected static int getLabelWidth(int totalWidth) { + return (int) (totalWidth * labelWidthMult); + } } public static class WrappedEntry extends Entry { diff --git a/src/main/java/com/simibubi/create/foundation/config/ui/SubMenuConfigScreen.java b/src/main/java/com/simibubi/create/foundation/config/ui/SubMenuConfigScreen.java index eb232bf5c..a4c81b70c 100644 --- a/src/main/java/com/simibubi/create/foundation/config/ui/SubMenuConfigScreen.java +++ b/src/main/java/com/simibubi/create/foundation/config/ui/SubMenuConfigScreen.java @@ -11,6 +11,7 @@ import com.electronwill.nightconfig.core.AbstractConfig; import com.electronwill.nightconfig.core.UnmodifiableConfig; import com.mojang.blaze3d.matrix.MatrixStack; import com.simibubi.create.foundation.config.ui.entries.BooleanEntry; +import com.simibubi.create.foundation.config.ui.entries.NumberEntry; import com.simibubi.create.foundation.config.ui.entries.SubMenuEntry; import com.simibubi.create.foundation.gui.ScreenOpener; import com.simibubi.create.foundation.gui.TextStencilElement; @@ -69,12 +70,15 @@ public class SubMenuConfigScreen extends ConfigScreen { if (value instanceof Boolean) { BooleanEntry entry = new BooleanEntry(humanKey, (ForgeConfigSpec.ConfigValue) configValue, valueSpec); list.children().add(entry); + } else if (value instanceof Number) { + NumberEntry entry = NumberEntry.create(value, humanKey, configValue, valueSpec); + if (entry != null) { + list.children().add(entry); + } else { + list.children().add(new ConfigScreenList.LabeledEntry("n-" + o.getClass().getSimpleName() + " " + humanKey + " : " + value)); + } } else { - AbstractSimiWidget widget = createWidgetForValue(configValue, valueSpec, value, s, this); - widget.y = y.getValue(); - //list.children().add(new ConfigScreenList.WrappedEntry(widget)); list.children().add(new ConfigScreenList.LabeledEntry(humanKey + " : " + value)); - //widgets.add(widget); } } diff --git a/src/main/java/com/simibubi/create/foundation/config/ui/entries/BooleanEntry.java b/src/main/java/com/simibubi/create/foundation/config/ui/entries/BooleanEntry.java index 94f702df2..f1426be76 100644 --- a/src/main/java/com/simibubi/create/foundation/config/ui/entries/BooleanEntry.java +++ b/src/main/java/com/simibubi/create/foundation/config/ui/entries/BooleanEntry.java @@ -31,11 +31,15 @@ public class BooleanEntry extends ValueEntry { .withCallback(() -> { value.set(!value.get()); buttonStencil.withSecond(value.get() ? enabled : disabled); + onValueChange(); }); buttonStencil = ((CombinedStencilElement) button.getStencilElement()) .withMode(CombinedStencilElement.ElementMode.BOTH) .withSecond(value.get() ? enabled : disabled); + + listeners.add(button); + onReset(); } @Override @@ -48,18 +52,19 @@ public class BooleanEntry extends ValueEntry { public void render(MatrixStack ms, int index, int y, int x, int width, int height, int mouseX, int mouseY, boolean p_230432_9_, float partialTicks) { super.render(ms, index, y, x, width, height, mouseX, mouseY, p_230432_9_, partialTicks); - button.x = x + width/2; + button.x = x + getLabelWidth(width); button.y = y; - button.withBounds(width/2 - 34, height).render(ms, mouseX, mouseY, partialTicks); + button.withBounds(width - getLabelWidth(width) - resetWidth, height).render(ms, mouseX, mouseY, partialTicks); } @Override protected void onReset() { + super.onReset(); buttonStencil.withSecond(value.get() ? enabled : disabled); } - @Override + /*@Override public boolean mouseClicked(double mX, double mY, int button) { return this.button.mouseClicked(mX, mY, button) || super.mouseClicked(mX, mY, button); - } + }*/ } diff --git a/src/main/java/com/simibubi/create/foundation/config/ui/entries/NumberEntry.java b/src/main/java/com/simibubi/create/foundation/config/ui/entries/NumberEntry.java new file mode 100644 index 000000000..8569a1a10 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/config/ui/entries/NumberEntry.java @@ -0,0 +1,197 @@ +package com.simibubi.create.foundation.config.ui.entries; + +import java.lang.reflect.Field; +import java.util.function.Function; + +import javax.annotation.Nullable; + +import com.mojang.blaze3d.matrix.MatrixStack; +import com.simibubi.create.foundation.gui.TextStencilElement; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.client.gui.widget.TextFieldWidget; +import net.minecraft.util.text.StringTextComponent; +import net.minecraftforge.common.ForgeConfigSpec; + +public abstract class NumberEntry extends ValueEntry { + + protected int minOffset = 0, maxOffset = 0; + protected TextStencilElement minText = null, maxText = null; + + @Nullable + public static NumberEntry create(Object type, String label, ForgeConfigSpec.ConfigValue value, ForgeConfigSpec.ValueSpec spec) { + if (type instanceof Integer) { + return new IntegerEntry(label, (ForgeConfigSpec.ConfigValue) value, spec); + } else if (type instanceof Float) { + return new FloatEntry(label, (ForgeConfigSpec.ConfigValue) value, spec); + } else if (type instanceof Double) { + return new DoubleEntry(label, (ForgeConfigSpec.ConfigValue) value, spec); + } + + return null; + } + + protected TextFieldWidget textField; + + public NumberEntry(String label, ForgeConfigSpec.ConfigValue value, ForgeConfigSpec.ValueSpec spec) { + super(label, value, spec); + textField = new TextFieldWidget(Minecraft.getInstance().fontRenderer, 0, 0, 200, 30, StringTextComponent.EMPTY); + textField.setText(String.valueOf(value.get())); + + Object range = spec.getRange(); + try { + Field minField = range.getClass().getDeclaredField("min"); + Field maxField = range.getClass().getDeclaredField("max"); + minField.setAccessible(true); + maxField.setAccessible(true); + T min = (T) minField.get(range); + T max = (T) maxField.get(range); + + FontRenderer font = Minecraft.getInstance().fontRenderer; + if (!min.equals(getTypeMin())) { + StringTextComponent t = new StringTextComponent(formatBound(min) + " < "); + minText = new TextStencilElement(font, t).centered(true, false); + minOffset = font.getWidth(t); + } + if (!max.equals(getTypeMax())) { + StringTextComponent t = new StringTextComponent(" < " + formatBound(max)); + maxText = new TextStencilElement(font, t).centered(true, false); + maxOffset = font.getWidth(t); + } + } catch (NoSuchFieldException | IllegalAccessException | ClassCastException e) { + e.printStackTrace(); + } + + textField.setResponder(s -> { + try { + T number = getParser().apply(s); + if (!spec.test(number)) + throw new IllegalArgumentException(); + + textField.setTextColor(0xff_20cc20); + value.set(number); + onValueChange(); + + } catch (IllegalArgumentException ignored) { + textField.setTextColor(0xff_cc2020); + } + }); + + listeners.add(textField); + onReset(); + } + + protected String formatBound(T bound) { + String sci = String.format("%.2E", bound); + String str = String.valueOf(bound); + return sci.length() < str.length() ? sci : str; + } + + protected abstract T getTypeMin(); + + protected abstract T getTypeMax(); + + protected abstract Function getParser(); + + @Override + protected void onReset() { + super.onReset(); + textField.setText(String.valueOf(value.get())); + } + + @Override + public void tick() { + super.tick(); + textField.tick(); + } + + @Override + public void render(MatrixStack ms, int index, int y, int x, int width, int height, int mouseX, int mouseY, boolean p_230432_9_, float partialTicks) { + super.render(ms, index, y, x, width, height, mouseX, mouseY, p_230432_9_, partialTicks); + + textField.x = x + getLabelWidth(width) + minOffset; + textField.y = y + 10; + textField.setWidth(width - getLabelWidth(width) - resetWidth - minOffset - maxOffset); + textField.setHeight(30); + textField.render(ms, mouseX, mouseY, partialTicks); + + if (minText != null) + minText + .at(textField.x - minOffset, textField.y, 0) + .withBounds(minOffset, textField.unusedGetHeight()) + .render(ms); + + if (maxText != null) + maxText + .at(textField.x + textField.getWidth(), textField.y, 0) + .withBounds(maxOffset, textField.unusedGetHeight()) + .render(ms); + } + + public static class IntegerEntry extends NumberEntry { + + public IntegerEntry(String label, ForgeConfigSpec.ConfigValue value, ForgeConfigSpec.ValueSpec spec) { + super(label, value, spec); + } + + @Override + protected Integer getTypeMin() { + return Integer.MIN_VALUE; + } + + @Override + protected Integer getTypeMax() { + return Integer.MAX_VALUE; + } + + @Override + protected Function getParser() { + return Integer::parseInt; + } + } + + public static class FloatEntry extends NumberEntry { + + public FloatEntry(String label, ForgeConfigSpec.ConfigValue value, ForgeConfigSpec.ValueSpec spec) { + super(label, value, spec); + } + + @Override + protected Float getTypeMin() { + return Float.MIN_VALUE; + } + + @Override + protected Float getTypeMax() { + return Float.MAX_VALUE; + } + + @Override + protected Function getParser() { + return Float::parseFloat; + } + } + + public static class DoubleEntry extends NumberEntry { + + public DoubleEntry(String label, ForgeConfigSpec.ConfigValue value, ForgeConfigSpec.ValueSpec spec) { + super(label, value, spec); + } + + @Override + protected Double getTypeMin() { + return Double.MIN_VALUE; + } + + @Override + protected Double getTypeMax() { + return Double.MAX_VALUE; + } + + @Override + protected Function getParser() { + return Double::parseDouble; + } + } +} diff --git a/src/main/java/com/simibubi/create/foundation/config/ui/entries/SubMenuEntry.java b/src/main/java/com/simibubi/create/foundation/config/ui/entries/SubMenuEntry.java index 18a75d5d4..28f5762d1 100644 --- a/src/main/java/com/simibubi/create/foundation/config/ui/entries/SubMenuEntry.java +++ b/src/main/java/com/simibubi/create/foundation/config/ui/entries/SubMenuEntry.java @@ -21,6 +21,8 @@ public class SubMenuEntry extends ConfigScreenList.LabeledEntry { TextStencilElement text = new TextStencilElement(Minecraft.getInstance().fontRenderer, "Click to open").centered(true, true); button = ConfigButton.createFromStencilElement(0, 0, text) .withCallback(() -> ScreenOpener.transitionTo(new SubMenuConfigScreen(parent, spec, config))); + + listeners.add(button); } @Override @@ -33,14 +35,14 @@ public class SubMenuEntry extends ConfigScreenList.LabeledEntry { public void render(MatrixStack ms, int index, int y, int x, int width, int height, int mouseX, int mouseY, boolean p_230432_9_, float partialTicks) { super.render(ms, index, y, x, width, height, mouseX, mouseY, p_230432_9_, partialTicks); - button.x = x + width/2; + button.x = x + getLabelWidth(width); button.y = y; - button.withBounds(width/2, height); + button.withBounds(width - getLabelWidth(width), height); button.render(ms, mouseX, mouseY, partialTicks); } - @Override + /*@Override public boolean mouseClicked(double p_231044_1_, double p_231044_3_, int p_231044_5_) { return button.mouseClicked(p_231044_1_, p_231044_3_, p_231044_5_); - } + }*/ } diff --git a/src/main/java/com/simibubi/create/foundation/config/ui/entries/ValueEntry.java b/src/main/java/com/simibubi/create/foundation/config/ui/entries/ValueEntry.java index 7a05ad41c..bde5066dc 100644 --- a/src/main/java/com/simibubi/create/foundation/config/ui/entries/ValueEntry.java +++ b/src/main/java/com/simibubi/create/foundation/config/ui/entries/ValueEntry.java @@ -10,6 +10,8 @@ import net.minecraftforge.common.ForgeConfigSpec; public class ValueEntry extends ConfigScreenList.LabeledEntry { + protected static final int resetWidth = 24;//including 2px offset on each side + protected ForgeConfigSpec.ConfigValue value; protected ForgeConfigSpec.ValueSpec spec; protected ConfigButton reset; @@ -21,11 +23,13 @@ public class ValueEntry extends ConfigScreenList.LabeledEntry { TextStencilElement text = new TextStencilElement(Minecraft.getInstance().fontRenderer, "R").centered(true, true); reset = ConfigButton.createFromStencilElement(0, 0, text) - .withBounds(30, 30) + .withBounds(resetWidth - 4, 20) .withCallback(() -> { value.set((T) spec.getDefault()); this.onReset(); }); + + listeners.add(reset); } @Override @@ -37,15 +41,22 @@ public class ValueEntry extends ConfigScreenList.LabeledEntry { public void render(MatrixStack ms, int index, int y, int x, int width, int height, int mouseX, int mouseY, boolean p_230432_9_, float partialTicks) { super.render(ms, index, y, x, width, height, mouseX, mouseY, p_230432_9_, partialTicks); - reset.x = x + width - 32; - reset.y = y + 10; + reset.x = x + width - resetWidth + 2; + reset.y = y + 15; reset.render(ms, mouseX, mouseY, partialTicks); } - @Override + /*@Override public boolean mouseClicked(double mX, double mY, int button) { return reset.mouseClicked(mX, mY, button); + }*/ + + protected void onReset() { + onValueChange(); } - protected void onReset() {} + protected void onValueChange() { + reset.active = !value.get().equals(spec.getDefault()); + reset.animateGradientFromState(); + } } diff --git a/src/main/java/com/simibubi/create/foundation/gui/TextStencilElement.java b/src/main/java/com/simibubi/create/foundation/gui/TextStencilElement.java index f7f5a556e..3fc0c4e24 100644 --- a/src/main/java/com/simibubi/create/foundation/gui/TextStencilElement.java +++ b/src/main/java/com/simibubi/create/foundation/gui/TextStencilElement.java @@ -77,28 +77,4 @@ public class TextStencilElement extends DelegatedStencilElement { public IFormattableTextComponent getComponent() { return component; } - - public static class Centered extends TextStencilElement { - - public Centered(FontRenderer font, String text, int width) { - super(font, text); - this.width = width; - } - - public Centered(FontRenderer font, IFormattableTextComponent component, int width) { - super(font, component); - this.width = width; - } - - @Override - protected void renderStencil(MatrixStack ms) { - int textWidth = font.getWidth(component); - font.draw(ms, component, width / 2f - textWidth / 2f, 0, 0xff_000000); - } - - @Override - protected void renderElement(MatrixStack ms) { - element.render(ms, width, 10); - } - } }