From f372a9aace6b09135d0ff409a840b110a6fa18b9 Mon Sep 17 00:00:00 2001 From: Shiewk Date: Mon, 5 Jan 2026 13:37:16 +0100 Subject: [PATCH] Gradient editor - Made all widgets use new GradientWidgetSetting - GradientOptions to store and for rendering - Gradient editor screen to customize - Rainbow preset --- README.md | 13 +- assets/images/color-editor.webp | Bin 0 -> 33520 bytes gradle.properties | 2 +- .../java/de/shiewk/widgets/ModWidget.java | 4 + .../shiewk/widgets/client/WidgetRenderer.java | 6 +- .../client/screen/ContextMenuScreen.java | 10 +- .../screen/EditWidgetPositionsScreen.java | 7 +- .../client/screen/WidgetConfigScreen.java | 2 +- .../client/screen/WidgetSettingsScreen.java | 17 +- .../client/screen/WidgetVisibilityToggle.java | 7 + .../components/WidgetDisplayWidget.java | 55 ++ .../components/WidgetSettingsEditWidget.java | 2 +- .../GradientEditorColorSection.java | 221 ++++++ .../gradienteditor/GradientEditorScreen.java | 200 ++++++ .../GradientEditorSettingsSection.java | 650 ++++++++++++++++++ .../de/shiewk/widgets/color/GradientMode.java | 18 + .../shiewk/widgets/color/GradientOptions.java | 153 +++++ .../shiewk/widgets/color/GradientPreset.java | 29 + .../HorizontalGradientGuiRenderState.java | 102 +++ .../de/shiewk/widgets/utils/WidgetUtils.java | 22 + .../widgets/widgets/ArmorHudWidget.java | 43 +- .../widgets/widgets/BandwidthWidget.java | 11 +- .../widgets/widgets/BasicTextWidget.java | 38 +- .../widgets/widgets/CoordinatesWidget.java | 50 +- .../widgets/widgets/InventoryWidget.java | 76 +- .../widgets/widgets/KeyStrokesWidget.java | 89 +-- .../de/shiewk/widgets/widgets/PingWidget.java | 13 +- .../de/shiewk/widgets/widgets/TPSWidget.java | 13 +- .../settings/GradientWidgetSetting.java | 129 ++++ .../settings/RGBAColorWidgetSetting.java | 12 +- .../widgets/settings/WidgetSettingOption.java | 1 + .../resources/assets/widgets/lang/de_de.json | 28 +- .../resources/assets/widgets/lang/en_us.json | 26 +- .../widgets/textures/gui/arrow_down.png | Bin 0 -> 511 bytes .../widgets/textures/gui/button_plus.png | Bin 0 -> 550 bytes 35 files changed, 1809 insertions(+), 240 deletions(-) create mode 100644 assets/images/color-editor.webp create mode 100644 src/main/java/de/shiewk/widgets/client/screen/WidgetVisibilityToggle.java create mode 100644 src/main/java/de/shiewk/widgets/client/screen/components/WidgetDisplayWidget.java create mode 100644 src/main/java/de/shiewk/widgets/client/screen/gradienteditor/GradientEditorColorSection.java create mode 100644 src/main/java/de/shiewk/widgets/client/screen/gradienteditor/GradientEditorScreen.java create mode 100644 src/main/java/de/shiewk/widgets/client/screen/gradienteditor/GradientEditorSettingsSection.java create mode 100644 src/main/java/de/shiewk/widgets/color/GradientMode.java create mode 100644 src/main/java/de/shiewk/widgets/color/GradientOptions.java create mode 100644 src/main/java/de/shiewk/widgets/color/GradientPreset.java create mode 100644 src/main/java/de/shiewk/widgets/render/state/HorizontalGradientGuiRenderState.java create mode 100644 src/main/java/de/shiewk/widgets/widgets/settings/GradientWidgetSetting.java create mode 100644 src/main/resources/assets/widgets/textures/gui/arrow_down.png create mode 100644 src/main/resources/assets/widgets/textures/gui/button_plus.png diff --git a/README.md b/README.md index 78ab7f1..6ce02d7 100644 --- a/README.md +++ b/README.md @@ -39,4 +39,15 @@ Right-clicking on this screen will bring up a useful context menu with additiona When you're done, just press Escape until you return to the game. -Now, everything is done. Your widgets automatically save for the next time you play. \ No newline at end of file +Now, everything is done. Your widgets automatically save for the next time you play. + +## Color editor + +Newer mod versions (2.3.0+) include a **color editor** which provides full customization for your widgets' background and text colors: + +![Color editor screen](assets/images/color-editor.webp) + +The color list on the left shows the colors which are currently configured; if you add more than one, it becomes a gradient. Clicking on the colors will select them. + +The settings bar on the right of the color list can be used to customize gradient settings, import from other widgets, or use presets. +Below that, the color which is currently selected can be changed or deleted. \ No newline at end of file diff --git a/assets/images/color-editor.webp b/assets/images/color-editor.webp new file mode 100644 index 0000000000000000000000000000000000000000..48df13c938cba48346022217eb96ac983cf5d3ec GIT binary patch literal 33520 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 onEdit; @@ -40,6 +40,11 @@ public class EditWidgetPositionsScreen extends AnimatedScreen { client.setScreen(parent); } + @Override + public boolean shouldRenderWidgets() { + return false; + } + private record AlignResult(double result, boolean isEnd){} private static final int SELECT_COLOR = Color.GREEN.getRGB(), ALIGN_COLOR = Color.ORANGE.getRGB(), ALIGN_DISABLED_COLOR = Color.GRAY.getRGB(); diff --git a/src/main/java/de/shiewk/widgets/client/screen/WidgetConfigScreen.java b/src/main/java/de/shiewk/widgets/client/screen/WidgetConfigScreen.java index 0ff2e8a..59f5c43 100644 --- a/src/main/java/de/shiewk/widgets/client/screen/WidgetConfigScreen.java +++ b/src/main/java/de/shiewk/widgets/client/screen/WidgetConfigScreen.java @@ -38,7 +38,7 @@ public class WidgetConfigScreen extends Screen { public void close() { WidgetManager.saveWidgets(widgetsEdited); for (ModWidget widget : widgetsEdited) { - widget.onSettingsChanged(widget.getSettings()); + widget.onSettingsChanged(); } assert client != null; client.setScreen(parent); diff --git a/src/main/java/de/shiewk/widgets/client/screen/WidgetSettingsScreen.java b/src/main/java/de/shiewk/widgets/client/screen/WidgetSettingsScreen.java index c22327c..07da815 100644 --- a/src/main/java/de/shiewk/widgets/client/screen/WidgetSettingsScreen.java +++ b/src/main/java/de/shiewk/widgets/client/screen/WidgetSettingsScreen.java @@ -12,7 +12,7 @@ import net.minecraft.util.Util; import java.util.function.Consumer; -public class WidgetSettingsScreen extends AnimatedScreen { +public class WidgetSettingsScreen extends AnimatedScreen implements WidgetVisibilityToggle { private static final Text previewText = Text.translatable("widgets.ui.preview"); private final ModWidget widget; private final Runnable onChange; @@ -20,7 +20,7 @@ public class WidgetSettingsScreen extends AnimatedScreen { super(Text.translatable("widgets.ui.widgetSettings", widget.getName()), parent, 500); this.widget = widget; onChange = () -> { - widget.onSettingsChanged(widget.getSettings()); + widget.onSettingsChanged(); changedWidgetConsumer.accept(widget); }; } @@ -60,4 +60,17 @@ public class WidgetSettingsScreen extends AnimatedScreen { widget.tick(); } } + + @Override + public boolean shouldRenderWidgets() { + return false; + } + + public ModWidget getWidget() { + return widget; + } + + public Runnable getOnChange() { + return onChange; + } } diff --git a/src/main/java/de/shiewk/widgets/client/screen/WidgetVisibilityToggle.java b/src/main/java/de/shiewk/widgets/client/screen/WidgetVisibilityToggle.java new file mode 100644 index 0000000..4da1b3e --- /dev/null +++ b/src/main/java/de/shiewk/widgets/client/screen/WidgetVisibilityToggle.java @@ -0,0 +1,7 @@ +package de.shiewk.widgets.client.screen; + +public interface WidgetVisibilityToggle { + + boolean shouldRenderWidgets(); + +} diff --git a/src/main/java/de/shiewk/widgets/client/screen/components/WidgetDisplayWidget.java b/src/main/java/de/shiewk/widgets/client/screen/components/WidgetDisplayWidget.java new file mode 100644 index 0000000..c02d145 --- /dev/null +++ b/src/main/java/de/shiewk/widgets/client/screen/components/WidgetDisplayWidget.java @@ -0,0 +1,55 @@ +package de.shiewk.widgets.client.screen.components; + +import de.shiewk.widgets.ModWidget; +import net.minecraft.client.font.TextRenderer; +import net.minecraft.client.gui.DrawContext; +import net.minecraft.client.gui.screen.narration.NarrationMessageBuilder; +import net.minecraft.client.gui.screen.narration.NarrationPart; +import net.minecraft.client.gui.widget.ClickableWidget; +import net.minecraft.util.Util; + +public class WidgetDisplayWidget extends ClickableWidget { + + protected final ModWidget widget; + protected final TextRenderer textRenderer; + protected final int centerX; + protected final int centerY; + + public WidgetDisplayWidget(ModWidget widget, TextRenderer textRenderer, int centerX, int centerY) { + super(0, 0, (int) widget.scaledWidth(), (int) widget.scaledHeight(), widget.getName()); + this.widget = widget; + this.textRenderer = textRenderer; + this.centerX = centerX; + this.centerY = centerY; + } + + @Override + public int getX() { + return (int) (centerX - (widget.scaledWidth() / 2f)); + } + + @Override + public int getY() { + return (int) (centerY - (widget.scaledHeight() / 2f)); + } + + @Override + public int getWidth() { + return (int) widget.scaledWidth(); + } + + @Override + public int getHeight() { + return (int) widget.scaledHeight(); + } + + @Override + protected void renderWidget(DrawContext context, int mouseX, int mouseY, float deltaTicks) { + widget.render(context, Util.getMeasuringTimeNano(), textRenderer, getX(), getY()); + } + + @Override + protected void appendClickableNarrations(NarrationMessageBuilder builder) { + builder.put(NarrationPart.HINT, widget.getName()); + } +} diff --git a/src/main/java/de/shiewk/widgets/client/screen/components/WidgetSettingsEditWidget.java b/src/main/java/de/shiewk/widgets/client/screen/components/WidgetSettingsEditWidget.java index a194df4..fcd0a81 100644 --- a/src/main/java/de/shiewk/widgets/client/screen/components/WidgetSettingsEditWidget.java +++ b/src/main/java/de/shiewk/widgets/client/screen/components/WidgetSettingsEditWidget.java @@ -31,7 +31,7 @@ public class WidgetSettingsEditWidget extends ScrollableWidget { customSetting.setFocused(false); } setWidth(width); - widget.onSettingsChanged(widget.getSettings()); + widget.onSettingsChanged(); } @Override diff --git a/src/main/java/de/shiewk/widgets/client/screen/gradienteditor/GradientEditorColorSection.java b/src/main/java/de/shiewk/widgets/client/screen/gradienteditor/GradientEditorColorSection.java new file mode 100644 index 0000000..bcc7a9f --- /dev/null +++ b/src/main/java/de/shiewk/widgets/client/screen/gradienteditor/GradientEditorColorSection.java @@ -0,0 +1,221 @@ +package de.shiewk.widgets.client.screen.gradienteditor; + +import de.shiewk.widgets.WidgetsMod; +import de.shiewk.widgets.utils.WidgetUtils; +import it.unimi.dsi.fastutil.ints.IntArrayList; +import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.font.TextRenderer; +import net.minecraft.client.gl.RenderPipelines; +import net.minecraft.client.gui.Click; +import net.minecraft.client.gui.DrawContext; +import net.minecraft.client.gui.Element; +import net.minecraft.client.gui.cursor.StandardCursors; +import net.minecraft.client.gui.widget.AlwaysSelectedEntryListWidget; +import net.minecraft.sound.SoundEvents; +import net.minecraft.text.Text; +import net.minecraft.util.Identifier; +import org.jetbrains.annotations.Nullable; + +import java.util.List; +import java.util.function.IntSupplier; + +import static net.minecraft.text.Text.empty; +import static net.minecraft.text.Text.translatable; + +public class GradientEditorColorSection extends AlwaysSelectedEntryListWidget { + + private final GradientEditorScreen editor; + private static final Identifier TEXTURE_BUTTON_PLUS = Identifier.of(WidgetsMod.MOD_ID, "textures/gui/button_plus.png"), + TEXTURE_ARROW_DOWN = Identifier.of(WidgetsMod.MOD_ID, "textures/gui/arrow_down.png"); + + private final List colorEntries; + + public GradientEditorColorSection(GradientEditorScreen editor, MinecraftClient client, int x, int y, int width, int height, int focusedIndex) { + super(client, width, height, y, 64); + setX(x); + this.editor = editor; + colorEntries = new ObjectArrayList<>(editor.colors.size()); + addEntry(new HeadingEntry(client.textRenderer), 18); + + IntArrayList colors = editor.colors; + for (int i = 0; i < colors.size(); i++) { + int finalI = i; + ColorEntry col = new ColorEntry(() -> colors.getInt(finalI)); + colorEntries.add(col); + addEntry(col); + addEntry(new ArrowDownEntry(), 48); + } + + addEntry(new AddButtonEntry(), 70); + setFocused(colorEntries.get(focusedIndex)); + } + + @Override + public int getRowWidth() { + return 64; + } + + @Override + protected void drawSelectionHighlight(DrawContext context, ListEntry entry, int color) {} + + @Override + protected void drawMenuListBackground(DrawContext context) { + context.fill(getX(), getY(), getX()+getWidth(), getY()+getHeight(), 0x50_00_00_00); + } + + @Override + protected void drawHeaderAndFooterSeparators(DrawContext context) {} + + @Override + protected void drawScrollbar(DrawContext context, int mouseX, int mouseY) {} + + @Override + public void setFocused(@Nullable Element focused) { + if (focused == null) return; + if (focused instanceof ListEntry se && !se.canFocus()) return; + + if (super.getFocused() != focused){ + WidgetUtils.playSound(SoundEvents.BLOCK_COPPER_BULB_TURN_ON); + } + if (focused instanceof ColorEntry color){ + editor.setCurrentColorIndex(colorEntries.indexOf(color)); + } + super.setFocused(focused); + } + + public void focusLast() { + setFocused(colorEntries.getLast()); + } + + public abstract static class ListEntry extends AlwaysSelectedEntryListWidget.Entry { + + public boolean canFocus(){ + return false; + } + + @Override + public Text getNarration() { + return empty(); + } + } + + public static class ColorEntry extends ListEntry { + + private final IntSupplier color; + + public ColorEntry(IntSupplier color) { + this.color = color; + } + + @Override + public void render(DrawContext context, int mouseX, int mouseY, boolean hovered, float deltaTicks) { + int color = this.color.getAsInt(); + int x = this.getX(); + int y = this.getContentY(); + + if (hovered && !isFocused()){ + context.setCursor(StandardCursors.POINTING_HAND); + context.fill(x, y, x+getWidth(), y+getHeight(), 0x30_ff_ff_ff); + } + + int outlineColor; + if (isFocused() || hovered){ + outlineColor = 0xff_ff_ff_00; + } else { + outlineColor = color | 0xff000000; + } + + context.fill(x+1, y+1, x+getWidth()-1, y+getHeight()-1, color); + + // Outline: + context.fill(x+1, y, x+getWidth()-1, y+1, outlineColor); + context.fill(x+1, y+getHeight()-1, x+getWidth()-1, y+getHeight(), outlineColor); + context.fill(x, y+1, x+1, y+getHeight()-1, outlineColor); + context.fill(x+getWidth()-1, y+1, x+getWidth(), y+getHeight()-1, outlineColor); + } + + @Override + public boolean canFocus() { + return true; + } + } + + private static class ArrowDownEntry extends ListEntry { + + @Override + public void render(DrawContext context, int mouseX, int mouseY, boolean hovered, float deltaTicks) { + context.drawTexture( + RenderPipelines.GUI_TEXTURED, + TEXTURE_ARROW_DOWN, + getX() + 16, + getContentY() + 8, + 0, + 0, + 32, + 32, + 32, + 32, + 0xff_8d_8d_8d + ); + } + } + + private static class HeadingEntry extends ListEntry { + + private final TextRenderer textRenderer; + + private HeadingEntry(TextRenderer textRenderer) { + this.textRenderer = textRenderer; + } + + @Override + public void render(DrawContext context, int mouseX, int mouseY, boolean hovered, float deltaTicks) { + Text text = translatable("widgets.ui.gradientEditor.colors"); + + int y = this.getContentY() + 2; + int rowWidth = 64; + + int textWidth = textRenderer.getWidth(text); + int textX = getX() + (rowWidth - textWidth) / 2; + context.drawText(textRenderer, text, textX, y, 0xffffffff, true); + } + } + + private class AddButtonEntry extends ListEntry { + @Override + public void render(DrawContext context, int mouseX, int mouseY, boolean hovered, float deltaTicks) { + context.drawTexture( + RenderPipelines.GUI_TEXTURED, + TEXTURE_BUTTON_PLUS, + getX(), + getContentY(), + 0, + 0, + 64, + 64, + 64, + 64, + hovered ? 0xff_cf_cf_cf : 0xff_8d_8d_8d + ); + if (hovered){ + context.setCursor(StandardCursors.POINTING_HAND); + context.drawTooltip(client.textRenderer, List.of( + translatable("widgets.ui.gradientEditor.colors.add.tooltip.0"), + translatable("widgets.ui.gradientEditor.colors.add.tooltip.1") + ), mouseX, mouseY); + } + } + + @Override + public boolean mouseClicked(Click click, boolean doubled) { + editor.addNewColor(editor.getCurrentColor()); + return true; + } + } + + @Override + public boolean isFocused() { + return true; + } +} diff --git a/src/main/java/de/shiewk/widgets/client/screen/gradienteditor/GradientEditorScreen.java b/src/main/java/de/shiewk/widgets/client/screen/gradienteditor/GradientEditorScreen.java new file mode 100644 index 0000000..0321ed3 --- /dev/null +++ b/src/main/java/de/shiewk/widgets/client/screen/gradienteditor/GradientEditorScreen.java @@ -0,0 +1,200 @@ +package de.shiewk.widgets.client.screen.gradienteditor; + +import de.shiewk.widgets.ModWidget; +import de.shiewk.widgets.client.screen.WidgetVisibilityToggle; +import de.shiewk.widgets.client.screen.components.WidgetDisplayWidget; +import de.shiewk.widgets.color.GradientMode; +import de.shiewk.widgets.color.GradientOptions; +import de.shiewk.widgets.widgets.settings.GradientWidgetSetting; +import it.unimi.dsi.fastutil.ints.IntArrayList; +import net.minecraft.client.gui.DrawContext; +import net.minecraft.client.gui.screen.Screen; +import net.minecraft.text.Text; +import net.minecraft.util.Util; +import org.joml.Matrix3x2fStack; + +import static net.minecraft.text.Text.translatable; + +public class GradientEditorScreen extends Screen implements WidgetVisibilityToggle { + + private static final GradientOptions topBarGradient = new GradientOptions(50, 20, new int[]{0xa0_00_00_00, 0x50_00_00_00}); + + final Screen parent; + final ModWidget widget; + final GradientWidgetSetting setting; + final Runnable onChange; + + GradientMode mode; + final IntArrayList colors; + int gradientSpeed; + int gradientSize; + + int currentColorIndex = 0; + + private GradientEditorColorSection colorSection; + private GradientEditorSettingsSection settingsSection; + + public GradientEditorScreen(Screen parent, ModWidget widget, GradientWidgetSetting setting, Runnable onChange) { + super(translatable("widgets.ui.gradientEditor")); + this.parent = parent; + this.widget = widget; + this.setting = setting; + this.onChange = onChange; + GradientOptions options = setting.getValue(); + this.mode = options.mode(); + this.gradientSpeed = (int) options.gradientSpeed(); + this.gradientSize = (int) options.gradientSize(); + this.colors = IntArrayList.of(options.colors()); + } + + @Override + protected void init() { + super.init(); + reloadComponents(); + } + + private int getTopBarHeight() { + return 8 + this.textRenderer.fontHeight * 2; + } + + @Override + public void render(DrawContext context, int mouseX, int mouseY, float deltaTicks) { + super.render(context, mouseX, mouseY, deltaTicks); + + Matrix3x2fStack matrices = context.getMatrices(); + long timeNanos = Util.getMeasuringTimeNano(); + + // Render top bar + topBarGradient.fillHorizontal(context, timeNanos, 0, 0, this.width, this.getTopBarHeight()); + + Text topBarText = translatable("widgets.ui.gradientEditor"); + int width = textRenderer.getWidth(topBarText); + + matrices.pushMatrix().translate(this.width / 2f - width, 5).scale(2); + context.drawText(textRenderer, topBarText, 0, 0, 0xff_ff_ff_ff, true); + matrices.popMatrix(); + } + + public void reloadComponents(){ + clearChildren(); + + double colorScrollY = 0; + double settingsScrollY = 0; + if (this.colorSection != null){ + colorScrollY = colorSection.getScrollY(); + settingsScrollY = settingsSection.getScrollY(); + } + int topBarHeight = getTopBarHeight(); + + + int colorSectionWidth = 90; + int settingsSectionWidth = 110; + int mainAreaWidth = this.width - colorSectionWidth - settingsSectionWidth; + int mainAreaHeight = this.height - topBarHeight; + + // sidebar + this.colorSection = new GradientEditorColorSection(this, this.client, 0, topBarHeight, colorSectionWidth, mainAreaHeight, this.getCurrentColorIndex()); + this.settingsSection = new GradientEditorSettingsSection(this, this.client, colorSectionWidth, topBarHeight, settingsSectionWidth, mainAreaHeight); + addDrawableChild(this.colorSection); + addDrawableChild(this.settingsSection); + colorSection.setScrollY(colorScrollY); + settingsSection.setScrollY(settingsScrollY); + + // main area + int mainAreaX = colorSectionWidth + settingsSectionWidth; + int mainAreaCenterX = mainAreaX + (mainAreaWidth / 2); + + addDrawable(new WidgetDisplayWidget(this.widget, this.textRenderer, mainAreaCenterX, (mainAreaHeight) / 2 + topBarHeight)); + } + + @Override + public void renderBackground(DrawContext context, int mouseX, int mouseY, float deltaTicks) { + super.renderBackground(context, mouseX, mouseY, deltaTicks); + } + + @Override + public void close() { + refreshSettingValue(); + client.setScreen(parent); + } + + private void refreshSettingValue() { + settingsSection.onUpdatedColor(); + setting.setValue(toGradientOptions()); + widget.onSettingsChanged(); + onChange.run(); + } + + private GradientOptions toGradientOptions() { + return new GradientOptions(this.mode, this.gradientSize, this.gradientSpeed, this.colors.toIntArray()); + } + + @Override + public boolean shouldRenderWidgets() { + return false; + } + + public void addNewColor(int initialColor) { + colors.add(initialColor); + this.reloadComponents(); + this.colorSection.focusLast(); + refreshSettingValue(); + } + + public void setGradientSize(double v) { + this.gradientSize = (int) v; + refreshSettingValue(); + } + + public void setGradientSpeed(double v) { + this.gradientSpeed = (int) v; + refreshSettingValue(); + } + + public int getCurrentColor() { + return colors.getInt(currentColorIndex); + } + + public int getCurrentColorIndex() { + return currentColorIndex; + } + + public void setCurrentColorIndex(int i) { + this.currentColorIndex = i; + if (settingsSection != null) settingsSection.onUpdatedColor(); + } + + public void setCurrentColor(int newColor) { + colors.set(getCurrentColorIndex(), newColor); + refreshSettingValue(); + } + + public void removeCurrentColor() { + colors.removeInt(getCurrentColorIndex()); + setCurrentColorIndex(0); + refreshSettingValue(); + reloadComponents(); + } + + public void cycleMode() { + this.mode = GradientMode.values()[(this.mode.ordinal() + 1) % GradientMode.values().length]; + refreshSettingValue(); + } + + public void swapColors(int[] colors) { + this.colors.clear(); + for (int color : colors) { + this.colors.add(color); + } + setCurrentColorIndex(0); + this.reloadComponents(); + refreshSettingValue(); + } + + public void swap(GradientOptions options) { + setGradientSize(options.gradientSize()); + setGradientSpeed(options.gradientSpeed()); + this.mode = options.mode(); + swapColors(options.colors()); + } +} diff --git a/src/main/java/de/shiewk/widgets/client/screen/gradienteditor/GradientEditorSettingsSection.java b/src/main/java/de/shiewk/widgets/client/screen/gradienteditor/GradientEditorSettingsSection.java new file mode 100644 index 0000000..846ba9d --- /dev/null +++ b/src/main/java/de/shiewk/widgets/client/screen/gradienteditor/GradientEditorSettingsSection.java @@ -0,0 +1,650 @@ +package de.shiewk.widgets.client.screen.gradienteditor; + +import de.shiewk.widgets.WidgetsMod; +import de.shiewk.widgets.client.WidgetManager; +import de.shiewk.widgets.client.screen.ContextMenuScreen; +import de.shiewk.widgets.color.GradientOptions; +import de.shiewk.widgets.color.GradientPreset; +import de.shiewk.widgets.widgets.settings.GradientWidgetSetting; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.gl.RenderPipelines; +import net.minecraft.client.gui.Click; +import net.minecraft.client.gui.DrawContext; +import net.minecraft.client.gui.cursor.StandardCursors; +import net.minecraft.client.gui.screen.Screen; +import net.minecraft.client.gui.tooltip.Tooltip; +import net.minecraft.client.gui.widget.AlwaysSelectedEntryListWidget; +import net.minecraft.client.gui.widget.ButtonWidget; +import net.minecraft.client.gui.widget.SliderWidget; +import net.minecraft.client.gui.widget.TextFieldWidget; +import net.minecraft.client.input.CharInput; +import net.minecraft.client.input.KeyInput; +import net.minecraft.client.texture.NativeImage; +import net.minecraft.client.texture.NativeImageBackedTexture; +import net.minecraft.text.Text; +import net.minecraft.util.Identifier; +import net.minecraft.util.math.MathHelper; +import org.jetbrains.annotations.NotNull; + +import java.awt.*; +import java.util.Arrays; +import java.util.function.IntConsumer; +import java.util.function.IntFunction; + +import static de.shiewk.widgets.utils.WidgetUtils.colorARGBToHexRGBA; +import static net.minecraft.text.Text.empty; +import static net.minecraft.text.Text.translatable; + +public class GradientEditorSettingsSection extends AlwaysSelectedEntryListWidget { + + private final GradientEditorScreen editor; + private final HexValueInputEntry hexInput; + private final ColorPickerHueSliderEntry hueSlider; + + public GradientEditorSettingsSection(GradientEditorScreen editor, MinecraftClient client, int x, int y, int width, int height) { + super(client, width, height, y, 110); + setX(x); + this.editor = editor; + + addEntry(new HeadingEntry(translatable("widgets.ui.gradientEditor.gradientSettings")), 18); + + addEntry(new SliderEntry(1, 100, editor.gradientSize, d -> translatable("widgets.ui.gradientEditor.size", d), editor::setGradientSize), 20); + addEntry(new SliderEntry(0, 100, editor.gradientSpeed, d -> translatable("widgets.ui.gradientEditor.speed", d), editor::setGradientSpeed), 20); + addEntry(new ToggleModeButtonEntry(), 20); + addEntry(new ImportButtonEntry(), 20); + addEntry(new UsePresetButtonEntry(), 20); + + addEntry(new HeadingEntry(translatable("widgets.ui.gradientEditor.editColor")), 18); + + addEntry(new ColorChangerEntry(0), 22); + addEntry(new ColorChangerEntry(1), 22); + addEntry(new ColorChangerEntry(2), 22); + addEntry(new ColorChangerEntry(3), 22); + + addEntry(new HeadingEntry(translatable("widgets.ui.gradientEditor.editColor.orPick")), 18); + + addEntry(new ColorPickerEntry(), getRowWidth()); + addEntry(hueSlider = new ColorPickerHueSliderEntry(), 22); + addEntry(new ColorChangerEntry(3, false), 22); + addEntry(hexInput = new HexValueInputEntry(), 20); + + addEntry(new RemoveColorButtonEntry(), 20); + } + + @Override + public int getRowWidth() { + return 110; + } + + @Override + protected void drawMenuListBackground(DrawContext context) { + context.fill(getX(), getY(), getX()+getWidth(), getY()+getHeight(), 0x20_00_00_00); + } + + @Override protected void drawHeaderAndFooterSeparators(DrawContext context) {} + @Override protected void drawSelectionHighlight(DrawContext context, ListEntry entry, int color) {} + @Override protected void drawScrollbar(DrawContext context, int mouseX, int mouseY) {} + + public abstract static class ListEntry extends Entry { + + @Override + public Text getNarration() { + return empty(); + } + } + + public void onUpdatedColor(){ + hexInput.refreshText(); + hueSlider.refreshHue(); + } + + private float getCurrentHue(){ + float[] hsb = getHsb(); + return hsb[0]; + } + + private float @NotNull [] getHsb() { + int currentRGBA = editor.getCurrentColor(); + return Color.RGBtoHSB((currentRGBA >> 16) & 0xff, (currentRGBA >> 8) & 0xff, currentRGBA & 0xff, null); + } + + + private class HeadingEntry extends ListEntry { + + private final Text text; + + private HeadingEntry(Text text) { + this.text = text; + } + + @Override + public void render(DrawContext context, int mouseX, int mouseY, boolean hovered, float deltaTicks) { + int y = this.getContentY() + 2; + int rowWidth = 110; + + int textWidth = client.textRenderer.getWidth(text); + int textX = getX() + (rowWidth - textWidth) / 2; + context.drawText(client.textRenderer, text, textX, y, 0xffffffff, true); + } + } + + private class SliderEntry extends ListEntry { + + private final SliderWidget slider; + + private SliderEntry(int min, int max, int initial, IntFunction textGetter, IntConsumer onUpdateValue) { + double value = (double) (initial - min) / (max - min); + slider = new Slider(textGetter, value, onUpdateValue, min, max); + } + + @Override + public void render(DrawContext context, int mouseX, int mouseY, boolean hovered, float deltaTicks) { + slider.active = editor.colors.size() > 1; + slider.setDimensionsAndPosition(getContentWidth(), getContentHeight(), getContentX(), getContentY()); + slider.render(context, mouseX, mouseY, deltaTicks); + if (hovered && !slider.active) { + context.setCursor(StandardCursors.NOT_ALLOWED); + slider.setTooltip(Tooltip.of(translatable("widgets.ui.gradientEditor.gradientSettings.addMoreColors"))); + } else { + slider.setTooltip(null); + } + } + + @Override public boolean mouseClicked(Click click, boolean doubled) { return slider.mouseClicked(click, doubled); } + @Override public boolean mouseDragged(Click click, double offsetX, double offsetY) { return slider.mouseDragged(click, offsetX, offsetY); } + @Override public boolean mouseReleased(Click click) { return slider.mouseReleased(click); } + @Override public boolean mouseScrolled(double mouseX, double mouseY, double horizontalAmount, double verticalAmount) { return slider.mouseScrolled(mouseX, mouseY, horizontalAmount, verticalAmount); } + @Override public void mouseMoved(double mouseX, double mouseY) { slider.mouseMoved(mouseX, mouseY); } + + private static class Slider extends SliderWidget { + + private final IntFunction textGetter; + private final IntConsumer onUpdateValue; + private final int min; + private final int max; + + public Slider(IntFunction textGetter, double value, IntConsumer onUpdateValue, int min, int max) { + super(0, 0, 0, 0, empty(), value); + this.textGetter = textGetter; + this.onUpdateValue = onUpdateValue; + this.min = min; + this.max = max; + this.updateMessage(); + } + + @Override + protected void updateMessage() { + this.setMessage(textGetter.apply(getTranslatedValue())); + } + + @Override + protected void applyValue() { + onUpdateValue.accept(getTranslatedValue()); + } + + private int getTranslatedValue() { + return (int) (min + (this.value * (max - min))); + } + + } + } + + private class ToggleModeButtonEntry extends ListEntry { + + private final ButtonWidget button = new ButtonWidget.Builder(empty(), this::press).build(); + + public ToggleModeButtonEntry() { + refreshButtonValues(); + } + + private void press(ButtonWidget button) { + editor.cycleMode(); + refreshButtonValues(); + } + + private void refreshButtonValues() { + button.setMessage(translatable("widgets.ui.gradientEditor.mode", editor.mode.name)); + if (editor.colors.size() > 1){ + button.setTooltip(Tooltip.of(editor.mode.description)); + } else { + button.setTooltip(Tooltip.of(translatable("widgets.ui.gradientEditor.gradientSettings.addMoreColors"))); + } + } + + @Override + public void render(DrawContext context, int mouseX, int mouseY, boolean hovered, float deltaTicks) { + button.active = editor.colors.size() > 1; + button.setDimensionsAndPosition(getContentWidth(), getContentHeight(), getContentX(), getContentY()); + button.render(context, mouseX, mouseY, deltaTicks); + } + + @Override + public boolean mouseClicked(Click click, boolean doubled) { + return button.mouseClicked(click, doubled); + } + } + + private class ImportButtonEntry extends ListEntry { + + private final ButtonWidget button = new ButtonWidget.Builder(translatable("widgets.ui.gradientEditor.importOther"), this::press).build(); + + private void press(ButtonWidget button) { + Screen currentScreen = client.currentScreen; + int menuX = (int) client.mouse.getScaledX(client.getWindow()); + int menuY = (int) client.mouse.getScaledY(client.getWindow()); + client.setScreen(new ContextMenuScreen( + button.getMessage(), + currentScreen, + menuX, menuY, + WidgetManager.getAllWidgets() + .stream() + .map(widget -> new ContextMenuScreen.Option( + widget.getName(), + () -> client.setScreen(new ContextMenuScreen( + widget.getName(), + currentScreen, + menuX, + menuY, + widget.getSettings().getCustomSettings() + .stream() + .filter(o -> o instanceof GradientWidgetSetting) + .map(option -> new ContextMenuScreen.Option( + option.getName(), + () -> editor.swap(((GradientWidgetSetting) option).getValue()) + )).toList() + )) + )).toList() + )); + } + + @Override + public void render(DrawContext context, int mouseX, int mouseY, boolean hovered, float deltaTicks) { + button.setDimensionsAndPosition(getContentWidth(), getContentHeight(), getContentX(), getContentY()); + button.render(context, mouseX, mouseY, deltaTicks); + } + + @Override + public boolean mouseClicked(Click click, boolean doubled) { + return button.mouseClicked(click, doubled); + } + } + + private class UsePresetButtonEntry extends ListEntry { + + private final ButtonWidget button = new ButtonWidget.Builder(translatable("widgets.ui.gradientEditor.usePreset"), this::press).build(); + + private void press(ButtonWidget button) { + Screen currentScreen = client.currentScreen; + int menuX = (int) client.mouse.getScaledX(client.getWindow()); + int menuY = (int) client.mouse.getScaledY(client.getWindow()); + client.setScreen(new ContextMenuScreen( + translatable("widgets.ui.gradientEditor.usePreset"), + currentScreen, + menuX, menuY, + Arrays.stream(GradientPreset.presets).map(preset -> new ContextMenuScreen.Option( + preset.name(), + () -> editor.swap(preset.gradient()) + )).toList() + )); + } + + @Override + public void render(DrawContext context, int mouseX, int mouseY, boolean hovered, float deltaTicks) { + button.setDimensionsAndPosition(getContentWidth(), getContentHeight(), getContentX(), getContentY()); + button.render(context, mouseX, mouseY, deltaTicks); + } + + @Override + public boolean mouseClicked(Click click, boolean doubled) { + return button.mouseClicked(click, doubled); + } + + } + + private class ColorChangerEntry extends ListEntry { + + private final int component; + private final boolean showLabel; + + public ColorChangerEntry(int component) { + this(component, true); + } + + public ColorChangerEntry(int component, boolean showLabel) { + this.component = component; + this.showLabel = showLabel; + } + + @Override + public void render(DrawContext context, int mouseX, int mouseY, boolean hovered, float deltaTicks) { + double sliderProg = getComponentValue() / 255d; + + GradientOptions bg = new GradientOptions(100, 0, new int[]{getBackgroundStartColor(), getBackgroundEndColor()}); + int contentY = getContentY(); + int contentWidth = getContentWidth(); + int contentX = getContentX(); + int contentHeight = getContentHeight(); + + bg.fillHorizontal(context, 0, contentX, contentY + 1, contentX + contentWidth, contentY + contentHeight - 1); + + context.drawVerticalLine((int) (contentX + (contentWidth * sliderProg)), contentY - 1, contentY + contentHeight, 0xff_ff_ff_ff); + if (showLabel){ + String label = getLabelWithValue(); + int w = client.textRenderer.getWidth(label); + context.drawText(client.textRenderer, label, contentX + (contentWidth - w) / 2, contentY + 5, 0xffffffff, true); + } + if (hovered){ + context.setCursor(StandardCursors.RESIZE_EW); + } + } + + private int getComponentValue() { + int currentColor = editor.getCurrentColor(); + return switch (component) { + case 0 -> (currentColor & 0x00_ff_00_00) >>> 16; + case 1 -> (currentColor & 0x00_00_ff_00) >>> 8; + case 2 -> (currentColor & 0x00_00_00_ff); + case 3 -> (currentColor & 0xff_00_00_00) >>> 24; + default -> throw new IllegalStateException(); + }; + } + + @Override + public boolean mouseDragged(Click click, double offsetX, double offsetY) { + double mouseX = click.x(); + int newComponentValue = (int) ((mouseX - getContentX()) / getContentWidth() * 255); + setComponentValue(newComponentValue); + return true; + } + + @Override + public boolean mouseClicked(Click click, boolean doubled) { + return mouseDragged(click, 0, 0); + } + + @Override + public boolean keyPressed(KeyInput input) { + if (input.isLeft()) { + setComponentValue(getComponentValue() - 1); + } else if (input.isRight()) { + setComponentValue(getComponentValue() + 1); + } + return true; + } + + private void setComponentValue(int val) { + val = MathHelper.clamp(val, 0, 255); + final int currentColor = editor.getCurrentColor(); + int newColor = switch (component){ + case 0 -> (currentColor & 0xff_00_ff_ff) | val << 16; + case 1 -> (currentColor & 0xff_ff_00_ff) | val << 8; + case 2 -> (currentColor & 0xff_ff_ff_00) | val; + case 3 -> (currentColor & 0x00_ff_ff_ff) | val << 24; + default -> throw new IllegalStateException(); + }; + editor.setCurrentColor(newColor); + } + + private String getLabelWithValue() { + return switch (component){ + case 0 -> "R: " + getComponentValue(); + case 1 -> "G: " + getComponentValue(); + case 2 -> "B: " + getComponentValue(); + case 3 -> "A: " + getComponentValue(); + default -> throw new IllegalStateException(); + }; + } + + private int getBackgroundEndColor() { + final int currentColor = editor.getCurrentColor(); + return switch (component){ + case 0 -> currentColor | 0x00_ff_00_00; + case 1 -> currentColor | 0x00_00_ff_00; + case 2 -> currentColor | 0x00_00_00_ff; + case 3 -> currentColor | 0xff_00_00_00; + default -> throw new IllegalStateException(); + }; + } + + private int getBackgroundStartColor() { + final int currentColor = editor.getCurrentColor(); + return switch (component){ + case 0 -> currentColor & 0xff_00_ff_ff; + case 1 -> currentColor & 0xff_ff_00_ff; + case 2 -> currentColor & 0xff_ff_ff_00; + case 3 -> currentColor & 0x00_ff_ff_ff; + default -> throw new IllegalStateException(); + }; + } + } + + private class RemoveColorButtonEntry extends ListEntry { + + private final ButtonWidget button = new ButtonWidget.Builder(translatable("widgets.ui.gradientEditor.removeColor"), this::press).build(); + + private void press(ButtonWidget button) { + button.active = false; + editor.removeCurrentColor(); + } + + @Override + public void render(DrawContext context, int mouseX, int mouseY, boolean hovered, float deltaTicks) { + button.active = editor.colors.size() > 1; + button.setDimensionsAndPosition(getContentWidth(), getContentHeight(), getContentX(), getContentY()); + button.render(context, mouseX, mouseY, deltaTicks); + } + + @Override + public boolean mouseClicked(Click click, boolean doubled) { + return button.mouseClicked(click, doubled); + } + } + + private class HexValueInputEntry extends ListEntry { + + private final TextFieldWidget inputField = new TextFieldWidget(client.textRenderer, 0, 0, empty()); + + public HexValueInputEntry() { + this.refreshText(); + inputField.setMaxLength(9); + } + + private void onChangeInputField(String s) { + boolean valid = false; + if (s.startsWith("#")) s = s.substring(1); + if (s.length() == 6) { + s += "ff"; + } + if (s.length() == 8) { + try { + String alpha = s.substring(6, 8); + String rgb = s.substring(0, 6); + String argbHex = alpha + rgb; + + int cl = Integer.parseUnsignedInt(argbHex, 16); + + if (cl != editor.getCurrentColor()) { + editor.setCurrentColor(cl); + } + valid = true; + } catch (NumberFormatException ignored) {} + } + + inputField.setEditableColor(valid ? 0xffffffff : 0xffff0000); + } + + @Override + public void render(DrawContext context, int mouseX, int mouseY, boolean hovered, float deltaTicks) { + inputField.setDimensionsAndPosition(getContentWidth(), getContentHeight(), getContentX(), getContentY()); + inputField.render(context, mouseX, mouseY, deltaTicks); + } + + public void refreshText(){ + inputField.setChangedListener(null); + inputField.setText('#' + colorARGBToHexRGBA(editor.getCurrentColor())); + inputField.setCursorToStart(false); + inputField.setEditableColor(0xffffffff); + inputField.setChangedListener(this::onChangeInputField); + } + + @Override + public void setFocused(boolean focused) { + inputField.setFocused(focused); + } + + @Override public boolean mouseClicked(Click click, boolean doubled) { return inputField.mouseClicked(click, doubled); } + @Override public boolean mouseDragged(Click click, double offsetX, double offsetY) { return inputField.mouseDragged(click, offsetX, offsetY); } + @Override public boolean mouseReleased(Click click) { return inputField.mouseReleased(click); } + @Override public boolean mouseScrolled(double mouseX, double mouseY, double horizontalAmount, double verticalAmount) { return inputField.mouseScrolled(mouseX, mouseY, horizontalAmount, verticalAmount); } + @Override public void mouseMoved(double mouseX, double mouseY) { inputField.mouseMoved(mouseX, mouseY); } + @Override public boolean charTyped(CharInput input) { return inputField.charTyped(input); } + @Override public boolean keyReleased(KeyInput input) { return inputField.keyReleased(input); } + @Override public boolean keyPressed(KeyInput input) { return inputField.keyPressed(input); } + } + + private class ColorPickerEntry extends ListEntry { + + @Override + public void render(DrawContext context, int mouseX, int mouseY, boolean hovered, float deltaTicks) { + context.fill( + getContentX(), + getContentY(), + getContentX() + getContentWidth(), + getContentY() + getContentHeight(), + getBackgroundFillColor() + ); + context.drawTexture( + RenderPipelines.GUI_TEXTURED, + getOverlayTextureIdentifier(), + getContentX(), getContentY(), + 0, 0, + getContentWidth(), getContentHeight(), + getContentWidth(), getContentHeight() + ); + + float[] hsb = getHsb(); + int pointerOffsetX = (int) (hsb[1] * getContentWidth()); + int pointerOffsetY = (int) ((1f - hsb[2]) * getContentHeight()); + context.fill( + getContentX() + pointerOffsetX - 2, getContentY() + pointerOffsetY - 2, + getContentX() + pointerOffsetX + 2, getContentY() + pointerOffsetY + 2, + 0xffffffff + ); + context.fill( + getContentX() + pointerOffsetX - 1, getContentY() + pointerOffsetY - 1, + getContentX() + pointerOffsetX + 1, getContentY() + pointerOffsetY + 1, + editor.getCurrentColor() | 0xff000000 + ); + + if (hovered){ + context.setCursor(StandardCursors.ARROW); + } + } + + @Override + public boolean mouseDragged(Click click, double offsetX, double offsetY) { + double x = click.x() - getContentX(); + double y = click.y() - getContentY(); + float saturation = (float) Math.clamp(x / getContentWidth(), 0d, 1d); + float brightness = (float) Math.clamp(1d - y / getContentHeight(), 0d, 1d); + + int newColorRgb = Color.HSBtoRGB(hueSlider.sliderProgress, saturation, brightness) & 0x00ffffff; + int alpha = editor.getCurrentColor() & 0xff000000; + + editor.setCurrentColor(newColorRgb | alpha); + return true; + } + + @Override + public boolean mouseClicked(Click click, boolean doubled) { + return mouseDragged(click, 0, 0); + } + + private int getBackgroundFillColor() { + return Color.HSBtoRGB(hueSlider.sliderProgress, 1, 1); + } + + private static Identifier OVERLAY_TEXTURE_ID; + + public Identifier getOverlayTextureIdentifier(){ + if (OVERLAY_TEXTURE_ID == null){ + NativeImageBackedTexture texture = generateOverlayTexture(); + OVERLAY_TEXTURE_ID = Identifier.of(WidgetsMod.MOD_ID, "textures/gui/generated/color-picker-overlay"); + client.getTextureManager().registerTexture(OVERLAY_TEXTURE_ID, texture); + } + return OVERLAY_TEXTURE_ID; + } + + private NativeImageBackedTexture generateOverlayTexture() { + NativeImageBackedTexture texture = new NativeImageBackedTexture("widgets:textures/gui/generated/color-picker-overlay", 256, 256, false); + NativeImage image = texture.getImage(); + + for (int x = 0; x < 256; x++) { + for (int y = 0; y < 256; y++) { + double alphaWhite = (255d - x) / 255d; + double alphaBlack = y / 255d; + double outAlpha = alphaBlack + alphaWhite * (1d - alphaBlack); + + int rgb = (int) Math.round(outAlpha > 0 ? (255d * alphaWhite * (1d - alphaBlack)) / outAlpha : 0); + int a = (int) Math.round(outAlpha * 255.0); + + image.setColorArgb(x, y, new Color(rgb, rgb, rgb, a).getRGB()); + } + } + + texture.upload(); + return texture; + } + + } + + private class ColorPickerHueSliderEntry extends ListEntry { + + private static final GradientOptions sliderGradient = new GradientOptions( + 16.666666f, + 0, + new int[]{0xffff0000, 0xffffff00, 0xff00ff00, 0xff00ffff, 0xff0000ff, 0xffff00ff, 0xffff0000} + ); + private float sliderProgress; + + public ColorPickerHueSliderEntry(){ + refreshHue(); + } + + @Override + public void render(DrawContext context, int mouseX, int mouseY, boolean hovered, float deltaTicks) { + sliderGradient.fillHorizontal(context, 0, getContentX(), getContentY() + 1, getContentX() + getContentWidth(), getContentY() + getContentHeight() - 1); + context.drawVerticalLine((int) (getContentX() + (getContentWidth() * sliderProgress)), getContentY() - 1, getContentY() + getContentHeight(), 0xff_ff_ff_ff); + + if (hovered){ + context.setCursor(StandardCursors.RESIZE_EW); + } + } + + @Override + public boolean mouseDragged(Click click, double offsetX, double offsetY) { + double x = click.x() - getContentX(); + float newHue = (float) Math.clamp(x / getContentWidth(), 0, 1); + this.sliderProgress = newHue; + + float[] hsb = getHsb(); + int newRgb = Color.HSBtoRGB(newHue, hsb[1], hsb[2]) & 0x00ffffff; + int alpha = editor.getCurrentColor() & 0xff000000; + int newColor = newRgb | alpha; + + if (newColor != editor.getCurrentColor()){ + editor.setCurrentColor(newColor); + } + return true; + } + + @Override + public boolean mouseClicked(Click click, boolean doubled) { + return this.mouseDragged(click, 0, 0); + } + + public void refreshHue() { + this.sliderProgress = getCurrentHue(); + } + } +} diff --git a/src/main/java/de/shiewk/widgets/color/GradientMode.java b/src/main/java/de/shiewk/widgets/color/GradientMode.java new file mode 100644 index 0000000..75a65a7 --- /dev/null +++ b/src/main/java/de/shiewk/widgets/color/GradientMode.java @@ -0,0 +1,18 @@ +package de.shiewk.widgets.color; + +import net.minecraft.text.Text; + +import static net.minecraft.text.Text.translatable; + +public enum GradientMode { + SWEEP(translatable("widgets.gradient.sweep"), translatable("widgets.gradient.sweep.description")), + PULSE(translatable("widgets.gradient.pulse"), translatable("widgets.gradient.pulse.description")); + + public final Text name; + public final Text description; + + GradientMode(Text name, Text description) { + this.name = name; + this.description = description; + } +} diff --git a/src/main/java/de/shiewk/widgets/color/GradientOptions.java b/src/main/java/de/shiewk/widgets/color/GradientOptions.java new file mode 100644 index 0000000..c4cbba4 --- /dev/null +++ b/src/main/java/de/shiewk/widgets/color/GradientOptions.java @@ -0,0 +1,153 @@ +package de.shiewk.widgets.color; + +import de.shiewk.widgets.render.state.HorizontalGradientGuiRenderState; +import net.minecraft.client.font.TextRenderer; +import net.minecraft.client.gui.DrawContext; +import net.minecraft.text.Text; +import org.joml.Matrix3x2fStack; + +import java.util.Objects; + +import static de.shiewk.widgets.utils.WidgetUtils.fadeColor; + +public record GradientOptions(GradientMode mode, float gradientSize, float gradientSpeed, int[] colors) { + + public GradientOptions(GradientMode mode, float gradientSize, float gradientSpeed, int[] colors) { + this.mode = Objects.requireNonNullElse(mode, GradientMode.SWEEP); + this.gradientSize = gradientSize; + this.gradientSpeed = gradientSpeed; + this.colors = Objects.requireNonNullElse(colors, new int[]{ -1 }); + } + + public GradientOptions(float gradientSize, float gradientSpeed, int[] colors) { + this(GradientMode.SWEEP, gradientSize, gradientSpeed, colors); + } + + public void fillHorizontal(DrawContext context, long timeNanos, int x, int y, int endX, int endY) { + if (colors.length == 1) { + context.fill(x, y, endX, endY, colors[0]); + return; + } + switch (mode){ + case SWEEP -> fillHorizonalSweep(context, timeNanos, x, y, endX, endY); + case PULSE -> fillHorizonalPulse(context, timeNanos, x, y, endX, endY); + } + } + + private void fillHorizonalSweep(DrawContext context, long timeNanos, int x, int y, int endX, int endY) { + context.enableScissor(x, y, endX, endY); + + int width = endX - x; + float sizeFactor = gradientSize / 100f; + int partSize = Math.max(1, Math.round(width * sizeFactor)); + + int totalGradientCycle = colors.length * partSize; + + float speedPxPerSec = width * (gradientSpeed / 100f); + float timeSeconds = timeNanos / 1_000_000_000f; + float offset = gradientSpeed == 0 ? 0 : (timeSeconds * speedPxPerSec + x) % totalGradientCycle; + + Matrix3x2fStack matrices = context.getMatrices().pushMatrix(); + matrices.translate(-offset, 0); + + int currentPos = 0; + int colorIndex = 0; + + while (currentPos < width + totalGradientCycle) { + int color1 = colors[colorIndex % colors.length]; + int color2 = colors[(colorIndex + 1) % colors.length]; + + HorizontalGradientGuiRenderState.draw( + context, x + currentPos, y, x + currentPos + partSize, endY, + color1, color2 + ); + + currentPos += partSize; + colorIndex++; + } + + matrices.popMatrix(); + context.disableScissor(); + } + + private void fillHorizonalPulse(DrawContext context, long timeNanos, int x, int y, int endX, int endY) { + context.fill(x, y, endX, endY, getCurrentPulseColor(timeNanos)); + } + + private int getCurrentPulseColor(long timeNanos) { + float progress = timeNanos / 1_000_000_000f * gradientSpeed / gradientSize; + int color1 = colors[(int) (progress % colors.length)]; + int color2 = colors[(int) ((progress + 1) % colors.length)]; + float delta = progress % 1; + return fadeColor(color1, color2, delta); + } + + public void drawHorizontalLine(DrawContext context, long mt, int posX, int endX, int posY) { + this.fillHorizontal(context, mt, posX, posY, endX, posY + 1); + } + + public void drawText(DrawContext context, TextRenderer textRenderer, long timeNanos, String displayText, int x, int y, boolean shadow) { + if (colors.length == 1){ + context.drawText(textRenderer, displayText, x, y, colors[0], shadow); + } else { + switch (mode){ + case SWEEP -> drawTextSweep(context, textRenderer, timeNanos, displayText, x, y, shadow); + case PULSE -> drawTextPulse(context, textRenderer, timeNanos, displayText, x, y, shadow); + } + } + } + + public void drawText(DrawContext context, TextRenderer textRenderer, long timeNanos, Text displayText, int x, int y, boolean shadow) { + if (colors.length == 1){ + context.drawText(textRenderer, displayText, x, y, colors[0], shadow); + } + this.drawText(context, textRenderer, timeNanos, displayText.getString(), x, y, shadow); + } + + private void drawTextSweep(DrawContext context, TextRenderer textRenderer, long timeNanos, String displayText, int x, int y, boolean shadow) { + int pos = 0; + for (int i = 0; i < displayText.length(); i++) { + String s = String.valueOf(displayText.charAt(i)); + int w = textRenderer.getWidth(s); + int col = computeSweepTextColorAt(gradientSpeed == 0 ? pos : pos + x, timeNanos); + context.drawText(textRenderer, s, x +pos, y, col, shadow); + pos += w; + } + } + + private int computeSweepTextColorAt(float pos, long timeNanos) { + pos += timeNanos / 500_000_000f * gradientSpeed; + + float partSize = gradientSize * 2; + int part = (int) (pos / partSize); + double off = pos % partSize / partSize; + + int color1 = colors[part % colors.length]; + int color2 = colors[(part+1) % colors.length]; + + return fadeColor(color1, color2, off); + } + + private void drawTextPulse(DrawContext context, TextRenderer textRenderer, long timeNanos, String displayText, int x, int y, boolean shadow) { + context.drawText(textRenderer, displayText, x, y, getCurrentPulseColor(timeNanos), shadow); + } + + public static GradientOptions solidColor(int color) { + return new GradientOptions(1, 0, new int[]{color}); + } + + public void drawVerticalLine(DrawContext context, long timeNanos, int posX, int posY, int endY) { + fillHorizontal(context, timeNanos, posX, posY, posX + 1, endY); + } + + public GradientOptions multiplyAlpha(double v) { + int[] newColors = new int[colors.length]; + for (int i = 0; i < colors.length; i++) { + int color = colors[i]; + int rgb = color & 0xffffff; + int newAlpha = (int) (((color & 0xff000000) >>> 24) * v); + newColors[i] = (newAlpha << 24) | rgb; + } + return new GradientOptions(mode, gradientSize, gradientSpeed, newColors); + } +} \ No newline at end of file diff --git a/src/main/java/de/shiewk/widgets/color/GradientPreset.java b/src/main/java/de/shiewk/widgets/color/GradientPreset.java new file mode 100644 index 0000000..d84043b --- /dev/null +++ b/src/main/java/de/shiewk/widgets/color/GradientPreset.java @@ -0,0 +1,29 @@ +package de.shiewk.widgets.color; + +import net.minecraft.text.Text; + +import static net.minecraft.text.Text.translatable; + +public record GradientPreset(Text name, GradientOptions gradient) { + + public static final GradientPreset[] presets = new GradientPreset[]{ + new GradientPreset( + translatable("widgets.gradient.preset.rainbow"), + new GradientOptions( + GradientMode.PULSE, + 14, + 20, + new int[]{ + 0xff_ff_00_00, + 0xff_ff_88_00, + 0xff_ff_ff_00, + 0xff_00_ff_00, + 0xff_00_ff_ff, + 0xff_50_00_80, + 0xff_ff_00_ff, + } + ) + ) + }; + +} diff --git a/src/main/java/de/shiewk/widgets/render/state/HorizontalGradientGuiRenderState.java b/src/main/java/de/shiewk/widgets/render/state/HorizontalGradientGuiRenderState.java new file mode 100644 index 0000000..87803d4 --- /dev/null +++ b/src/main/java/de/shiewk/widgets/render/state/HorizontalGradientGuiRenderState.java @@ -0,0 +1,102 @@ +package de.shiewk.widgets.render.state; + +import com.mojang.blaze3d.pipeline.RenderPipeline; +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.minecraft.client.gl.RenderPipelines; +import net.minecraft.client.gui.DrawContext; +import net.minecraft.client.gui.ScreenRect; +import net.minecraft.client.gui.render.state.SimpleGuiElementRenderState; +import net.minecraft.client.render.VertexConsumer; +import net.minecraft.client.texture.TextureSetup; +import org.jetbrains.annotations.Nullable; +import org.joml.Matrix3x2f; + +@Environment(EnvType.CLIENT) +public final class HorizontalGradientGuiRenderState implements SimpleGuiElementRenderState { + + private final RenderPipeline pipeline; + private final TextureSetup textureSetup; + private final Matrix3x2f pose; + private final ScreenRect scissorArea; + private final ScreenRect bounds; + + private final int x; + private final int y; + + private final int endX; + private final int endY; + + private final int colorLeft; + private final int colorRight; + + private HorizontalGradientGuiRenderState( + RenderPipeline pipeline, + TextureSetup textureSetup, + Matrix3x2f pose, + ScreenRect scissorArea, + int x, + int y, + int endX, + int endY, int colorLeft, int colorRight + ) { + this.pipeline = pipeline; + this.textureSetup = textureSetup; + this.pose = pose; + this.scissorArea = scissorArea; + this.x = x; + this.y = y; + this.endX = endX; + this.endY = endY; + this.colorLeft = colorLeft; + this.colorRight = colorRight; + this.bounds = createBounds(x, y, endX, endY, pose, scissorArea); + } + + @Override + public void setupVertices(VertexConsumer vertices) { + vertices.vertex(pose, x, y).color(colorLeft); + vertices.vertex(pose, x, endY).color(colorLeft); + vertices.vertex(pose, endX, endY).color(colorRight); + vertices.vertex(pose, endX, y).color(colorRight); + } + + @Override + public RenderPipeline pipeline() { + return pipeline; + } + + @Override + public TextureSetup textureSetup() { + return textureSetup; + } + + @Override + public @Nullable ScreenRect scissorArea() { + return scissorArea; + } + + @Nullable + private static ScreenRect createBounds(int x0, int y0, int x1, int y1, Matrix3x2f pose, @Nullable ScreenRect scissorArea) { + ScreenRect screenRect = (new ScreenRect(x0, y0, x1 - x0 + 1, y1 - y0)).transformEachVertex(pose); + return scissorArea != null ? scissorArea.intersection(screenRect) : screenRect; + } + + @Override + public @Nullable ScreenRect bounds() { + return bounds; + } + + public static void draw(DrawContext context, int x, int y, int endX, int endY, int colorLeft, int colorRight) { + context.state.addSimpleElement( + new HorizontalGradientGuiRenderState( + RenderPipelines.GUI, + TextureSetup.empty(), + new Matrix3x2f(context.getMatrices()), + context.scissorStack.peekLast(), + x, y, endX, endY, + colorLeft, colorRight + ) + ); + } +} diff --git a/src/main/java/de/shiewk/widgets/utils/WidgetUtils.java b/src/main/java/de/shiewk/widgets/utils/WidgetUtils.java index 5129f14..8cb7236 100644 --- a/src/main/java/de/shiewk/widgets/utils/WidgetUtils.java +++ b/src/main/java/de/shiewk/widgets/utils/WidgetUtils.java @@ -3,6 +3,7 @@ package de.shiewk.widgets.utils; import net.minecraft.client.MinecraftClient; import net.minecraft.client.sound.PositionedSoundInstance; import net.minecraft.sound.SoundEvent; +import net.minecraft.util.math.MathHelper; import net.minecraft.world.tick.TickManager; import java.util.function.BooleanSupplier; @@ -35,4 +36,25 @@ public class WidgetUtils { MinecraftClient.getInstance().getSoundManager().play(PositionedSoundInstance.master(ev, 1f, 1f)); } + public static int fadeColor(int color1, int color2, double delta) { + int alpha = (int) MathHelper.lerp(delta, (color1 >> 24) & 0xff, (color2 >> 24) & 0xff); + int red = (int) MathHelper.lerp(delta, (color1 >> 16) & 0xff, (color2 >> 16) & 0xff); + int green = (int) MathHelper.lerp(delta, (color1 >> 8) & 0xff, (color2 >> 8) & 0xff); + int blue = (int) MathHelper.lerp(delta, color1 & 0xff, color2 & 0xff); + return (alpha << 24) | (red << 16) | (green << 8) | blue; + } + + public static String colorARGBToHexRGBA(int color) { + int a = color >> 24 & 0xff; + int r = color >> 16 & 0xff; + int g = color >> 8 & 0xff; + int b = color & 0xff; + return toHexSingle(r) + toHexSingle(g) + toHexSingle(b) + toHexSingle(a); + } + + private static String toHexSingle(int comp){ + String s = Integer.toHexString(comp); + return "0".repeat(2 - s.length()) + s; + } + } diff --git a/src/main/java/de/shiewk/widgets/widgets/ArmorHudWidget.java b/src/main/java/de/shiewk/widgets/widgets/ArmorHudWidget.java index 08fc655..374df5b 100644 --- a/src/main/java/de/shiewk/widgets/widgets/ArmorHudWidget.java +++ b/src/main/java/de/shiewk/widgets/widgets/ArmorHudWidget.java @@ -1,10 +1,8 @@ package de.shiewk.widgets.widgets; import de.shiewk.widgets.WidgetSettings; -import de.shiewk.widgets.widgets.settings.EnumWidgetSetting; -import de.shiewk.widgets.widgets.settings.IntSliderWidgetSetting; -import de.shiewk.widgets.widgets.settings.RGBAColorWidgetSetting; -import de.shiewk.widgets.widgets.settings.ToggleWidgetSetting; +import de.shiewk.widgets.color.GradientOptions; +import de.shiewk.widgets.widgets.settings.*; import net.minecraft.client.MinecraftClient; import net.minecraft.client.font.TextRenderer; import net.minecraft.client.gui.DrawContext; @@ -28,17 +26,13 @@ public class ArmorHudWidget extends ResizableWidget { new ToggleWidgetSetting("show_durability", translatable("widgets.widgets.armorHud.showDurability"), true), new IntSliderWidgetSetting("width", translatable("widgets.widgets.basictext.width"), 16, 42, 128), new EnumWidgetSetting<>("alignment", translatable("widgets.widgets.basictext.alignment"), BasicTextWidget.TextAlignment.class, BasicTextWidget.TextAlignment.CENTER, BasicTextWidget.TextAlignment::displayText), - new RGBAColorWidgetSetting("backgroundcolor", translatable("widgets.widgets.basictext.background"), 0, 0, 0, 80), + new GradientWidgetSetting("backgroundcolor", translatable("widgets.widgets.basictext.background"), 0x50_00_00_00), new EnumWidgetSetting<>("durability_style", translatable("widgets.widgets.armorHud.durabilityStyle"), DurabilityStyle.class, DurabilityStyle.NUMBER, DurabilityStyle::getDisplayName), - new ToggleWidgetSetting("rainbow", translatable("widgets.widgets.common.rainbow"), false), - new IntSliderWidgetSetting("rainbow_speed", translatable("widgets.widgets.common.rainbow.speed"), 1, 3, 10), - new RGBAColorWidgetSetting("textcolor", translatable("widgets.widgets.basictext.textcolor"), 255, 255, 255, 255) + new GradientWidgetSetting("textcolor", translatable("widgets.widgets.basictext.textcolor"), 0xff_ff_ff_ff) )); getSettings().optionById("width").setShowCondition(() -> this.showDurability); getSettings().optionById("alignment").setShowCondition(() -> this.showDurability); getSettings().optionById("durability_style").setShowCondition(() -> this.showDurability); - getSettings().optionById("rainbow_speed").setShowCondition(() -> this.rainbow); - getSettings().optionById("textcolor").setShowCondition(() -> !this.rainbow); } public enum DurabilityStyle { @@ -50,22 +44,25 @@ public class ArmorHudWidget extends ResizableWidget { } } - private int padding = 1; - private boolean showDurability = true; - private DurabilityStyle durabilityStyle; + protected int padding = 1; + protected boolean showDurability = true; + protected DurabilityStyle durabilityStyle; protected ItemStack helmet; protected ItemStack chestplate; protected ItemStack leggings; protected ItemStack boots; - protected boolean rainbow = false; - protected int rainbowSpeed = 3; protected int preferredWidth = 42; protected BasicTextWidget.TextAlignment textAlignment = BasicTextWidget.TextAlignment.CENTER; - protected int backgroundColor = 0x50_00_00_00, textColor = 0xff_ff_ff_ff; + protected GradientOptions backgroundColor, textColor; @Override public void renderScaled(DrawContext context, long measuringTimeNano, TextRenderer textRenderer, int posX, int posY) { - context.fill(posX, posY, posX+width(), posY+height(), backgroundColor); + backgroundColor.fillHorizontal( + context, + measuringTimeNano, + posX, posY, + posX+width(), posY+height() + ); if (helmet != null){ renderItem(context, measuringTimeNano, textRenderer, helmet, posX + padding, posY + padding); } @@ -99,14 +96,14 @@ public class ArmorHudWidget extends ResizableWidget { switch (textAlignment){ case RIGHT -> { int width = textRenderer.getWidth(text); - context.drawText(textRenderer, text, posX + width() - width - padding * 2, posY + 5, rainbow ? BasicTextWidget.rainbowColor(mt, rainbowSpeed) : textColor, true); + textColor.drawText(context, textRenderer, mt, text, posX + width() - width - padding * 2, posY + 5, true); } case CENTER -> { int width = textRenderer.getWidth(text); - context.drawText(textRenderer, text, posX + ((preferredWidth + padding*2) - width) / 2 + 8, posY + 5, rainbow ? BasicTextWidget.rainbowColor(mt, rainbowSpeed) : textColor, true); + textColor.drawText(context, textRenderer, mt, text, posX + ((preferredWidth + padding*2) - width) / 2 + 8, posY + 5, true); } case LEFT -> { - context.drawText(textRenderer, text, posX + 16 + padding, posY + 5, rainbow ? BasicTextWidget.rainbowColor(mt, rainbowSpeed) : textColor, true); + textColor.drawText(context, textRenderer, mt, text, posX + 16 + padding, posY + 5, true); } } } @@ -156,10 +153,8 @@ public class ArmorHudWidget extends ResizableWidget { this.padding = (int) settings.optionById("padding").getValue(); this.showDurability = (boolean) settings.optionById("show_durability").getValue(); this.durabilityStyle = (DurabilityStyle) settings.optionById("durability_style").getValue(); - this.rainbow = (boolean) settings.optionById("rainbow").getValue(); - this.rainbowSpeed = (int) settings.optionById("rainbow_speed").getValue(); - this.textColor = (int) settings.optionById("textcolor").getValue(); - this.backgroundColor = (int) settings.optionById("backgroundcolor").getValue(); + this.textColor = (GradientOptions) settings.optionById("textcolor").getValue(); + this.backgroundColor = (GradientOptions) settings.optionById("backgroundcolor").getValue(); this.preferredWidth = (int) settings.optionById("width").getValue(); this.textAlignment = (BasicTextWidget.TextAlignment) settings.optionById("alignment").getValue(); } diff --git a/src/main/java/de/shiewk/widgets/widgets/BandwidthWidget.java b/src/main/java/de/shiewk/widgets/widgets/BandwidthWidget.java index a780e69..50f712e 100644 --- a/src/main/java/de/shiewk/widgets/widgets/BandwidthWidget.java +++ b/src/main/java/de/shiewk/widgets/widgets/BandwidthWidget.java @@ -1,6 +1,7 @@ package de.shiewk.widgets.widgets; import de.shiewk.widgets.WidgetSettings; +import de.shiewk.widgets.color.GradientOptions; import de.shiewk.widgets.utils.WidgetUtils; import de.shiewk.widgets.widgets.settings.EnumWidgetSetting; import de.shiewk.widgets.widgets.settings.ToggleWidgetSetting; @@ -52,9 +53,7 @@ public class BandwidthWidget extends BasicTextWidget { new EnumWidgetSetting<>("unit", Text.translatable("widgets.widgets.bandwidth.unit"), Unit.class, Unit.KB, unit -> literal(unit.name)), new ToggleWidgetSetting("fastupdate", translatable("widgets.widgets.bandwidth.fastupdate"), false) )); - getSettings().optionById("textcolor").setShowCondition(() -> !this.dynamicColor && !this.rainbow); - getSettings().optionById("rainbow").setShowCondition(() -> !this.dynamicColor); - getSettings().optionById("rainbow_speed").setShowCondition(() -> !this.dynamicColor && this.rainbow); + getSettings().optionById("textcolor").setShowCondition(() -> !this.dynamicColor); } private int t = 0; @@ -75,11 +74,11 @@ public class BandwidthWidget extends BasicTextWidget { formatAndSetRenderText(literal(unit.sizeFormatter.apply(avgBytesPerSecond))); if (this.dynamicColor){ if (avgBytesPerSecond < 100000){ - this.textColor = 0xff00ff00; + this.textColor = GradientOptions.solidColor(0xff00ff00); } else if (avgBytesPerSecond < 750000) { - this.textColor = 0xffffff00; + this.textColor = GradientOptions.solidColor(0xffffff00); } else { - this.textColor = 0xffff3030; + this.textColor = GradientOptions.solidColor(0xffff3030); } } } diff --git a/src/main/java/de/shiewk/widgets/widgets/BasicTextWidget.java b/src/main/java/de/shiewk/widgets/widgets/BasicTextWidget.java index ef18540..778c708 100644 --- a/src/main/java/de/shiewk/widgets/widgets/BasicTextWidget.java +++ b/src/main/java/de/shiewk/widgets/widgets/BasicTextWidget.java @@ -1,12 +1,9 @@ package de.shiewk.widgets.widgets; -import de.shiewk.widgets.widgets.settings.WidgetSettingOption; +import de.shiewk.widgets.color.GradientOptions; +import de.shiewk.widgets.widgets.settings.*; import de.shiewk.widgets.WidgetSettings; import de.shiewk.widgets.client.WidgetRenderer; -import de.shiewk.widgets.widgets.settings.EnumWidgetSetting; -import de.shiewk.widgets.widgets.settings.IntSliderWidgetSetting; -import de.shiewk.widgets.widgets.settings.RGBAColorWidgetSetting; -import de.shiewk.widgets.widgets.settings.ToggleWidgetSetting; import it.unimi.dsi.fastutil.objects.ObjectArrayList; import net.minecraft.client.font.TextRenderer; import net.minecraft.client.gui.DrawContext; @@ -67,15 +64,11 @@ public abstract class BasicTextWidget extends ResizableWidget { private int padding = 0; private TextRenderer renderer = null; private boolean textShadow = true; - protected boolean rainbow = false; - private int rainbowSpeed = 3; private static ObjectArrayList> getCustomSettings(List> otherCustomOptions) { final ObjectArrayList> list = new ObjectArrayList<>(otherCustomOptions); - list.add(new RGBAColorWidgetSetting("backgroundcolor", translatable("widgets.widgets.basictext.background"), 0, 0, 0, 80)); - list.add(new ToggleWidgetSetting("rainbow", translatable("widgets.widgets.common.rainbow"), false)); - list.add(new RGBAColorWidgetSetting("textcolor", translatable("widgets.widgets.basictext.textcolor"), 255, 255, 255, 255)); - list.add(new IntSliderWidgetSetting("rainbow_speed", translatable("widgets.widgets.common.rainbow.speed"), 1, 3, 10)); + list.add(new GradientWidgetSetting("backgroundcolor", translatable("widgets.widgets.basictext.background"), 0x50_00_00_00)); + list.add(new GradientWidgetSetting("textcolor", translatable("widgets.widgets.basictext.textcolor"), 0xff_ff_ff_ff)); list.add(new IntSliderWidgetSetting("width", translatable("widgets.widgets.basictext.width"), 10, DEFAULT_WIDTH, 80*3)); list.add(new IntSliderWidgetSetting("height", translatable("widgets.widgets.basictext.height"), 9, DEFAULT_HEIGHT, 80)); list.add(new ToggleWidgetSetting("shadow", translatable("widgets.widgets.basictext.textshadow"), true)); @@ -87,17 +80,14 @@ public abstract class BasicTextWidget extends ResizableWidget { protected BasicTextWidget(Identifier id, List> otherCustomOptions) { super(id, getCustomSettings(otherCustomOptions)); getSettings().optionById("padding").setShowCondition(() -> this.textAlignment != TextAlignment.CENTER); - getSettings().optionById("textcolor").setShowCondition(() -> !this.rainbow); - getSettings().optionById("rainbow_speed").setShowCondition(() -> this.rainbow); } protected static final int DEFAULT_WIDTH = 80, - DEFAULT_HEIGHT = 9 + 12, - DEFAULT_BACKGROUND_COLOR = new Color(0, 0, 0, 80).getRGB(), - DEFAULT_TEXT_COLOR = new Color(255, 255 ,255, 255).getRGB(); + DEFAULT_HEIGHT = 9 + 12; - protected int backgroundColor = DEFAULT_BACKGROUND_COLOR, textColor = DEFAULT_TEXT_COLOR, width = DEFAULT_WIDTH, height = DEFAULT_HEIGHT; + protected int width = DEFAULT_WIDTH, height = DEFAULT_HEIGHT; + protected GradientOptions backgroundColor, textColor; protected TextAlignment textAlignment = TextAlignment.CENTER; protected TextStyle textStyle = TextStyle.PLAIN; @@ -115,18 +105,14 @@ public abstract class BasicTextWidget extends ResizableWidget { public void renderScaled(DrawContext context, long n, TextRenderer textRenderer, int posX, int posY) { if (!shouldRender) return; renderer = textRenderer; - context.fill(posX, posY, posX + width(), posY + height(), this.backgroundColor); + this.backgroundColor.fillHorizontal(context, n, posX, posY, posX + width(), posY + height()); Matrix3x2fStack matrices = context.getMatrices() .pushMatrix(); matrices.translate(posX + textX, posY + textY, matrices); - context.drawText(textRenderer, renderText, 0, 0, rainbow ? rainbowColor(n, rainbowSpeed) : this.textColor, textShadow); + this.textColor.drawText(context, textRenderer, n, renderText, 0, 0, textShadow); matrices.popMatrix(); } - public static int rainbowColor(long n, float speed) { - return Color.HSBtoRGB(n / 10_000_000_000f * speed, 1, 1); - } - @Override public final void tick() { tickWidget(); @@ -165,15 +151,13 @@ public abstract class BasicTextWidget extends ResizableWidget { @Override public void onSettingsChanged(WidgetSettings settings) { super.onSettingsChanged(settings); - this.backgroundColor = (int) settings.optionById("backgroundcolor").getValue(); - this.textColor = (int) settings.optionById("textcolor").getValue(); + this.backgroundColor = (GradientOptions) settings.optionById("backgroundcolor").getValue(); + this.textColor = (GradientOptions) settings.optionById("textcolor").getValue(); this.width = (int) settings.optionById("width").getValue(); this.height = (int) settings.optionById("height").getValue(); this.textAlignment = (TextAlignment) settings.optionById("alignment").getValue(); this.padding = (int) settings.optionById("padding").getValue(); this.textShadow = (boolean) settings.optionById("shadow").getValue(); this.textStyle = (TextStyle) settings.optionById("text_style").getValue(); - this.rainbow = (boolean) settings.optionById("rainbow").getValue(); - this.rainbowSpeed = (int) settings.optionById("rainbow_speed").getValue(); } } diff --git a/src/main/java/de/shiewk/widgets/widgets/CoordinatesWidget.java b/src/main/java/de/shiewk/widgets/widgets/CoordinatesWidget.java index e4e9a96..ea6addc 100644 --- a/src/main/java/de/shiewk/widgets/widgets/CoordinatesWidget.java +++ b/src/main/java/de/shiewk/widgets/widgets/CoordinatesWidget.java @@ -1,8 +1,9 @@ package de.shiewk.widgets.widgets; import de.shiewk.widgets.WidgetSettings; +import de.shiewk.widgets.color.GradientOptions; +import de.shiewk.widgets.widgets.settings.GradientWidgetSetting; import de.shiewk.widgets.widgets.settings.IntSliderWidgetSetting; -import de.shiewk.widgets.widgets.settings.RGBAColorWidgetSetting; import de.shiewk.widgets.widgets.settings.ToggleWidgetSetting; import net.minecraft.client.MinecraftClient; import net.minecraft.client.font.TextRenderer; @@ -14,58 +15,48 @@ import net.minecraft.util.Identifier; import java.awt.*; import java.util.List; -import static net.minecraft.text.Text.translatable; - public class CoordinatesWidget extends ResizableWidget { public CoordinatesWidget(Identifier id) { super(id, List.of( new ToggleWidgetSetting("x", Text.translatable("widgets.widgets.coordinates.showX"), true), new ToggleWidgetSetting("y", Text.translatable("widgets.widgets.coordinates.showY"), true), new ToggleWidgetSetting("z", Text.translatable("widgets.widgets.coordinates.showZ"), true), - new RGBAColorWidgetSetting("backgroundcolor", Text.translatable("widgets.widgets.basictext.background"), 0, 0, 0, 80), - new ToggleWidgetSetting("rainbow", translatable("widgets.widgets.common.rainbow"), false), - new RGBAColorWidgetSetting("textcolor", Text.translatable("widgets.widgets.basictext.textcolor"), 255, 255, 255, 255), - new IntSliderWidgetSetting("rainbow_speed", translatable("widgets.widgets.common.rainbow.speed"), 1, 3, 10), + new GradientWidgetSetting("backgroundcolor", Text.translatable("widgets.widgets.basictext.background"), 0x50_00_00_00), + new GradientWidgetSetting("textcolor", Text.translatable("widgets.widgets.basictext.textcolor"), 0xffffffff), new IntSliderWidgetSetting("width", Text.translatable("widgets.widgets.basictext.width"), 10, WIDTH, 80*3), new IntSliderWidgetSetting("paddingX", Text.translatable("widgets.widgets.basictext.paddingX"), 0, 5, 20), new IntSliderWidgetSetting("paddingY", Text.translatable("widgets.widgets.basictext.paddingY"), 0, 5, 20), new ToggleWidgetSetting("shadow", Text.translatable("widgets.widgets.basictext.textshadow"), true) )); - getSettings().optionById("textcolor").setShowCondition(() -> !this.rainbow); - getSettings().optionById("rainbow_speed").setShowCondition(() -> this.rainbow); } private String textX = "X", textY = "Y", textZ = "Z"; - private int txc = 0, tyc = 0, tzc = 0, rainbowSpeed = 3; - private boolean shadow = true, rainbow = false; + private int txc = 0, tyc = 0, tzc = 0; + private boolean shadow = true; @Override public void renderScaled(DrawContext context, long mt, TextRenderer textRenderer, int posX, int posY) { - context.fill(posX, posY, posX + width(), posY + height(), this.backgroundColor); + this.backgroundColor.fillHorizontal(context, mt, posX, posY, posX + width(), posY + height()); int y = this.paddingY; if (showX){ y++; - context.drawText(textRenderer, "X: ", posX + paddingX, posY + y, textColor(mt), shadow); - context.drawText(textRenderer, textX, posX + txc, posY + y, textColor(mt), shadow); + this.textColor.drawText(context, textRenderer, mt, "X: ", posX + paddingX, posY + y, shadow); + this.textColor.drawText(context, textRenderer, mt, textX, posX + txc, posY + y, shadow); y += textRenderer.fontHeight + 1; } if (showY){ y++; - context.drawText(textRenderer, "Y: ", posX + paddingX, posY + y, textColor(mt), shadow); - context.drawText(textRenderer, textY, posX + tyc, posY + y, textColor(mt), shadow); + this.textColor.drawText(context, textRenderer, mt, "Y: ", posX + paddingX, posY + y, shadow); + this.textColor.drawText(context, textRenderer, mt, textY, posX + tyc, posY + y, shadow); y += textRenderer.fontHeight + 1; } if (showZ){ y++; - context.drawText(textRenderer, "Z: ", posX + paddingX, posY + y, textColor(mt), shadow); - context.drawText(textRenderer, textZ, posX + tzc, posY + y, textColor(mt), shadow); + this.textColor.drawText(context, textRenderer, mt, "Z: ", posX + paddingX, posY + y, shadow); + this.textColor.drawText(context, textRenderer, mt, textZ, posX + tzc, posY + y, shadow); } } - private int textColor(long n) { - return rainbow ? BasicTextWidget.rainbowColor(n, rainbowSpeed) : textColor; - } - @Override public void tick() { final TextRenderer textRenderer = MinecraftClient.getInstance().textRenderer; @@ -95,20 +86,17 @@ public class CoordinatesWidget extends ResizableWidget { return Text.translatable("widgets.widgets.coordinates.description"); } - protected static final int - WIDTH = 80, - PADDING = 6, - DEFAULT_BACKGROUND_COLOR = new Color(0, 0, 0, 80).getRGB(), - DEFAULT_TEXT_COLOR = new Color(255, 255 ,255, 255).getRGB(); + protected static final int WIDTH = 80, PADDING = 6; - protected int backgroundColor = DEFAULT_BACKGROUND_COLOR, textColor = DEFAULT_TEXT_COLOR, paddingX = PADDING, paddingY = PADDING, width = WIDTH; + protected GradientOptions backgroundColor, textColor; + protected int paddingX = PADDING, paddingY = PADDING, width = WIDTH; protected boolean showX = true, showY = true, showZ = true; @Override public void onSettingsChanged(WidgetSettings settings) { super.onSettingsChanged(settings); - this.backgroundColor = (int) settings.optionById("backgroundcolor").getValue(); - this.textColor = (int) settings.optionById("textcolor").getValue(); + this.backgroundColor = (GradientOptions) settings.optionById("backgroundcolor").getValue(); + this.textColor = (GradientOptions) settings.optionById("textcolor").getValue(); this.showX = (boolean) settings.optionById("x").getValue(); this.showY = (boolean) settings.optionById("y").getValue(); this.showZ = (boolean) settings.optionById("z").getValue(); @@ -116,8 +104,6 @@ public class CoordinatesWidget extends ResizableWidget { this.paddingY = (int) settings.optionById("paddingY").getValue(); this.width = (int) settings.optionById("width").getValue(); this.shadow = (boolean) settings.optionById("shadow").getValue(); - this.rainbow = (boolean) settings.optionById("rainbow").getValue(); - this.rainbowSpeed = (int) settings.optionById("rainbow_speed").getValue(); } @Override diff --git a/src/main/java/de/shiewk/widgets/widgets/InventoryWidget.java b/src/main/java/de/shiewk/widgets/widgets/InventoryWidget.java index 473bcbe..d729877 100644 --- a/src/main/java/de/shiewk/widgets/widgets/InventoryWidget.java +++ b/src/main/java/de/shiewk/widgets/widgets/InventoryWidget.java @@ -1,10 +1,8 @@ package de.shiewk.widgets.widgets; import de.shiewk.widgets.WidgetSettings; -import de.shiewk.widgets.widgets.settings.EnumWidgetSetting; -import de.shiewk.widgets.widgets.settings.IntSliderWidgetSetting; -import de.shiewk.widgets.widgets.settings.RGBAColorWidgetSetting; -import de.shiewk.widgets.widgets.settings.ToggleWidgetSetting; +import de.shiewk.widgets.color.GradientOptions; +import de.shiewk.widgets.widgets.settings.*; import net.minecraft.client.MinecraftClient; import net.minecraft.client.font.TextRenderer; import net.minecraft.client.gl.RenderPipelines; @@ -51,34 +49,18 @@ public class InventoryWidget extends ResizableWidget { super(id, List.of( new EnumWidgetSetting<>("mode", translatable("widgets.widgets.inventory.mode"), InventoryMode.class, InventoryMode.TEXTURE_PACK, InventoryMode::display), new ToggleWidgetSetting("show_hotbar", translatable("widgets.widgets.inventory.showHotbar"), true), - new ToggleWidgetSetting("rainbow_grid", translatable("widgets.widgets.inventory.rainbowGrid"), false), - new IntSliderWidgetSetting("grid_rainbow_speed", translatable("widgets.widgets.common.rainbow.speed"), 1, 3, 10), - new RGBAColorWidgetSetting("grid_color", translatable("widgets.widgets.inventory.gridColor"), 0, 0, 0, 255), - new ToggleWidgetSetting("rainbow_boxes", translatable("widgets.widgets.inventory.rainbowBoxes"), false), - new IntSliderWidgetSetting("box_rainbow_speed", translatable("widgets.widgets.common.rainbow.speed"), 1, 3, 10), - new RGBAColorWidgetSetting("box_color", translatable("widgets.widgets.inventory.boxColor"), 80, 80, 80, 128) + new GradientWidgetSetting("grid_color", translatable("widgets.widgets.inventory.gridColor"), 0xff000000), + new GradientWidgetSetting("box_color", translatable("widgets.widgets.inventory.boxColor"), 0x88505050) )); - getSettings().optionById("rainbow_grid").setShowCondition(() -> this.mode == InventoryMode.GRID); - getSettings().optionById("grid_rainbow_speed").setShowCondition(() -> this.mode == InventoryMode.GRID && this.rainbowGrid); - getSettings().optionById("grid_color").setShowCondition(() -> this.mode == InventoryMode.GRID && !this.rainbowGrid); - - getSettings().optionById("rainbow_boxes").setShowCondition(() -> this.mode == InventoryMode.BOXES); - getSettings().optionById("box_rainbow_speed").setShowCondition(() -> this.mode == InventoryMode.BOXES && this.rainbowBoxes); - getSettings().optionById("box_color").setShowCondition(() -> this.mode == InventoryMode.BOXES && !this.rainbowBoxes); - + getSettings().optionById("grid_color").setShowCondition(() -> this.mode == InventoryMode.GRID); + getSettings().optionById("box_color").setShowCondition(() -> this.mode == InventoryMode.BOXES); getSettings().optionById("show_hotbar").setShowCondition(() -> this.mode.canDisableHotbar); } private InventoryMode mode = InventoryMode.TEXTURE_PACK; private PlayerInventory inventory; - private boolean rainbowGrid = false; - private int gridColor = 0xff000000; - private int gridRainbowSpeed = 3; - - private boolean rainbowBoxes = false; - private int boxColor = 0xff000000; - private int boxRainbowSpeed = 3; + private GradientOptions gridColor, boxColor; private boolean showHotbar = false; @Override @@ -109,30 +91,28 @@ public class InventoryWidget extends ResizableWidget { context.disableScissor(); } case GRID -> { - int gridColor = rainbowGrid ? BasicTextWidget.rainbowColor(mt, gridRainbowSpeed) : this.gridColor; - context.drawHorizontalLine(posX, posX+width(), posY, gridColor); - context.drawHorizontalLine(posX, posX+width(), posY + 18, gridColor); - context.drawHorizontalLine(posX, posX+width(), posY + 36, gridColor); - context.drawHorizontalLine(posX, posX+width(), posY + 54, gridColor); + gridColor.drawHorizontalLine(context, mt, posX, posX+width(), posY); + gridColor.drawHorizontalLine(context, mt, posX, posX+width(), posY + 18); + gridColor.drawHorizontalLine(context, mt, posX, posX+width(), posY + 36); + gridColor.drawHorizontalLine(context, mt, posX, posX+width(), posY + 54); if (showHotbar){ - context.drawHorizontalLine(posX, posX+width(), posY + 58, gridColor); - context.drawHorizontalLine(posX, posX+width(), posY + 76, gridColor); + gridColor.drawHorizontalLine(context, mt, posX, posX+width(), posY + 58); + gridColor.drawHorizontalLine(context, mt, posX, posX+width(), posY + 76); } - context.drawVerticalLine(posX, posY, posY+height(), gridColor); - context.drawVerticalLine(posX+18, posY, posY+height(), gridColor); - context.drawVerticalLine(posX+18*2, posY, posY+height(), gridColor); - context.drawVerticalLine(posX+18*3, posY, posY+height(), gridColor); - context.drawVerticalLine(posX+18*4, posY, posY+height(), gridColor); - context.drawVerticalLine(posX+18*5, posY, posY+height(), gridColor); - context.drawVerticalLine(posX+18*6, posY, posY+height(), gridColor); - context.drawVerticalLine(posX+18*7, posY, posY+height(), gridColor); - context.drawVerticalLine(posX+18*8, posY, posY+height(), gridColor); - context.drawVerticalLine(posX+18*9, posY, posY+height(), gridColor); + gridColor.drawVerticalLine(context, mt, posX, posY, posY+height()); + gridColor.drawVerticalLine(context, mt, posX+18, posY, posY+height()); + gridColor.drawVerticalLine(context, mt, posX+18*2, posY, posY+height()); + gridColor.drawVerticalLine(context, mt, posX+18*3, posY, posY+height()); + gridColor.drawVerticalLine(context, mt, posX+18*4, posY, posY+height()); + gridColor.drawVerticalLine(context, mt, posX+18*5, posY, posY+height()); + gridColor.drawVerticalLine(context, mt, posX+18*6, posY, posY+height()); + gridColor.drawVerticalLine(context, mt, posX+18*7, posY, posY+height()); + gridColor.drawVerticalLine(context, mt, posX+18*8, posY, posY+height()); + gridColor.drawVerticalLine(context, mt, posX+18*9, posY, posY+height()); } case BOXES -> { - int boxColor = rainbowBoxes ? ((BasicTextWidget.rainbowColor(mt, boxRainbowSpeed) & 0xffffff) | (this.boxColor & 0xff000000)) : this.boxColor; for (int ry = 0; ry < 4; ry++) { if (ry == 0 && !showHotbar) continue; for (int rx = 0; rx < 9; rx++) { @@ -140,7 +120,7 @@ public class InventoryWidget extends ResizableWidget { int itemY = ry == 0 ? posY + 58 : posY + (ry-1) * 18; int itemX = posX + rx * 18; - context.fill(itemX, itemY, itemX + 16, itemY + 16, boxColor); + boxColor.fillHorizontal(context, mt, itemX, itemY, itemX + 16, itemY + 16); } } } @@ -206,13 +186,9 @@ public class InventoryWidget extends ResizableWidget { public void onSettingsChanged(WidgetSettings settings) { super.onSettingsChanged(settings); this.mode = (InventoryMode) settings.optionById("mode").getValue(); - this.rainbowGrid = (boolean) settings.optionById("rainbow_grid").getValue(); - this.gridRainbowSpeed = (int) settings.optionById("grid_rainbow_speed").getValue(); - this.gridColor = (int) settings.optionById("grid_color").getValue(); - this.rainbowBoxes = (boolean) settings.optionById("rainbow_boxes").getValue(); - this.boxRainbowSpeed = (int) settings.optionById("box_rainbow_speed").getValue(); - this.boxColor = (int) settings.optionById("box_color").getValue(); + this.gridColor = (GradientOptions) settings.optionById("grid_color").getValue(); + this.boxColor = (GradientOptions) settings.optionById("box_color").getValue(); this.showHotbar = (boolean) settings.optionById("show_hotbar").getValue() || !mode.canDisableHotbar; } diff --git a/src/main/java/de/shiewk/widgets/widgets/KeyStrokesWidget.java b/src/main/java/de/shiewk/widgets/widgets/KeyStrokesWidget.java index 79ad3ee..411feb5 100644 --- a/src/main/java/de/shiewk/widgets/widgets/KeyStrokesWidget.java +++ b/src/main/java/de/shiewk/widgets/widgets/KeyStrokesWidget.java @@ -1,8 +1,8 @@ package de.shiewk.widgets.widgets; import de.shiewk.widgets.WidgetSettings; -import de.shiewk.widgets.widgets.settings.IntSliderWidgetSetting; -import de.shiewk.widgets.widgets.settings.RGBAColorWidgetSetting; +import de.shiewk.widgets.color.GradientOptions; +import de.shiewk.widgets.widgets.settings.GradientWidgetSetting; import de.shiewk.widgets.widgets.settings.ToggleWidgetSetting; import net.minecraft.client.MinecraftClient; import net.minecraft.client.font.TextRenderer; @@ -11,40 +11,24 @@ import net.minecraft.client.option.KeyBinding; import net.minecraft.text.Text; import net.minecraft.util.Identifier; import net.minecraft.util.Util; -import net.minecraft.util.math.MathHelper; -import java.awt.*; import java.util.List; import java.util.Objects; -import static net.minecraft.text.Text.translatable; - public class KeyStrokesWidget extends ResizableWidget { public KeyStrokesWidget(Identifier id) { super(id, List.of( new ToggleWidgetSetting("showjump", Text.translatable("widgets.widgets.keystrokes.showJumpKey"), true), - new RGBAColorWidgetSetting("bgpressed", Text.translatable("widgets.widgets.keystrokes.colorBackgroundPressed"), 255, 255, 255, 80), - new RGBAColorWidgetSetting("bgunpressed", Text.translatable("widgets.widgets.keystrokes.colorBackgroundUnpressed"), 0, 0, 0, 80), - new ToggleWidgetSetting("rainbow", translatable("widgets.widgets.common.rainbow"), false), - new IntSliderWidgetSetting("rainbow_speed", translatable("widgets.widgets.common.rainbow.speed"), 1, 3, 10), - new RGBAColorWidgetSetting("keypressed", Text.translatable("widgets.widgets.keystrokes.colorKeyPressed"), 255, 255, 255, 255), - new RGBAColorWidgetSetting("keyunpressed", Text.translatable("widgets.widgets.keystrokes.colorKeyUnpressed"), 255, 255, 255, 255) + new GradientWidgetSetting("bgpressed", Text.translatable("widgets.widgets.keystrokes.colorBackgroundPressed"), 0x50ffffff), + new GradientWidgetSetting("bgunpressed", Text.translatable("widgets.widgets.keystrokes.colorBackgroundUnpressed"), 0x50000000), + new GradientWidgetSetting("keypressed", Text.translatable("widgets.widgets.keystrokes.colorKeyPressed"), 0xffffffff), + new GradientWidgetSetting("keyunpressed", Text.translatable("widgets.widgets.keystrokes.colorKeyUnpressed"), 0xffffffff) )); - getSettings().optionById("keypressed").setShowCondition(() -> !this.rainbow); - getSettings().optionById("keyunpressed").setShowCondition(() -> !this.rainbow); - getSettings().optionById("rainbow_speed").setShowCondition(() -> this.rainbow); } + private GradientOptions colorBackgroundPressed, colorBackgroundUnpressed, colorKeyUnpressed, colorKeyPressed; private boolean showJumpKey = true; - private int colorBackgroundPressed = new Color(255, 255, 255, 80).getRGB(), - colorBackgroundUnpressed = new Color(0, 0, 0, 80).getRGB(), - colorKeyUnpressed = 0xffffffff, - colorKeyPressed = 0xffffffff; - - protected boolean rainbow = false; - protected int rainbowSpeed = 3; - protected static class Key { protected final KeyBinding binding; protected boolean isPressed; @@ -78,49 +62,28 @@ public class KeyStrokesWidget extends ResizableWidget { if (showJumpKey) renderSpaceBar(context, measuringTimeNano, posX, posY + 44, KEY_JUMP); } - protected void renderSpaceBar(final DrawContext context, - final long measuringTimeNano, - final int posX, - final int posY, - final Key key){ - long l = measuringTimeNano - key.lastChanged; + protected void renderSpaceBar(final DrawContext context, long mt, int posX, int posY, Key key){ + long l = mt - key.lastChanged; if (l < 100000000){ - if (key.isPressed){ - context.fill(posX, posY, posX + 64, posY + 10, fadeColor(colorBackgroundUnpressed, colorBackgroundPressed, 0.00000001d * l)); - } else { - context.fill(posX, posY, posX + 64, posY + 10, fadeColor(colorBackgroundPressed, colorBackgroundUnpressed, 0.00000001d * l)); - } + double alpha = 0.00000001d * l; + colorBackgroundUnpressed.multiplyAlpha(key.isPressed ? 1-alpha : alpha).fillHorizontal(context, mt, posX, posY, posX + 64, posY + 10); + colorBackgroundPressed.multiplyAlpha(key.isPressed ? alpha : 1-alpha).fillHorizontal(context, mt, posX, posY, posX + 64, posY + 10); } else { - context.fill(posX, posY, posX + 64, posY + 10, key.isPressed ? colorBackgroundPressed : colorBackgroundUnpressed); + (key.isPressed ? colorBackgroundPressed : colorBackgroundUnpressed).fillHorizontal(context, mt, posX, posY, posX + 64, posY + 10); } - context.fill(posX + 5, posY + 4, posX + 59, posY + 5, rainbow ? BasicTextWidget.rainbowColor(measuringTimeNano, rainbowSpeed) : (key.isPressed ? colorKeyPressed : colorKeyUnpressed)); + (key.isPressed ? colorKeyPressed : colorKeyUnpressed).fillHorizontal(context, mt, posX + 5, posY + 4, posX + 59, posY + 5); } - protected void renderKeyStroke(final DrawContext context, - final TextRenderer textRenderer, - final long measuringTimeNano, - final int posX, - final int posY, - final KeyLarge key){ - long l = measuringTimeNano - key.lastChanged; + protected void renderKeyStroke(DrawContext context, TextRenderer textRenderer, long mt, int posX, int posY, KeyLarge key){ + long l = mt - key.lastChanged; if (l < 100000000){ - if (key.isPressed){ - context.fill(posX, posY, posX+20, posY+20, fadeColor(colorBackgroundUnpressed, colorBackgroundPressed, 0.00000001d * l)); - } else { - context.fill(posX, posY, posX+20, posY+20, fadeColor(colorBackgroundPressed, colorBackgroundUnpressed, 0.00000001d * l)); - } + double alpha = 0.00000001d * l; + colorBackgroundUnpressed.multiplyAlpha(key.isPressed ? 1-alpha : alpha).fillHorizontal(context, mt, posX, posY, posX + 20, posY + 20); + colorBackgroundPressed.multiplyAlpha(key.isPressed ? alpha : 1-alpha).fillHorizontal(context, mt, posX, posY, posX + 20, posY + 20); } else { - context.fill(posX, posY, posX+20, posY+20, key.isPressed ? colorBackgroundPressed : colorBackgroundUnpressed); + (key.isPressed ? colorBackgroundPressed : colorBackgroundUnpressed).fillHorizontal(context, mt, posX, posY, posX + 20, posY + 20); } - context.drawText(textRenderer, key.boundToKey, posX+10-(key.boundToLength/2), posY + 6, rainbow ? BasicTextWidget.rainbowColor(measuringTimeNano, rainbowSpeed) : (key.isPressed ? colorKeyPressed : colorKeyUnpressed), true); - } - - private int fadeColor(int color1, int color2, double delta) { - int alpha = (int) MathHelper.lerp(delta, (color1 >> 24) & 0xff, (color2 >> 24) & 0xff); - int red = (int) MathHelper.lerp(delta, (color1 >> 16) & 0xff, (color2 >> 16) & 0xff); - int green = (int) MathHelper.lerp(delta, (color1 >> 8) & 0xff, (color2 >> 8) & 0xff); - int blue = (int) MathHelper.lerp(delta, color1 & 0xff, color2 & 0xff); - return (alpha << 24) | (red << 16) | (green << 8) | blue; + (key.isPressed ? colorKeyPressed : colorKeyUnpressed).drawText(context, textRenderer, mt, key.boundToKey, posX+10-(key.boundToLength/2), posY+6, true); } @Override @@ -168,11 +131,9 @@ public class KeyStrokesWidget extends ResizableWidget { public void onSettingsChanged(WidgetSettings settings) { super.onSettingsChanged(settings); this.showJumpKey = (boolean) settings.optionById("showjump").getValue(); - this.colorBackgroundPressed = (int) settings.optionById("bgpressed").getValue(); - this.colorBackgroundUnpressed = (int) settings.optionById("bgunpressed").getValue(); - this.colorKeyPressed = (int) settings.optionById("keypressed").getValue(); - this.colorKeyUnpressed = (int) settings.optionById("keyunpressed").getValue(); - this.rainbow = (boolean) settings.optionById("rainbow").getValue(); - this.rainbowSpeed = (int) settings.optionById("rainbow_speed").getValue(); + this.colorBackgroundPressed = (GradientOptions) settings.optionById("bgpressed").getValue(); + this.colorBackgroundUnpressed = (GradientOptions) settings.optionById("bgunpressed").getValue(); + this.colorKeyPressed = (GradientOptions) settings.optionById("keypressed").getValue(); + this.colorKeyUnpressed = (GradientOptions) settings.optionById("keyunpressed").getValue(); } } diff --git a/src/main/java/de/shiewk/widgets/widgets/PingWidget.java b/src/main/java/de/shiewk/widgets/widgets/PingWidget.java index 8d73ad8..da2a76f 100644 --- a/src/main/java/de/shiewk/widgets/widgets/PingWidget.java +++ b/src/main/java/de/shiewk/widgets/widgets/PingWidget.java @@ -1,6 +1,7 @@ package de.shiewk.widgets.widgets; import de.shiewk.widgets.WidgetSettings; +import de.shiewk.widgets.color.GradientOptions; import de.shiewk.widgets.utils.WidgetUtils; import de.shiewk.widgets.widgets.settings.ToggleWidgetSetting; import net.minecraft.client.MinecraftClient; @@ -21,9 +22,7 @@ public class PingWidget extends BasicTextWidget { new ToggleWidgetSetting("dynamic_color", Text.translatable("widgets.widgets.ping.dynamicColor"), true), new ToggleWidgetSetting("hide_in_singleplayer", Text.translatable("widgets.widgets.common.hideInSingleplayer"), false) )); - getSettings().optionById("textcolor").setShowCondition(() -> !this.dynamicColor && !this.rainbow); - getSettings().optionById("rainbow").setShowCondition(() -> !this.dynamicColor); - getSettings().optionById("rainbow_speed").setShowCondition(() -> !this.dynamicColor && this.rainbow); + getSettings().optionById("textcolor").setShowCondition(() -> !this.dynamicColor); } private boolean dynamicColor = false; @@ -53,18 +52,18 @@ public class PingWidget extends BasicTextWidget { } if (valuesRead == 0){ formatAndSetRenderText(literal("??? ms")); - if (this.dynamicColor) this.textColor = 0xff00ff00; + if (this.dynamicColor) this.textColor = GradientOptions.solidColor(0xff00ff00); return; } long avgPing = ping / valuesRead; formatAndSetRenderText(literal(avgPing + " ms")); if (this.dynamicColor){ if (avgPing < 50){ - this.textColor = 0xff00ff00; + this.textColor = GradientOptions.solidColor(0xff00ff00); } else if (avgPing < 120) { - this.textColor = 0xffffff00; + this.textColor = GradientOptions.solidColor(0xffffff00); } else { - this.textColor = 0xffff3030; + this.textColor = GradientOptions.solidColor(0xffff3030); } } } diff --git a/src/main/java/de/shiewk/widgets/widgets/TPSWidget.java b/src/main/java/de/shiewk/widgets/widgets/TPSWidget.java index 9b7786e..a477c66 100644 --- a/src/main/java/de/shiewk/widgets/widgets/TPSWidget.java +++ b/src/main/java/de/shiewk/widgets/widgets/TPSWidget.java @@ -2,6 +2,7 @@ package de.shiewk.widgets.widgets; import de.shiewk.widgets.WidgetSettings; import de.shiewk.widgets.WidgetsMod; +import de.shiewk.widgets.color.GradientOptions; import de.shiewk.widgets.widgets.settings.IntSliderWidgetSetting; import de.shiewk.widgets.widgets.settings.ToggleWidgetSetting; import net.minecraft.client.MinecraftClient; @@ -22,9 +23,7 @@ public class TPSWidget extends BasicTextWidget { new ToggleWidgetSetting("dynamic_color", translatable("widgets.widgets.tps.dynamicColor"), true), new IntSliderWidgetSetting("window_size", translatable("widgets.widgets.tps.windowSize"), 2, 5, 20) )); - getSettings().optionById("textcolor").setShowCondition(() -> !this.dynamicColor && !this.rainbow); - getSettings().optionById("rainbow").setShowCondition(() -> !this.dynamicColor); - getSettings().optionById("rainbow_speed").setShowCondition(() -> !this.dynamicColor && this.rainbow); + getSettings().optionById("textcolor").setShowCondition(() -> !this.dynamicColor); } public static final TPSWidget INSTANCE = new TPSWidget(Identifier.of(WidgetsMod.MOD_ID, "tps")); @@ -86,7 +85,7 @@ public class TPSWidget extends BasicTextWidget { } else { formatAndSetRenderText(literal("???")); } - if (dynamicColor) this.textColor = 0xff00ff00; + if (dynamicColor) this.textColor = GradientOptions.solidColor(0xff00ff00); } else { tps = Math.round(tps * 10f) / 10f; if (showLabel){ @@ -96,11 +95,11 @@ public class TPSWidget extends BasicTextWidget { } if (dynamicColor){ if (tps >= targetTickRate * 0.990){ - this.textColor = 0xff00ff00; + this.textColor = GradientOptions.solidColor(0xff00ff00); } else if (tps >= targetTickRate * 0.740){ - this.textColor = 0xffffff00; + this.textColor = GradientOptions.solidColor(0xffffff00); } else { - this.textColor = 0xffff0000; + this.textColor = GradientOptions.solidColor(0xffff0000); } } } diff --git a/src/main/java/de/shiewk/widgets/widgets/settings/GradientWidgetSetting.java b/src/main/java/de/shiewk/widgets/widgets/settings/GradientWidgetSetting.java new file mode 100644 index 0000000..a1fb94b --- /dev/null +++ b/src/main/java/de/shiewk/widgets/widgets/settings/GradientWidgetSetting.java @@ -0,0 +1,129 @@ +package de.shiewk.widgets.widgets.settings; + +import com.google.gson.JsonElement; +import de.shiewk.widgets.client.screen.WidgetSettingsScreen; +import de.shiewk.widgets.client.screen.gradienteditor.GradientEditorScreen; +import de.shiewk.widgets.color.GradientMode; +import de.shiewk.widgets.color.GradientOptions; +import de.shiewk.widgets.utils.WidgetUtils; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.font.TextRenderer; +import net.minecraft.client.gui.Click; +import net.minecraft.client.gui.DrawContext; +import net.minecraft.client.gui.cursor.StandardCursors; +import net.minecraft.sound.SoundEvents; +import net.minecraft.text.Text; +import net.minecraft.util.Util; + +import static de.shiewk.widgets.client.WidgetManager.gson; +import static de.shiewk.widgets.utils.WidgetUtils.colorARGBToHexRGBA; + +public class GradientWidgetSetting extends WidgetSettingOption { + + public GradientWidgetSetting(String id, Text name, GradientMode defaultMode, int defaultGradientSize, int defaultGradientSpeed, int defaultColor) { + super(id, name); + this.value = new GradientOptions( + defaultMode, + defaultGradientSize, + defaultGradientSpeed, + new int[]{defaultColor} + ); + } + + public GradientWidgetSetting(String id, Text name, int defaultColor) { + this(id, name, GradientMode.SWEEP, 40, 10, defaultColor); + } + + private GradientOptions value; + + @Override + public JsonElement saveState() { + return gson.toJsonTree(getValue()); + } + + @Override + public void loadState(JsonElement state) { + if (state.isJsonPrimitive() && state.getAsJsonPrimitive().isNumber()){ + this.value = new GradientOptions( + this.value.mode(), + this.value.gradientSize(), + this.value.gradientSpeed(), + new int[]{ state.getAsInt() } + ); + } else { + this.value = gson.fromJson(state, GradientOptions.class); + } + } + + @Override + public GradientOptions getValue() { + return this.value; + } + + @Override + public void render(DrawContext context, int mouseX, int mouseY, float deltaTicks) { + final TextRenderer textRenderer = MinecraftClient.getInstance().textRenderer; + final long n = Util.getMeasuringTimeNano(); + GradientOptions gradient = this.getValue(); + gradient.fillHorizontal( + context, + n, + getX(), + getY(), + getX() + getWidth(), + getY() + getHeight() + ); + int outlineColor; + String displayText; + int[] colors = gradient.colors(); + if (colors.length == 1){ + outlineColor = colors[0] | 0xff_00_00_00; + displayText = "#" + colorARGBToHexRGBA(colors[0]); + } else { + outlineColor = 0xff_ff_ff_ff; + displayText = Text.translatable("widgets.ui.widgetSettings.colors", colors.length).getString(); + } + context.drawHorizontalLine(getX(), getX()+getWidth(), getY(), outlineColor); + context.drawHorizontalLine(getX(), getX()+getWidth(), getY()+getHeight(), outlineColor); + context.drawVerticalLine(getX(), getY(), getY() + getHeight(), outlineColor); + context.drawVerticalLine(getX() + getWidth(), getY(), getY() + getHeight(), outlineColor); + + int width = textRenderer.getWidth(displayText); + context.drawText( + textRenderer, + displayText, + getX() + (getWidth() / 2 - (width / 2)), + getY() + (getHeight() / 2 - 4), + 0xff_ff_ff_ff, + true + ); + + if (this.isHovered(mouseX, mouseY)){ + context.setCursor(StandardCursors.POINTING_HAND); + } + } + + @Override + public int getWidth() { + return 72; + } + + @Override + public int getHeight() { + return 24; + } + + @Override + public boolean mouseClicked(Click click, boolean doubled) { + MinecraftClient client = MinecraftClient.getInstance(); + if (client.currentScreen instanceof WidgetSettingsScreen screen) { + WidgetUtils.playSound(SoundEvents.BLOCK_COPPER_BULB_TURN_ON); + client.setScreen(new GradientEditorScreen(client.currentScreen, screen.getWidget(), this, screen.getOnChange())); + } + return true; + } + + public void setValue(GradientOptions value) { + this.value = value; + } +} diff --git a/src/main/java/de/shiewk/widgets/widgets/settings/RGBAColorWidgetSetting.java b/src/main/java/de/shiewk/widgets/widgets/settings/RGBAColorWidgetSetting.java index 69e975f..01694c5 100644 --- a/src/main/java/de/shiewk/widgets/widgets/settings/RGBAColorWidgetSetting.java +++ b/src/main/java/de/shiewk/widgets/widgets/settings/RGBAColorWidgetSetting.java @@ -2,6 +2,7 @@ package de.shiewk.widgets.widgets.settings; import com.google.gson.JsonElement; import com.google.gson.JsonPrimitive; +import de.shiewk.widgets.client.screen.WidgetVisibilityToggle; import de.shiewk.widgets.utils.WidgetUtils; import net.minecraft.client.MinecraftClient; import net.minecraft.client.font.TextRenderer; @@ -19,6 +20,10 @@ import org.jetbrains.annotations.NotNull; import java.awt.*; +/** + * @deprecated Use {@link GradientWidgetSetting} + */ +@Deprecated(forRemoval = true, since = "2.3.0") public class RGBAColorWidgetSetting extends WidgetSettingOption { public RGBAColorWidgetSetting(String id, Text name, int defaultR, int defaultG, int defaultB, int defaultAlpha) { super(id, name); @@ -118,7 +123,7 @@ public class RGBAColorWidgetSetting extends WidgetSettingOption { return true; } - public class ChangeScreen extends Screen { + public class ChangeScreen extends Screen implements WidgetVisibilityToggle { private final Screen parent; private int x; @@ -205,6 +210,11 @@ public class RGBAColorWidgetSetting extends WidgetSettingOption { return super.mouseClicked(click, doubled); } + @Override + public boolean shouldRenderWidgets() { + return false; + } + public class ColorBar extends ClickableWidget { private final int component; diff --git a/src/main/java/de/shiewk/widgets/widgets/settings/WidgetSettingOption.java b/src/main/java/de/shiewk/widgets/widgets/settings/WidgetSettingOption.java index aad88d9..303d1b3 100644 --- a/src/main/java/de/shiewk/widgets/widgets/settings/WidgetSettingOption.java +++ b/src/main/java/de/shiewk/widgets/widgets/settings/WidgetSettingOption.java @@ -14,6 +14,7 @@ import java.util.function.BooleanSupplier; import java.util.function.Consumer; public abstract class WidgetSettingOption implements Drawable, Widget { + private final String id; private final Text name; private int x = 0; diff --git a/src/main/resources/assets/widgets/lang/de_de.json b/src/main/resources/assets/widgets/lang/de_de.json index b76c3d0..f029dec 100644 --- a/src/main/resources/assets/widgets/lang/de_de.json +++ b/src/main/resources/assets/widgets/lang/de_de.json @@ -1,6 +1,11 @@ { + "widgets.gradient.preset.rainbow": "Regenbogen", + "widgets.gradient.pulse": "Pulse", + "widgets.gradient.pulse.description": "Färbt Text oder Oberfläche mit einer einzelnen Farbe und geht dabei zwischen den ausgewählten Farben über", + "widgets.gradient.sweep": "Sweep", + "widgets.gradient.sweep.description": "Färbt Text oder Oberfläche mit einem sich bewegenden Farbverlauf", "widgets.key.category": "Widgets", - "widgets.key.config": "Öffne Widgets-Einstellungen", + "widgets.key.config": "Widgets-Einstellungen öffnen", "widgets.ui.anchor.bottom_center": "Unten mittig", "widgets.ui.anchor.bottom_left": "Unten links", "widgets.ui.anchor.bottom_right": "Unten rechts", @@ -20,9 +25,24 @@ "widgets.ui.editPositions.snap": "Positionen ausrichten: %s", "widgets.ui.editPositions.snap.help": "Richtet die Position des Widgets mit Positionen der anderen Widgets aus", "widgets.ui.enabled": "Aktiviert", + "widgets.ui.gradientEditor": "Farbe bearbeiten", + "widgets.ui.gradientEditor.colors": "Dieser Verlauf:", + "widgets.ui.gradientEditor.colors.add.tooltip.0": "Diesem Farbverlauf eine Farbe hinzufügen", + "widgets.ui.gradientEditor.colors.add.tooltip.1": "(Bleibe bei einer Farbe, um den Farbverlauf zu deaktivieren)", + "widgets.ui.gradientEditor.editColor": "Farbe bearbeiten:", + "widgets.ui.gradientEditor.editColor.orPick": "Alternative Auswahl:", + "widgets.ui.gradientEditor.gradientSettings": "Verlaufsoptionen:", + "widgets.ui.gradientEditor.gradientSettings.addMoreColors": "Füge mindestens zwei Farben hinzu, um den Farbverlauf zu bearbeiten.", + "widgets.ui.gradientEditor.importOther": "Von Widget importieren", + "widgets.ui.gradientEditor.mode": "Modus: %s", + "widgets.ui.gradientEditor.removeColor": "Farbe entfernen", + "widgets.ui.gradientEditor.size": "Größe: %s%%", + "widgets.ui.gradientEditor.speed": "Geschwindigkeit: %s%%", + "widgets.ui.gradientEditor.usePreset": "Voreinstellung nutzen", "widgets.ui.preview": "Vorschau", "widgets.ui.search": "Suchen...", "widgets.ui.widgetSettings": "Bearbeite %s Einstellungen", + "widgets.ui.widgetSettings.colors": "%s Farben", "widgets.widgets.armorHud": "Rüstungsstatus", "widgets.widgets.armorHud.description": "Zeigt die Rüstung, die du gerade trägst, und ihre Haltbarkeit.", "widgets.widgets.armorHud.durabilityStyle": "Haltbarkeitsstil", @@ -31,7 +51,7 @@ "widgets.widgets.armorHud.padding": "Abstand", "widgets.widgets.armorHud.showDurability": "Haltbarkeitsbeschriftung anzeigen", "widgets.widgets.bandwidth": "Bandbreite", - "widgets.widgets.bandwidth.description": "Zeigt, wie viele Daten an den aktuell Server gesendet werden/vom Server an den Klient gesendet werden.", + "widgets.widgets.bandwidth.description": "Zeigt, wie viele Daten aktuell vom Server an den Klienten gesendet werden.", "widgets.widgets.bandwidth.dynamicColor": "Farbe dynamisch anzeigen", "widgets.widgets.bandwidth.fastupdate": "Schnelle Aktualisierung", "widgets.widgets.bandwidth.unit": "Einheit", @@ -70,8 +90,6 @@ "widgets.widgets.combo.description": "Zeigt deine momentane Combo an", "widgets.widgets.combo.displayThreshold": "Minimum sichtbar", "widgets.widgets.common.hideInSingleplayer": "In Einzelspielerwelten verbergen", - "widgets.widgets.common.rainbow": "Regenbogen-Text", - "widgets.widgets.common.rainbow.speed": "Regenbogengeschwindigkeit", "widgets.widgets.common.realtime": "Echtzeit-Update (braucht mehr Leistung)", "widgets.widgets.common.showLabel": "Beschriftung anzeigen", "widgets.widgets.common.sizePercent": "Widgetgröße (%)", @@ -101,8 +119,6 @@ "widgets.widgets.inventory.mode.texture_pack": "Texturenpaket", "widgets.widgets.inventory.mode.transparent": "Transparent", "widgets.widgets.inventory.mode.vanilla": "Standard", - "widgets.widgets.inventory.rainbowBoxes": "Regenbogenzellen", - "widgets.widgets.inventory.rainbowGrid": "Regenbogengitter", "widgets.widgets.inventory.showHotbar": "Schnellzugriffsleiste anzeigen", "widgets.widgets.keystrokes": "Keystrokes", "widgets.widgets.keystrokes.colorBackgroundPressed": "Hintergrundfarbe (Taste gedrückt)", diff --git a/src/main/resources/assets/widgets/lang/en_us.json b/src/main/resources/assets/widgets/lang/en_us.json index 9b4b852..47d6577 100644 --- a/src/main/resources/assets/widgets/lang/en_us.json +++ b/src/main/resources/assets/widgets/lang/en_us.json @@ -1,4 +1,9 @@ { + "widgets.gradient.preset.rainbow": "Rainbow", + "widgets.gradient.pulse": "Pulse", + "widgets.gradient.pulse.description": "Paints the text or surface with one solid color, cycling through your selected palette", + "widgets.gradient.sweep": "Sweep", + "widgets.gradient.sweep.description": "Paints the text or surface with a moving gradient", "widgets.key.category": "Widgets", "widgets.key.config": "Open Widget Management", "widgets.ui.anchor.bottom_center": "Bottom center", @@ -20,9 +25,24 @@ "widgets.ui.editPositions.snap": "Align positions: %s", "widgets.ui.editPositions.snap.help": "Aligns the widget with positions of other widgets", "widgets.ui.enabled": "Enabled", + "widgets.ui.gradientEditor": "Color editor", + "widgets.ui.gradientEditor.colors": "This gradient:", + "widgets.ui.gradientEditor.colors.add.tooltip.0": "Add a color to this gradient", + "widgets.ui.gradientEditor.colors.add.tooltip.1": "(Leave this as one color to disable the gradient)", + "widgets.ui.gradientEditor.editColor": "Edit color:", + "widgets.ui.gradientEditor.editColor.orPick": "Alternative picker:", + "widgets.ui.gradientEditor.gradientSettings": "Gradient settings:", + "widgets.ui.gradientEditor.gradientSettings.addMoreColors": "Add more than one color to customize the gradient", + "widgets.ui.gradientEditor.importOther": "Import from widget", + "widgets.ui.gradientEditor.mode": "Mode: %s", + "widgets.ui.gradientEditor.removeColor": "Remove color", + "widgets.ui.gradientEditor.size": "Size: %s%%", + "widgets.ui.gradientEditor.speed": "Speed: %s%%", + "widgets.ui.gradientEditor.usePreset": "Use preset", "widgets.ui.preview": "Preview", "widgets.ui.search": "Search...", "widgets.ui.widgetSettings": "Edit %s settings", + "widgets.ui.widgetSettings.colors": "%s colors", "widgets.widgets.armorHud": "Armor Status", "widgets.widgets.armorHud.description": "Shows the armor you are currently wearing and its durability.", "widgets.widgets.armorHud.durabilityStyle": "Durability style", @@ -31,7 +51,7 @@ "widgets.widgets.armorHud.padding": "Padding", "widgets.widgets.armorHud.showDurability": "Show durability label", "widgets.widgets.bandwidth": "Bandwidth", - "widgets.widgets.bandwidth.description": "Shows how much data is being read/sent from the server you're connected to.", + "widgets.widgets.bandwidth.description": "Shows how much data the server you're connected to is sending.", "widgets.widgets.bandwidth.dynamicColor": "Dynamic Color", "widgets.widgets.bandwidth.fastupdate": "Fast update", "widgets.widgets.bandwidth.unit": "Unit", @@ -70,8 +90,6 @@ "widgets.widgets.combo.description": "Shows your current Combo.", "widgets.widgets.combo.displayThreshold": "Display Threshold", "widgets.widgets.common.hideInSingleplayer": "Hide in singleplayer worlds", - "widgets.widgets.common.rainbow": "Rainbow text", - "widgets.widgets.common.rainbow.speed": "Rainbow speed", "widgets.widgets.common.realtime": "Real-time updating (may use more performance)", "widgets.widgets.common.showLabel": "Show label", "widgets.widgets.common.sizePercent": "Widget size (%)", @@ -101,8 +119,6 @@ "widgets.widgets.inventory.mode.texture_pack": "Texture pack", "widgets.widgets.inventory.mode.transparent": "Transparent", "widgets.widgets.inventory.mode.vanilla": "Vanilla", - "widgets.widgets.inventory.rainbowBoxes": "Rainbow boxes", - "widgets.widgets.inventory.rainbowGrid": "Rainbow Grid", "widgets.widgets.inventory.showHotbar": "Show hotbar", "widgets.widgets.keystrokes": "Keystrokes", "widgets.widgets.keystrokes.colorBackgroundPressed": "Background color (key pressed)", diff --git a/src/main/resources/assets/widgets/textures/gui/arrow_down.png b/src/main/resources/assets/widgets/textures/gui/arrow_down.png new file mode 100644 index 0000000000000000000000000000000000000000..e7bcf166f642d0f5d85abb28d8d9ca3ab60da77c GIT binary patch literal 511 zcmVEX>4Tx04R~2kg-a`P!xv0R8f)YqBy8S2GOabnH;PNK~RXXg4HQaQYo|GgJlb`qxL>^`JfRk(h)f7!pX=ig|v!7@8+ z2Vt3aJ@16Z^ZANp^rd6Gn&ZhRv>@CgbqO)7+*VXBX$DuiC`rm{UA#28Kx&)D|IOdxThqPCdBGZ zG*fXSD&^#IAnJ*9n})pgI?q$eKprD`nS?u1d73=T|9-E1oYkAw+B6S}pl;2mTEii{ zKf+QUR-R$;x*==f_uCp~oOyy+779H*NB{r;8FWQhbVF}#ZDnqB07G(R zVRU6=Aa`kWXdp*PO;A^X4i^9b06a-VK~yNuV_+Z+{Qs}}A60~jkd_gm03JZ-02W|S z6T%r$HRv&DqKPnsF(B&>!)6Uk2@YwP50@?kEP)kdg0003aX+uL$Nkc;* zaB^>EX>4Tx04R~2kg-a`P!xv0R8f)YqBy8S2GOabnH;PNK~RXXg4HQaQYo|GgJlb`qxL>^`JfRk(h)f7!pX=ig|v!7@8+ z2Vt3aJ@16Z^ZANp^rd6Gn&ZhRv>@CgbqO)7+*VXBX$DuiC`rm{UA#28Kx&)D|IOdxThqPCdBGZ zG*fXSD&^#IAnJ*9n})pgI?q$eKprD`nS?u1d73=T|9-E1oYkAw+B6S}pl;2mTEii{ zKf+QUR-R$;x*==f_uCp~oOyy+1&)J!mH+?%h)G02R7l6=Ra*{#APnma z*TMUr0}oU`20~&$*}la6kPup$?gcnQ^dJpT0f3|2w=>Px# literal 0 HcmV?d00001