From 7008dfb9c79462d89b7e23462e8c126acf63c6ff Mon Sep 17 00:00:00 2001 From: Kat Date: Fri, 17 Jul 2026 02:28:21 -0400 Subject: [PATCH 1/9] Feat: Color Picker rewrite & alpha slider/presets I would have waited longer to commit this, but there is a Windows update and I'm afraid of it destroying my progress --- .../ingame/ColorPickerIncludedScreen.java | 68 +- .../gui/screen/ingame/NoteEditScreen.java | 60 +- .../screen/ingame/SpriteBlockEditScreen.java | 23 +- .../screen/ingame/TextBlockEditScreen.java | 204 ++-- .../gui/screen/ingame/TextEditorScreen.java | 38 +- .../gui/widget/ingame/ColorPickerWidget.java | 607 ----------- .../gui/widget/ingame/ColorPresetWidget.java | 24 +- .../widget/ingame/color/HexColorEditBox.java | 153 +++ .../ingame/color/functional/ColorGetter.java | 5 + .../ingame/color/functional/ColorSetter.java | 5 + .../functional/PickerPresetListener.java | 7 + .../color/picker/ColorPickerWidget.java | 999 ++++++++++++++++++ .../ingame/color/picker/PickerArea.java | 155 +++ .../ingame/color/picker/PickerPreset.java | 86 ++ .../glowcase/client/util/ColorUtil.java | 130 +++ .../glowcase/client/util/GuiGraphicsUtil.java | 92 ++ .../resources/assets/glowcase/lang/en_us.json | 4 +- .../gui/sprites/color_picker/alpha_preset.png | Bin 0 -> 117 bytes .../color_picker/alpha_preset.png.mcmeta | 10 + .../sprites/color_picker/alpha_preview.png | Bin 0 -> 117 bytes .../color_picker/alpha_preview.png.mcmeta | 10 + .../gui/sprites/color_picker/alpha_slider.png | Bin 0 -> 117 bytes .../color_picker/alpha_slider.png.mcmeta | 10 + .../gui/sprites/color_picker/alpha_thumb.png | Bin 0 -> 117 bytes .../color_picker/alpha_thumb.png.mcmeta | 10 + 25 files changed, 1932 insertions(+), 768 deletions(-) delete mode 100644 src/main/java/dev/hephaestus/glowcase/client/gui/widget/ingame/ColorPickerWidget.java create mode 100644 src/main/java/dev/hephaestus/glowcase/client/gui/widget/ingame/color/HexColorEditBox.java create mode 100644 src/main/java/dev/hephaestus/glowcase/client/gui/widget/ingame/color/functional/ColorGetter.java create mode 100644 src/main/java/dev/hephaestus/glowcase/client/gui/widget/ingame/color/functional/ColorSetter.java create mode 100644 src/main/java/dev/hephaestus/glowcase/client/gui/widget/ingame/color/functional/PickerPresetListener.java create mode 100644 src/main/java/dev/hephaestus/glowcase/client/gui/widget/ingame/color/picker/ColorPickerWidget.java create mode 100644 src/main/java/dev/hephaestus/glowcase/client/gui/widget/ingame/color/picker/PickerArea.java create mode 100644 src/main/java/dev/hephaestus/glowcase/client/gui/widget/ingame/color/picker/PickerPreset.java create mode 100644 src/main/java/dev/hephaestus/glowcase/client/util/GuiGraphicsUtil.java create mode 100644 src/main/resources/assets/glowcase/textures/gui/sprites/color_picker/alpha_preset.png create mode 100644 src/main/resources/assets/glowcase/textures/gui/sprites/color_picker/alpha_preset.png.mcmeta create mode 100644 src/main/resources/assets/glowcase/textures/gui/sprites/color_picker/alpha_preview.png create mode 100644 src/main/resources/assets/glowcase/textures/gui/sprites/color_picker/alpha_preview.png.mcmeta create mode 100644 src/main/resources/assets/glowcase/textures/gui/sprites/color_picker/alpha_slider.png create mode 100644 src/main/resources/assets/glowcase/textures/gui/sprites/color_picker/alpha_slider.png.mcmeta create mode 100644 src/main/resources/assets/glowcase/textures/gui/sprites/color_picker/alpha_thumb.png create mode 100644 src/main/resources/assets/glowcase/textures/gui/sprites/color_picker/alpha_thumb.png.mcmeta diff --git a/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/ColorPickerIncludedScreen.java b/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/ColorPickerIncludedScreen.java index 531b9f90..f4560423 100644 --- a/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/ColorPickerIncludedScreen.java +++ b/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/ColorPickerIncludedScreen.java @@ -1,11 +1,73 @@ package dev.hephaestus.glowcase.client.gui.screen.ingame; -import dev.hephaestus.glowcase.client.gui.widget.ingame.ColorPickerWidget; +import dev.hephaestus.glowcase.client.gui.widget.ingame.color.picker.ColorPickerWidget; import net.minecraft.ChatFormatting; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.components.AbstractWidget; +import net.minecraft.client.gui.components.events.GuiEventListener; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.input.KeyEvent; +import net.minecraft.client.input.MouseButtonEvent; +import org.lwjgl.glfw.GLFW; +/** + * Main interface for any Screen wishing to implement a {@link ColorPickerWidget}.

+ * Each ColorPickerIncludedScreen has *one* Color Picker widget which gets shared among all things using it. + */ public interface ColorPickerIncludedScreen { - ColorPickerWidget colorPickerWidget(); - void toggleColorPicker(boolean active); + ColorPickerWidget getColorPickerWidget(); + + default boolean mouseClickedColorPicker(MouseButtonEvent event, boolean doubleClick) { + double mouseX = event.x(); + double mouseY = event.y(); + ColorPickerWidget colorPickerWidget = this.getColorPickerWidget(); + + if (colorPickerWidget.isActive() && colorPickerWidget.visible) { + if (colorPickerWidget.isMouseOver(mouseX, mouseY)) { + colorPickerWidget.mouseClicked(event, doubleClick); + Screen self = (Screen) this; + self.setFocused(colorPickerWidget); + self.setDragging(true); + return true; + } else if (colorPickerWidget.targetElement == null || !colorPickerWidget.targetElement.isMouseOver(mouseX, mouseY)) { + this.hideColorPickerWidget(); + } + } + return false; + } + + default boolean keyPressedColorPicker(KeyEvent event) { + int keyCode = event.key(); + ColorPickerWidget colorPickerWidget = this.getColorPickerWidget(); + if (colorPickerWidget.isActive()) { + Screen self = (Screen) this; + switch (keyCode) { + case GLFW.GLFW_KEY_ENTER, GLFW.GLFW_KEY_KP_ENTER -> colorPickerWidget.hide(); + case GLFW.GLFW_KEY_ESCAPE -> colorPickerWidget.cancel(); + default -> { + GuiEventListener pickerTarget = colorPickerWidget.targetElement; + if (pickerTarget != null) { + self.setFocused(pickerTarget); + pickerTarget.keyPressed(event); + return true; + } + } + } + self.setFocused(null); + return true; + } + return false; + } + +// default void setColorPickerTarget(GuiEventListener element) { +// this.getColorPickerWidget().target(element); +// } + + default void hideColorPickerWidget() { + this.getColorPickerWidget().hide(); + } + + // TODO - break this into FormattableScreen void insertHexTag(String hex); void insertFormattingTag(ChatFormatting formatting); } diff --git a/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/NoteEditScreen.java b/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/NoteEditScreen.java index 6e8d6253..09313845 100644 --- a/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/NoteEditScreen.java +++ b/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/NoteEditScreen.java @@ -2,7 +2,7 @@ import com.mojang.datafixers.util.Pair; import dev.hephaestus.glowcase.Glowcase; -import dev.hephaestus.glowcase.client.gui.widget.ingame.ColorPickerWidget; +import dev.hephaestus.glowcase.client.gui.widget.ingame.color.picker.ColorPickerWidget; import dev.hephaestus.glowcase.client.util.NoteTextColorResource; import dev.hephaestus.glowcase.item.component.NoteComponent; import dev.hephaestus.glowcase.packet.C2SEditNoteItem; @@ -67,7 +67,7 @@ public class NoteEditScreen extends TextEditorScreen { private boolean finalizing = false; private List signing_text; - private ColorPickerWidget colorPickerWidget; +// private ColorPickerWidget colorPickerWidget; private Button doneButton; private Button signButton; private Button changeAlignment; @@ -187,10 +187,10 @@ protected void init() { }).bounds(width / 2 + BG_WIDTH / 2 - (BG_WIDTH / 2 - 3), height / 2 + BG_HEIGHT / 2 + offset, BG_WIDTH / 2 - 3, 20).build(); - this.colorPickerWidget = ColorPickerWidget.builder(this, 216, 10).size(182, 104).build(); - this.colorPickerWidget.toggle(false); //start deactivated +// this.colorPickerWidget = ColorPickerWidget.builder(this, 216, 10).size(182, 104).build(); +// this.colorPickerWidget.toggle(false); //start deactivated - this.addRenderableWidget(colorPickerWidget); +// this.addRenderableWidget(colorPickerWidget); addRenderableWidget(changeAlignment); addRenderableWidget(doneButton); @@ -347,12 +347,13 @@ public boolean keyPressed(KeyEvent event) { boolean result; int keyCode = event.key(); - if (this.colorPickerWidget.active && (keyCode == GLFW.GLFW_KEY_ENTER || keyCode == GLFW.GLFW_KEY_ESCAPE)) { - if (keyCode == GLFW.GLFW_KEY_ENTER) { - this.colorPickerWidget.confirmColor(); - } else { - this.colorPickerWidget.cancel(); - } +// if (this.colorPickerWidget.active && (keyCode == GLFW.GLFW_KEY_ENTER || keyCode == GLFW.GLFW_KEY_ESCAPE)) { + if (false) { +// if (keyCode == GLFW.GLFW_KEY_ENTER) { +// this.colorPickerWidget.confirmColor(); +// } else { +// this.colorPickerWidget.cancel(); +// } result = true; } else { setFocused(null); @@ -444,18 +445,18 @@ public boolean charTyped(CharacterEvent event) { public boolean mouseClicked(MouseButtonEvent event, boolean doubleClick) { double mouseX = event.x(); double mouseY = event.y(); - if (colorPickerWidget.active && colorPickerWidget.visible) { - if (colorPickerWidget.isMouseOver(mouseX, mouseY)) { - colorPickerWidget.mouseClicked(event, doubleClick); - this.setFocused(colorPickerWidget); - this.setDragging(true); - return true; - } else { - if (!this.colorPickerWidget.targetElement.isMouseOver(mouseX, mouseY)) { - toggleColorPicker(false); - } - } - } +// if (colorPickerWidget.active && colorPickerWidget.visible) { +// if (colorPickerWidget.isMouseOver(mouseX, mouseY)) { +// colorPickerWidget.mouseClicked(event, doubleClick); +// this.setFocused(colorPickerWidget); +// this.setDragging(true); +// return true; +// } else { +//// if (!this.colorPickerWidget.targetElement.isMouseOver(mouseX, mouseY)) { +//// toggleColorPicker(false); +//// } +// } +// } boolean withinX = (mouseX >= width / 2f - BG_WIDTH / 2f && mouseX <= width / 2f + BG_WIDTH / 2f); boolean withinY = (mouseY >= height / 2f - BG_HEIGHT / 2f && mouseY <= height / 2f + BG_HEIGHT / 2f); @@ -597,14 +598,15 @@ public CustomPacketPayload getUpdatePayload() { } @Override - public ColorPickerWidget colorPickerWidget() { - return colorPickerWidget; + public ColorPickerWidget getColorPickerWidget() { +// return colorPickerWidget; + return null; } - @Override - public void toggleColorPicker(boolean active) { - colorPickerWidget.toggle(active); - } +// @Override +// public void toggleColorPickerWidget(boolean active) { +//// colorPickerWidget.toggle(active); +// } @Override TextFieldHelper getSelectionManager() { diff --git a/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/SpriteBlockEditScreen.java b/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/SpriteBlockEditScreen.java index 4e0a0ea9..ff43a249 100644 --- a/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/SpriteBlockEditScreen.java +++ b/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/SpriteBlockEditScreen.java @@ -4,6 +4,7 @@ import dev.hephaestus.glowcase.block.entity.TextBlockEntity; import dev.hephaestus.glowcase.client.gui.widget.ingame.GlowcaseEditBox; import dev.hephaestus.glowcase.client.gui.widget.ingame.SuggestionListWidget; +import dev.hephaestus.glowcase.client.gui.widget.ingame.color.HexColorEditBox; import dev.hephaestus.glowcase.packet.C2SEditSpriteBlock; import net.fabricmc.loader.api.FabricLoader; import net.minecraft.client.gui.GuiGraphicsExtractor; @@ -29,7 +30,7 @@ public class SpriteBlockEditScreen extends BlockEditorScreen private Button spriteWidgetHelpButton; private Button rotationWidget; private Button zOffsetToggle; - private EditBox colorEntryWidget; + private HexColorEditBox colorEntryWidget; private EditBox scaleEntryWidget; private List spriteHelpTooltipText; @@ -73,13 +74,19 @@ public void init() { this.zOffsetToggle.setMessage(Component.literal(this.blockEntity.zOffset.name())); }).bounds(width / 2 - 90, height / 2 + 5, 180, 20).build(); - this.colorEntryWidget = new EditBox(this.minecraft.font, width / 2 - 90, height / 2 + 35, 180, 20, Component.empty()); - this.colorEntryWidget.setValue("#" + String.format("%1$06X", this.blockEntity.color & 0x00FFFFFF)); - this.colorEntryWidget.setResponder(string -> { - TextColor.parseColor(this.colorEntryWidget.getValue()).ifSuccess(color -> { - this.blockEntity.color = color == null ? 0xFFFFFFFF : color.getValue() | 0xFF000000; - }); - }); + this.colorEntryWidget = HexColorEditBox.builder(this.minecraft.font, width / 2 - 90, height / 2 + 35, + () -> this.blockEntity.color, color -> this.blockEntity.color = color + ) + .setWidth(180) + .build(); + +// this.colorEntryWidget = new EditBox(this.minecraft.font, width / 2 - 90, height / 2 + 35, 180, 20, Component.empty()); +// this.colorEntryWidget.setValue("#" + String.format("%1$06X", this.blockEntity.color & 0x00FFFFFF)); +// this.colorEntryWidget.setResponder(string -> { +// TextColor.parseColor(this.colorEntryWidget.getValue()).ifSuccess(color -> { +// this.blockEntity.color = color == null ? 0xFFFFFFFF : color.getValue() | 0xFF000000; +// }); +// }); this.scaleEntryWidget = new EditBox(this.minecraft.font, width / 2 - 90, height / 2 + 65, 180, 20, Component.empty()); this.scaleEntryWidget.setValue(String.valueOf(this.blockEntity.scale)); diff --git a/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/TextBlockEditScreen.java b/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/TextBlockEditScreen.java index 412db662..d8fe7929 100644 --- a/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/TextBlockEditScreen.java +++ b/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/TextBlockEditScreen.java @@ -1,7 +1,8 @@ package dev.hephaestus.glowcase.client.gui.screen.ingame; import dev.hephaestus.glowcase.block.entity.TextBlockEntity; -import dev.hephaestus.glowcase.client.gui.widget.ingame.ColorPickerWidget; +import dev.hephaestus.glowcase.client.gui.widget.ingame.color.HexColorEditBox; +import dev.hephaestus.glowcase.client.gui.widget.ingame.color.picker.ColorPickerWidget; import dev.hephaestus.glowcase.client.gui.widget.ingame.GlowcaseEditBox; import dev.hephaestus.glowcase.client.util.ColorUtil; import dev.hephaestus.glowcase.packet.C2SEditTextBlock; @@ -37,14 +38,15 @@ public class TextBlockEditScreen extends TextEditorScreen implements BlockEditor private final TextBlockEntity textBlockEntity; private List textWidgets; - private List colorListeners; +// private List colorListeners; private TextFieldHelper selectionManager; - private EditBox colorEntryWidget; + private HexColorEditBox colorEntryWidget; private int currentRow; private long ticksSinceOpened = 0; private ColorPickerWidget colorPickerWidget; - private Color colorEntryPreColorPicker; //used for color picker cancel button +// private ColorPickerWidget colorPickerWidget; +// private Color colorEntryPreColorPicker; // used for color picker cancel button public TextBlockEditScreen(TextBlockEntity textBlockEntity) { this.textBlockEntity = textBlockEntity; @@ -69,24 +71,42 @@ public void init() { var scaleSlider = new TextScale.SliderWidget(textBlockEntity, middle - 203, innerPadding, 113, 20); addFormattingButtons(middle - 90 + 6, innerPadding, 0, 20, 2); - this.colorEntryWidget = new EditBox(this.minecraft.font, middle + 54, innerPadding, 64, 20, Component.empty()); - this.colorEntryWidget.setTooltip(Tooltip.create(Component.translatable("gui.glowcase.color"))); - this.colorEntryWidget.setValue(ColorUtil.toAlphaHex(this.textBlockEntity.color)); - this.colorEntryWidget.setResponder(string -> { - ColorUtil.parse(string, this.textBlockEntity.color).ifSuccess(newColor -> { - final int color = (Math.max(newColor >>> 24, 0x1A) << 24) | (newColor & ColorUtil.RGB_MASK); - - this.textBlockEntity.color = color; - // make sure it doesn't update from the color picker updating the text - if (this.colorEntryWidget.isFocused()) { - this.colorPickerWidget.setColor(new Color(color)); + this.colorPickerWidget = ColorPickerWidget.builder(this).build(); + +// this.colorEntryWidget = new HexColorEditBox(this.minecraft.font, middle + 54, innerPadding, 64, 20, +// true, this.colorPickerWidget, () -> this.textBlockEntity.color, color -> this.textBlockEntity.color = color +// ); + this.colorEntryWidget = HexColorEditBox.builder(this.minecraft.font, middle + 54, innerPadding, + () -> this.textBlockEntity.color, color -> { + this.textBlockEntity.color = color; + this.textBlockEntity.rebake(true); } - this.textBlockEntity.rebake(true); - }); - }); + ) + .setEditableAlpha(true) + .setColorPickerWidget(this.colorPickerWidget) + .build(); + this.colorEntryWidget.setTooltip(Tooltip.create(Component.translatable("gui.glowcase.color"))); + + +// this.colorEntryWidget = new EditBox(this.minecraft.font, middle + 54, innerPadding, 64, 20, Component.empty()); +// this.colorEntryWidget.setTooltip(Tooltip.create(Component.translatable("gui.glowcase.color"))); +// this.colorEntryWidget.setValue(ColorUtil.toAlphaHex(this.textBlockEntity.color)); +// this.colorEntryWidget.setResponder(string -> { +// ColorUtil.parse(string, this.textBlockEntity.color).ifSuccess(newColor -> { +// final int color = (Math.max(newColor >>> 24, 0x1A) << 24) | (newColor & ColorUtil.RGB_MASK); +// +// this.textBlockEntity.color = color; +// // make sure it doesn't update from the color picker updating the text +// if (this.colorEntryWidget.isFocused()) { +// this.colorPickerWidget.setColor(new Color(color)); +// } +// this.textBlockEntity.rebake(true); +// }); +// }); - this.colorPickerWidget = ColorPickerWidget.builder(this, 216, 10).size(182, 104).build(); - this.colorPickerWidget.toggle(false); //start deactivated + +// this.colorPickerWidget = ColorPickerWidget.builder(this, 216, 10).size(182, 104).build(); +// this.colorPickerWidget.toggle(false); //start deactivated var moreOptionsButton = Button.builder( Component.translatable("gui.glowcase.more"), @@ -101,9 +121,9 @@ public void init() { this.colorEntryWidget ); - this.colorListeners = List.of( - this.colorEntryWidget - ); +// this.colorListeners = List.of( +// this.colorEntryWidget +// ); this.addRenderableWidget(colorPickerWidget); this.addRenderableWidget(this.colorEntryWidget); @@ -216,31 +236,35 @@ public boolean charTyped(CharacterEvent event) { public boolean keyPressed(KeyEvent event) { var keyCode = event.key(); - if (this.colorPickerWidget.active) { - switch (keyCode) { - case GLFW.GLFW_KEY_ENTER, GLFW.GLFW_KEY_KP_ENTER -> this.colorPickerWidget.confirmColor(); - case GLFW.GLFW_KEY_ESCAPE -> this.colorPickerWidget.cancel(); - default -> { - final GuiEventListener listener = this.colorPickerWidget.targetElement; - if (listener != null) { - this.setFocused(listener); - return listener.keyPressed(event); - } - } - } - - this.toggleColorPicker(false); - this.setFocused(null); - + if (this.keyPressedColorPicker(event)) { return true; } +// if (this.colorPickerWidget.active) { +// switch (keyCode) { +// case GLFW.GLFW_KEY_ENTER, GLFW.GLFW_KEY_KP_ENTER -> this.colorPickerWidget.confirmColor(); +// case GLFW.GLFW_KEY_ESCAPE -> this.colorPickerWidget.cancel(); +// default -> { +// final GuiEventListener listener = this.colorPickerWidget.targetElement; +// if (listener != null) { +// this.setFocused(listener); +// return listener.keyPressed(event); +// } +// } +// } +// +//// this.toggleColorPickerWidget(false); +// this.setFocused(null); +// +// return true; +// } + if (this.getFocused() != null) { if (this.getFocused().keyPressed(event)) { return true; } - this.toggleColorPicker(false); +// this.toggleColorPickerWidget(false); this.setFocused(null); if (keyCode == GLFW.GLFW_KEY_ESCAPE) { @@ -280,7 +304,7 @@ public boolean keyPressed(KeyEvent event) { return true; } else { - //formatting hotkeys + // Formatting hotkeys if (event.hasControlDown()) { if (keyCode == GLFW.GLFW_KEY_B) { insertTag(TagRegistry.SAFE.getTag("bold"), true); @@ -292,9 +316,9 @@ public boolean keyPressed(KeyEvent event) { insertTag(TagRegistry.SAFE.getTag("underline"), true); return true; } else if (keyCode == GLFW.GLFW_KEY_5 || keyCode == GLFW.GLFW_KEY_S) { - //There isn't a commonly agreed upon hotkey for strikethrough unlike the rest above - //apparently 5 is commonly used for strikethrough ¯\_(ツ)_/¯ - //Google Docs and Microsoft Word have 5 in their hotkeys, while Discord has S in its hotkey + // There isn't a commonly agreed upon hotkey for strikethrough unlike the rest above + // apparently 5 is commonly used for strikethrough ¯\_(ツ)_/¯ + // Google Docs and Microsoft Word have 5 in their hotkeys, while Discord has S in its hotkey insertTag(TagRegistry.SAFE.getTag("strikethrough"), true); return true; } else if (keyCode == GLFW.GLFW_KEY_O) { @@ -345,28 +369,28 @@ private void deleteLine() { } private void colorListenerClicked(EditBox textWidget) { - this.colorPickerWidget.setPosition(Math.min(textWidget.getX(), width - colorPickerWidget.getWidth()), textWidget.getY() + textWidget.getHeight()); - this.colorPickerWidget.setTargetElement(textWidget); - this.colorPickerWidget.setOnAccept(picker -> { - textWidget.setValue(ColorUtil.toAlphaHex(picker.getCurrentColor().getRGB())); - }); - this.colorPickerWidget.setOnCancel(picker -> { - picker.setColor(this.colorEntryPreColorPicker); - textWidget.setValue(ColorUtil.toAlphaHex(this.colorEntryPreColorPicker.getRGB())); - }); - this.colorPickerWidget.setChangeListener(color -> { - final int newColor = ColorUtil.transferAlpha(this.colorEntryPreColorPicker.getRGB(), color.getRGB()); - textWidget.setValue(ColorUtil.toAlphaHex(newColor)); - }); - this.colorPickerWidget.setPresetListener((color, formatting) -> { - this.colorPickerWidget.setColor(color); - }); - ColorUtil.parse(textWidget.getValue(), ColorUtil.WHITE).ifSuccess(color -> { - final Color pickerColor = new Color(color); - this.colorEntryPreColorPicker = pickerColor; - this.colorPickerWidget.setColor(pickerColor); - }).ifError(textColorError -> this.colorEntryPreColorPicker = this.colorPickerWidget.getCurrentColor()); - toggleColorPicker(true); +// this.colorPickerWidget.setPosition(Math.min(textWidget.getX(), width - colorPickerWidget.getWidth()), textWidget.getY() + textWidget.getHeight()); +// this.colorPickerWidget.setTargetElement(textWidget); +// this.colorPickerWidget.setOnAccept(picker -> { +// textWidget.setValue(ColorUtil.toAlphaHex(picker.getCurrentColor().getRGB())); +// }); +// this.colorPickerWidget.setOnCancel(picker -> { +// picker.setColor(this.colorEntryPreColorPicker); +// textWidget.setValue(ColorUtil.toAlphaHex(this.colorEntryPreColorPicker.getRGB())); +// }); +// this.colorPickerWidget.setChangeListener(color -> { +// final int newColor = ColorUtil.transferAlpha(this.colorEntryPreColorPicker.getRGB(), color.getRGB()); +// textWidget.setValue(ColorUtil.toAlphaHex(newColor)); +// }); +// this.colorPickerWidget.setPresetListener((color, formatting) -> { +// this.colorPickerWidget.setColor(color); +// }); +// ColorUtil.parse(textWidget.getValue(), ColorUtil.WHITE).ifSuccess(color -> { +// final Color pickerColor = new Color(color); +// this.colorEntryPreColorPicker = pickerColor; +// this.colorPickerWidget.setColor(pickerColor); +// }).ifError(textColorError -> this.colorEntryPreColorPicker = this.colorPickerWidget.getCurrentColor()); +// toggleColorPickerWidget(true); } @Override @@ -380,27 +404,31 @@ public boolean mouseClicked(MouseButtonEvent event, boolean doubleClick) { continue; } this.setFocused(text); - if (this.colorListeners.contains(text)) { - this.colorListenerClicked(text); - } - if (this.colorPickerWidget.targetElement != text) { - text.setFocused(false); - } +// if (this.colorListeners.contains(text)) { +// this.colorListenerClicked(text); +// } +// if (this.colorPickerWidget.targetElement != text) { +// text.setFocused(false); +// } break; } - if (colorPickerWidget.active && colorPickerWidget.visible) { - if (colorPickerWidget.isMouseOver(mouseX, mouseY)) { - colorPickerWidget.mouseClicked(event, doubleClick); - this.setFocused(colorPickerWidget); - this.setDragging(true); - return true; - } else { - if (!this.colorPickerWidget.targetElement.isMouseOver(mouseX, mouseY)) { - toggleColorPicker(false); - } - } + if (mouseClickedColorPicker(event, doubleClick)) { + return true; } + +// if (colorPickerWidget.active && colorPickerWidget.visible) { +// if (colorPickerWidget.isMouseOver(mouseX, mouseY)) { +// colorPickerWidget.mouseClicked(event, doubleClick); +// this.setFocused(colorPickerWidget); +// this.setDragging(true); +// return true; +// } else { +// if (!this.colorPickerWidget.targetElement.isMouseOver(mouseX, mouseY)) { +// toggleColorPickerWidget(false); +// } +// } +// } if (mouseY > topOffset) { this.currentRow = Mth.clamp((int) (mouseY - topOffset) / 12, 0, this.textBlockEntity.lines.size() - 1); this.setFocused(null); @@ -455,14 +483,14 @@ public boolean mouseClicked(MouseButtonEvent event, boolean doubleClick) { } @Override - public ColorPickerWidget colorPickerWidget() { + public ColorPickerWidget getColorPickerWidget() { return this.colorPickerWidget; } - @Override - public void toggleColorPicker(boolean active) { - this.colorPickerWidget.toggle(active); - } +// @Override +// public void toggleColorPickerWidget(boolean active) { +// this.colorPickerWidget.toggle(active); +// } @Override TextFieldHelper getSelectionManager() { diff --git a/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/TextEditorScreen.java b/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/TextEditorScreen.java index de428bd5..aa1f9102 100644 --- a/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/TextEditorScreen.java +++ b/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/TextEditorScreen.java @@ -1,6 +1,6 @@ package dev.hephaestus.glowcase.client.gui.screen.ingame; -import dev.hephaestus.glowcase.client.gui.widget.ingame.ColorPickerWidget; +import dev.hephaestus.glowcase.client.gui.widget.ingame.color.picker.ColorPickerWidget; import eu.pb4.placeholders.api.parsers.tag.TagRegistry; import eu.pb4.placeholders.api.parsers.tag.TextTag; import net.minecraft.ChatFormatting; @@ -47,24 +47,24 @@ protected void addFormattingButtons(int x, int y, int innerPadding, int buttonSi buttonX += buttonSize + buttonPadding; // + 4? (only works on padding of 2) this.colorText = Button.builder(Component.literal("\uD83D\uDD8C"), action -> { - ColorPickerWidget colorPickerWidget = colorPickerWidget(); - colorPickerWidget.setPosition(216, 10); - colorPickerWidget.setTargetElement(this.colorText); - colorPickerWidget.setOnAccept(picker -> { - picker.insertColor(picker.color); - picker.toggle(false); - }); - colorPickerWidget.setOnCancel(picker -> picker.toggle(false)); - colorPickerWidget.setPresetListener((color, formatting) -> { - if(formatting != null) { - insertFormattingTag(formatting); - } else { - insertHexTag(ColorPickerWidget.getHexCode(color)); - } - this.toggleColorPicker(false); - }); - colorPickerWidget.setChangeListener(null); - toggleColorPicker(!colorPickerWidget.active); +// ColorPickerWidget colorPickerWidget = getColorPickerWidget(); +// colorPickerWidget.setPosition(216, 10); +// colorPickerWidget.setTargetElement(this.colorText); +// colorPickerWidget.setOnAccept(picker -> { +// picker.insertColor(picker.color); +// picker.toggle(false); +// }); +// colorPickerWidget.setOnCancel(picker -> picker.toggle(false)); +// colorPickerWidget.setPresetListener((color, formatting) -> { +// if(formatting != null) { +// insertFormattingTag(formatting); +// } else { +// insertHexTag(ColorPickerWidget.getHexCode(color)); +// } +// this.toggleColorPickerWidget(false); +// }); +// colorPickerWidget.setChangeListener(null); +// toggleColorPickerWidget(!colorPickerWidget.active); }).bounds(buttonX, buttonY, buttonSize, buttonSize).build(); widgets = new Button[]{ diff --git a/src/main/java/dev/hephaestus/glowcase/client/gui/widget/ingame/ColorPickerWidget.java b/src/main/java/dev/hephaestus/glowcase/client/gui/widget/ingame/ColorPickerWidget.java deleted file mode 100644 index c5c38aaf..00000000 --- a/src/main/java/dev/hephaestus/glowcase/client/gui/widget/ingame/ColorPickerWidget.java +++ /dev/null @@ -1,607 +0,0 @@ -package dev.hephaestus.glowcase.client.gui.widget.ingame; - -import com.mojang.blaze3d.pipeline.RenderPipeline; -import com.mojang.blaze3d.vertex.VertexConsumer; -import dev.hephaestus.glowcase.client.gui.screen.ingame.ColorPickerIncludedScreen; -import net.fabricmc.api.EnvType; -import net.fabricmc.api.Environment; -import net.minecraft.ChatFormatting; -import net.minecraft.client.gui.GuiGraphicsExtractor; -import net.minecraft.client.gui.components.AbstractButton; -import net.minecraft.client.gui.components.events.GuiEventListener; -import net.minecraft.client.gui.narration.NarrationElementOutput; -import net.minecraft.client.gui.navigation.ScreenRectangle; -import net.minecraft.client.gui.render.TextureSetup; -import net.minecraft.client.input.InputWithModifiers; -import net.minecraft.client.input.MouseButtonEvent; -import net.minecraft.client.renderer.RenderPipelines; -import net.minecraft.client.renderer.state.gui.GuiElementRenderState; -import net.minecraft.network.chat.Component; -import net.minecraft.resources.Identifier; -import org.apache.commons.compress.utils.Lists; -import org.jetbrains.annotations.Nullable; -import org.joml.Matrix3x2fStack; - -import java.awt.*; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.function.BiConsumer; -import java.util.function.Consumer; - -public class ColorPickerWidget extends AbstractButton { - static final Identifier CONFIRM_TEXTURE = Identifier.withDefaultNamespace("pending_invite/accept"); - static final Identifier CONFIRM_HIGHLIGHTED_TEXTURE = Identifier.withDefaultNamespace("pending_invite/accept_highlighted"); - static final Identifier CANCEL_TEXTURE = Identifier.withDefaultNamespace("pending_invite/reject"); - static final Identifier CANCEL_HIGHLIGHTED_TEXTURE = Identifier.withDefaultNamespace("pending_invite/reject_highlighted"); - - public final ColorPickerIncludedScreen screen; - public GuiEventListener targetElement; - public Color color = Color.red; - public boolean includePresets = true; - public ArrayList presetWidgets = Lists.newArrayList(); - public boolean confirmOrCancelButtonDown = false; - public IconButtonWidget confirmButton; - public IconButtonWidget cancelButton; - private Consumer changeListener; - private BiConsumer presetListener; - private Consumer onAccept; - private Consumer onCancel; - - private boolean mouseDown = false; - private int presetY, presetSize, presetPadding, presetHeight; - private boolean presetDown = false; - private int previewX, previewY, previewWidth, previewHeight; - private int hueX, hueY, hueWidth, hueHeight; - private boolean hueDown = false; - private int satLightX, satLightY, satLightWidth, satLightHeight; - private boolean satLightDown = false; - public int hueThumbX; - public int satLightThumbX, satLightThumbY; - - private float[] HSL; - private float hue; - private float saturation; - private float light; - - public static ColorPickerWidget.Builder builder(ColorPickerIncludedScreen screen, int x, int y) { - return new ColorPickerWidget.Builder(screen, x, y); - } - - public ColorPickerWidget(ColorPickerIncludedScreen screen, int x, int y, int width, int height, Component message) { - super(x, y, width, height, message); - this.screen = screen; - - this.confirmButton = IconButtonWidget.builder(CONFIRM_TEXTURE, action -> this.confirmColor()) - .hoverIcon(CONFIRM_HIGHLIGHTED_TEXTURE).build(); - - this.cancelButton = IconButtonWidget.builder(CANCEL_TEXTURE, action -> this.cancel()) - .hoverIcon(CANCEL_HIGHLIGHTED_TEXTURE).build(); - - updatePositions(); - updateHSL(); - updateThumbPositions(); - } - - public void setTargetElement(GuiEventListener element) { - this.targetElement = element; - } - - public void setIncludePresets(boolean shouldInclude) { - this.includePresets = shouldInclude; - } - - public void setPresets(boolean includeDefaultPresets, List addedPresets) { - if (includeDefaultPresets) { - addDefaultPresets(); - } - if (!addedPresets.isEmpty()) { - for (Color preset : addedPresets) { - this.presetWidgets.add(ColorPresetWidget.fromColor(this, preset)); - } - } - } - - public void confirmColor() { - if (this.onAccept != null) { - this.onAccept.accept(this); - } - - this.toggle(false); - } - - public void cancel() { - if (this.onCancel != null) { - this.onCancel.accept(this); - } - - this.toggle(false); - } - - public void toggle(boolean active) { - this.active = active; - this.visible = active; - if (this.active) { - this.updatePositions(); - this.updateHSL(); - this.updateThumbPositions(); - } - } - - public void insertColor(Color color) { - String hex = getHexCode(color); - this.screen.insertHexTag(hex); - } - - public void insertFormatting(ChatFormatting formatting) { - this.screen.insertFormattingTag(formatting); - } - - public void setColor(Color color) { - this.color = color; - this.updateHSL(); - this.updateThumbPositions(); - } - - @Override - protected void extractContents(GuiGraphicsExtractor graphics, int mouseX, int mouseY, float delta) { - if (!visible) return; - updateHSL(); - - //graphics.setShaderColor(1f, 1f, 1f, this.alpha); - /*RenderSystem.enableBlend(); - RenderSystem.enableDepthTest();*/ - Matrix3x2fStack matrices = graphics.pose(); - //graphics.applyBlur(); - - graphics.nextStratum(); - matrices.pushMatrix(); - - int x = this.getX(); - int y = this.getY(); - int z = 1; - int width = this.getWidth(); - int height = this.getHeight(); - - //background - graphics.blit(RenderPipelines.GUI_TEXTURED, Identifier.withDefaultNamespace("textures/gui/inworld_menu_list_background.png"), x, y, 0, 0, width, height, 32, 32); - if (this.isHoveredOrFocused()) { - //outline - drawOutline(graphics, x, y, width, height, Color.white); - } - - //color picker stuff - updatePositions(); - this.confirmButton.setPosition(x + width - presetSize - presetPadding, y + height - presetSize - 2, z + 1, presetSize, presetSize + 2); - this.cancelButton.setPosition(x + width - presetSize * 2 - presetPadding * 2 - 1, y + height - presetSize - 2, z + 1, presetSize, presetSize + 2); - - drawColorPreview(graphics, previewX, previewY, previewWidth, previewHeight); - drawSatLight(graphics, satLightX, satLightY, satLightWidth, satLightHeight); - drawHueBar(graphics, hueX, hueY, hueWidth, hueHeight, z + 1); - if (this.includePresets) { - //sorta dynamic but also really specific to keep it all aligned - //I'm not going to worry about it a lot though because I do not see the custom preset thing being used a lot if at all - drawPresets(graphics, mouseX, mouseY, delta, previewX, presetY, y + height - presetY, z + 1, presetSize, width / (presetSize + presetPadding), presetPadding); - } - - this.confirmButton.extractRenderState(graphics, mouseX, mouseY, delta); - this.cancelButton.extractRenderState(graphics, mouseX, mouseY, delta); - - - matrices.popMatrix(); - - //graphics.setShaderColor(1f, 1f, 1f, 1f); - } - - public void updatePositions() { - int x = this.getX(); - int y = this.getY(); - int width = this.getWidth(); - int height = this.getHeight(); - - presetSize = (int) (height / 6.5); - presetPadding = 2; - presetHeight = presetSize * 2 + presetPadding * 2; - - previewX = x + 2; - previewY = y + 2; - previewWidth = width / 3; - previewHeight = height - 16 - (includePresets ? presetHeight : 0); - satLightX = previewX + previewWidth + 2; - satLightY = y + 2; - satLightWidth = width - previewWidth - 6; - satLightHeight = previewHeight; - hueX = x + 2; - hueY = previewY + previewHeight + 2; - hueWidth = width - 4; - hueHeight = height - previewHeight - 6 - (includePresets ? presetHeight : 0); - presetY = hueY + hueHeight + presetPadding; - } - - private void drawColorPreview(GuiGraphicsExtractor graphics, int x, int y, int width, int height) { - graphics.fill(x, y, x + width, y + height, this.color.getRGB()); - } - - private void drawHueBar(GuiGraphicsExtractor graphics, int x, int y, int width, int height, int z) { - //rainbow gradient - int[] colors = new int[]{ - Color.red.getRGB(), Color.yellow.getRGB(), Color.green.getRGB(), - Color.cyan.getRGB(), Color.blue.getRGB(), Color.magenta.getRGB(), - Color.red.getRGB() - }; - - int maxColors = colors.length - 1; - for (int color = 0; color < maxColors; color++) { - sidewaysGradient( - graphics, - x + (width / maxColors * (color)), y, - width / maxColors, height, - colors[color], colors[color + 1] - ); - } - - //thumb - graphics.fill(hueThumbX - 3, y - 1, hueThumbX + 3, y + height + 1, getRgbFromHueThumb()); - drawOutline(graphics, hueThumbX - 3, y - 1, 6, height + 2, Color.white); - } - - private void drawSatLight(GuiGraphicsExtractor graphics, int x, int y, int width, int height) { - //white to current color's hue, left to right - sidewaysGradient(graphics, x, y, width, height, Color.white.getRGB(), getRgbFromHueThumb()); - - //transparent to black, top to bottom - graphics.fillGradient(x, y, x + width, y + height, 0x00000000, Color.black.getRGB()); - - //thumb - graphics.fill(satLightThumbX - 4, satLightThumbY - 4, satLightThumbX + 4, satLightThumbY + 4, this.color.getRGB()); - drawOutline(graphics, satLightThumbX - 4, satLightThumbY - 4, 8, 8, Color.white); - } - - private void drawOutline(GuiGraphicsExtractor graphics, int x, int y, int width, int height, Color outlineColor) { - int color = outlineColor.getRGB(); - graphics.fill(x, y, x + width, y + 1, color); - graphics.fill(x, y, x + 1, y + height, color); - graphics.fill(x + width, y, x + width - 1, y + height, color); - graphics.fill(x, y + height, x + width, y + height - 1, color); - } - - private void sidewaysGradient(GuiGraphicsExtractor graphics, int x, int y, int width, int height, int startColor, int endColor) { - graphics.guiRenderState.addGuiElement(new GuiElementRenderState() { - - @Override - public ScreenRectangle bounds() { - return new ScreenRectangle(x, y, width, height).transformMaxBounds(graphics.pose()); - } - - @Override - public void buildVertices(VertexConsumer vertices) { - Matrix3x2fStack matrix = graphics.pose(); - vertices.addVertexWith2DPose(matrix, x, y).setColor(startColor); - vertices.addVertexWith2DPose(matrix, x, y + height).setColor(startColor); - vertices.addVertexWith2DPose(matrix, x + width, y + height).setColor(endColor); - vertices.addVertexWith2DPose(matrix, x + width, y).setColor(endColor); - } - - @Override - public RenderPipeline pipeline() { - return RenderPipelines.GUI; - } - - @Override - public TextureSetup textureSetup() { - return TextureSetup.noTexture(); - } - - @Override - public @Nullable ScreenRectangle scissorArea() { - return null; - } - }); - } - - private void drawPresets(GuiGraphicsExtractor graphics, int mouseX, int mouseY, float delta, int x, int y, int height, int z, int presetSize, int presetsPerLine, int presetPadding) { - int presetX = x; - int presetY = y; - int renderedPresets = 0; - for (ColorPresetWidget preset : this.presetWidgets) { - preset.setPosition(presetX, presetY, z, presetSize); - preset.extractRenderState(graphics, mouseX, mouseY, delta); - presetX += presetSize + presetPadding; - renderedPresets++; - if (renderedPresets % presetsPerLine == 0) { - presetY += presetSize + presetPadding; - if (presetY > y + height) { //prevent overflow - return; - } - presetX = x; - } - } - } - - //done manually to keep list order instead of looping through Formatting.values() - public void addDefaultPresets() { - ColorPresetWidget darkRed = ColorPresetWidget.fromFormatting(this, ChatFormatting.DARK_RED); - ColorPresetWidget red = ColorPresetWidget.fromFormatting(this, ChatFormatting.RED); - ColorPresetWidget gold = ColorPresetWidget.fromFormatting(this, ChatFormatting.GOLD); - ColorPresetWidget yellow = ColorPresetWidget.fromFormatting(this, ChatFormatting.YELLOW); - ColorPresetWidget green = ColorPresetWidget.fromFormatting(this, ChatFormatting.GREEN); - ColorPresetWidget darkGreen = ColorPresetWidget.fromFormatting(this, ChatFormatting.DARK_GREEN); - ColorPresetWidget aqua = ColorPresetWidget.fromFormatting(this, ChatFormatting.AQUA); - ColorPresetWidget darkAqua = ColorPresetWidget.fromFormatting(this, ChatFormatting.DARK_AQUA); - ColorPresetWidget blue = ColorPresetWidget.fromFormatting(this, ChatFormatting.BLUE); - ColorPresetWidget darkBlue = ColorPresetWidget.fromFormatting(this, ChatFormatting.DARK_BLUE); - ColorPresetWidget lightPurple = ColorPresetWidget.fromFormatting(this, ChatFormatting.LIGHT_PURPLE); - ColorPresetWidget darkPurple = ColorPresetWidget.fromFormatting(this, ChatFormatting.DARK_PURPLE); - ColorPresetWidget white = ColorPresetWidget.fromFormatting(this, ChatFormatting.WHITE); - ColorPresetWidget grey = ColorPresetWidget.fromFormatting(this, ChatFormatting.GRAY); - ColorPresetWidget darkGrey = ColorPresetWidget.fromFormatting(this, ChatFormatting.DARK_GRAY); - ColorPresetWidget black = ColorPresetWidget.fromFormatting(this, ChatFormatting.BLACK); - this.presetWidgets.addAll(List.of(darkRed, red, gold, yellow, green, darkGreen, aqua, darkAqua, - blue, darkBlue, lightPurple, darkPurple, white, grey, darkGrey, black)); - } - - @Override - public void onClick(MouseButtonEvent event, boolean doubleClick) { - this.mouseDown = true; - this.satLightDown = false; - this.hueDown = false; - this.presetDown = false; - this.confirmOrCancelButtonDown = false; - setColorFromMouse(event, doubleClick); - } - - public void setColorFromMouse(MouseButtonEvent event, boolean doubleClick) { - int colorAlpha = color.getAlpha(); - - double mouseX = event.x(); - double mouseY = event.y(); - if (clickedSatLight(mouseX, mouseY)) { - setSatLightFromMouse(mouseX, mouseY); - } else if (clickedHue(mouseX, mouseY)) { - setHueFromMouse(mouseX); - } else if (this.confirmButton.isMouseOver(mouseX, mouseY)) { - if (satLightDown || hueDown || presetDown || confirmOrCancelButtonDown) return; - this.confirmButton.onClick(event, doubleClick); - confirmOrCancelButtonDown = true; - } else if (this.cancelButton.isMouseOver(mouseX, mouseY)) { - if (satLightDown || hueDown || presetDown || confirmOrCancelButtonDown) return; - this.cancelButton.onClick(event, doubleClick); - confirmOrCancelButtonDown = true; - } else { - //clickedPreset also sets the preset to avoid an extra calculation - checkAndSetPreset(event, doubleClick); - } - - if (this.changeListener != null) { - this.changeListener.accept(this.color); - } - } - - public boolean clickedSatLight(double mouseX, double mouseY) { - if (hueDown || presetDown || confirmOrCancelButtonDown) return false; - - if (mouseX >= satLightX - && mouseX <= satLightX + satLightWidth - && mouseY >= satLightY - && mouseY <= satLightY + satLightHeight) { - satLightDown = true; - } - - if (satLightDown) { - satLightThumbX = (int) Math.clamp(mouseX, satLightX, satLightX + satLightWidth); - satLightThumbY = (int) Math.clamp(mouseY, satLightY, satLightY + satLightHeight); - } - return satLightDown; - } - - public boolean clickedHue(double mouseX, double mouseY) { - if (satLightDown || presetDown || confirmOrCancelButtonDown) return false; - - if (mouseY >= hueY && mouseY <= hueY + hueHeight - && mouseX >= hueX && mouseX <= hueX + hueWidth) { - hueDown = true; - } - - if (hueDown) { - hueThumbX = (int) Math.clamp(mouseX, hueX, hueX + hueWidth); - } - return hueDown; - } - - public boolean checkAndSetPreset(MouseButtonEvent event, boolean doubleClick) { - if (satLightDown || hueDown || presetDown || confirmOrCancelButtonDown) return false; - - //just checks for each preset here, and also sets here so it doesn't have to check again - for (ColorPresetWidget preset : this.presetWidgets) { - if (preset.isMouseOver(event.x(), event.y())) { - preset.onClick(event, doubleClick); - //even though the preset closes the color picker, - //this is added to prevent spamming tags when holding down the mouse button - presetDown = true; - } - } - return presetDown; - } - - @Override - protected void onDrag(MouseButtonEvent event, double dx, double dy) { - if (mouseDown || isMouseOver(event.x(), event.y())) { - setColorFromMouse(event, false); - } - } - - @Override - public void onRelease(MouseButtonEvent event) { - this.mouseDown = false; - } - - @Override - public boolean isMouseOver(double mouseX, double mouseY) { - return super.isMouseOver(mouseX, mouseY); - } - - @Override - public void onPress(InputWithModifiers input) { - } - - - public void setSatLightFromMouse(double mouseX, double mouseY) { - if (mouseX < satLightX) { - this.saturation = 0f; - } else if (mouseX > satLightX + satLightWidth) { - this.saturation = 1f; - } else { - float newSat = (float) (mouseX - satLightX) / satLightWidth; - this.saturation = Math.clamp(newSat, 0f, 1f); - } - - if (mouseY < satLightY) { - this.light = 1f; - } else if (mouseY > satLightY + satLightHeight) { - this.light = 0f; - } else { - float newLight = (float) (mouseY - satLightY) / satLightHeight; - this.light = Math.clamp(1f - newLight, 0f, 1f); - } - - setColorFromHSL(); - } - - public void setHueFromMouse(double mouseX) { - if (mouseX < hueX) { - this.hue = 0f; - } else if (mouseX > hueX + hueWidth) { - this.hue = 1f; - } else { - float newHue = (float) (mouseX - hueX) / hueWidth; - this.hue = Math.clamp(newHue, 0f, 1f); - } - - setColorFromHSL(); - } - - public void updateThumbPositions() { - this.satLightThumbX = getSatLightThumbX(); - this.satLightThumbY = getSatLightThumbY(); - this.hueThumbX = getHueThumbX(); - } - - private int getSatLightThumbX() { - int min = satLightX; - int max = satLightX + satLightWidth; - int value = (int) (min + (satLightWidth * this.saturation)); - return Math.clamp(value, min, max); - } - - private int getSatLightThumbY() { - int min = satLightY; - int max = satLightY + satLightHeight; - int value = (int) (min + (satLightHeight * (1.0f - this.light))); - return Math.clamp(value, min, max); - } - - private int getHueThumbX() { - int min = hueX; - int max = hueX + hueWidth; - int value = (int) (min + hueWidth * this.hue); - return Math.clamp(value, min, max); - } - - public Color getCurrentColor() { - return this.color; - } - - public void setColorFromHSL() { - float trueHue = (float) (hueThumbX - hueX) / hueWidth; - this.color = Color.getHSBColor(trueHue, this.saturation, this.light); - } - - public int getRgbFromHueThumb() { - float trueHue = (float) (hueThumbX - hueX) / hueWidth; - return Color.HSBtoRGB(trueHue, 1, 1); - } - - public void updateHSL() { - this.HSL = getHSL(); - this.hue = HSL[0]; - this.saturation = HSL[1]; - this.light = HSL[2]; - } - - protected float[] getHSL() { - return Color.RGBtoHSB(this.color.getRed(), this.color.getGreen(), this.color.getBlue(), null); - } - - @Override - public void updateWidgetNarration(NarrationElementOutput builder) { - this.defaultButtonNarrationText(builder); - } - - public void setChangeListener(Consumer changeListener) { - this.changeListener = changeListener; - } - - public void setPresetListener(BiConsumer presetListener) { - this.presetListener = presetListener; - } - - public void setOnAccept(Consumer onAccept) { - this.onAccept = onAccept; - } - - public void setOnCancel(Consumer onCancel) { - this.onCancel = onCancel; - } - - public BiConsumer getPresetListener() { - return presetListener; - } - - public static String getHexCode(Color color) { - return "#" + String.format("%1$06X", color.getRGB() & 0x00FFFFFF); - } - - @Environment(EnvType.CLIENT) - public static class Builder { - private final ColorPickerIncludedScreen screen; - private final int x; - private final int y; - private int width = 150; - private int height = 200; - private boolean includePresets = true; - private boolean includeDefaultPresets = true; - private final List presets = Lists.newArrayList(); - - public Builder(ColorPickerIncludedScreen screen, int x, int y) { - this.screen = screen; - this.x = x; - this.y = y; - } - - public ColorPickerWidget.Builder size(int width, int height) { - this.width = width; - this.height = height; - return this; - } - - public ColorPickerWidget.Builder includePresets(boolean shouldInclude) { - this.includePresets = shouldInclude; - return this; - } - - public ColorPickerWidget.Builder withPreset(boolean includeDefault, Color... presets) { - this.includeDefaultPresets = includeDefault; - this.presets.addAll(Arrays.asList(presets)); - return this; - } - - public ColorPickerWidget build() { - ColorPickerWidget colorPickerWidget = new ColorPickerWidget(this.screen, this.x, this.y, this.width, this.height, Component.nullToEmpty("")); - colorPickerWidget.setIncludePresets(this.includePresets); - if (this.includePresets) { - colorPickerWidget.setPresets(this.includeDefaultPresets, this.presets); - } - return colorPickerWidget; - } - } -} diff --git a/src/main/java/dev/hephaestus/glowcase/client/gui/widget/ingame/ColorPresetWidget.java b/src/main/java/dev/hephaestus/glowcase/client/gui/widget/ingame/ColorPresetWidget.java index 2533b6dc..d7b96691 100644 --- a/src/main/java/dev/hephaestus/glowcase/client/gui/widget/ingame/ColorPresetWidget.java +++ b/src/main/java/dev/hephaestus/glowcase/client/gui/widget/ingame/ColorPresetWidget.java @@ -1,5 +1,6 @@ package dev.hephaestus.glowcase.client.gui.widget.ingame; +import dev.hephaestus.glowcase.client.gui.widget.ingame.color.picker.ColorPickerWidget; import net.minecraft.ChatFormatting; import net.minecraft.client.gui.GuiGraphicsExtractor; import net.minecraft.client.gui.components.AbstractButton; @@ -9,7 +10,6 @@ import org.jetbrains.annotations.Nullable; import java.awt.*; -import java.util.function.BiConsumer; public class ColorPresetWidget extends AbstractButton { public final ColorPickerWidget colorPickerWidget; @@ -63,17 +63,17 @@ private void drawOutline(GuiGraphicsExtractor graphics, int x, int y, int width, @Override public void onPress(InputWithModifiers input) { - BiConsumer presetListener = this.colorPickerWidget.getPresetListener(); - if (presetListener != null) { - presetListener.accept(this.color, this.formatting != null && this.formatting.isColor() ? this.formatting : null); - } else { - if (this.formatting != null && formatting.isColor()) { - this.colorPickerWidget.color = this.color; - this.colorPickerWidget.toggle(false); - } else { - this.colorPickerWidget.setColor(this.color); - } - } +// BiConsumer presetListener = this.colorPickerWidget.getPresetListener(); +// if (presetListener != null) { +// presetListener.accept(this.color, this.formatting != null && this.formatting.isColor() ? this.formatting : null); +// } else { +// if (this.formatting != null && formatting.isColor()) { +// this.colorPickerWidget.color = this.color; +// this.colorPickerWidget.toggle(false); +// } else { +// this.colorPickerWidget.setColor(this.color); +// } +// } } diff --git a/src/main/java/dev/hephaestus/glowcase/client/gui/widget/ingame/color/HexColorEditBox.java b/src/main/java/dev/hephaestus/glowcase/client/gui/widget/ingame/color/HexColorEditBox.java new file mode 100644 index 00000000..bd6cd436 --- /dev/null +++ b/src/main/java/dev/hephaestus/glowcase/client/gui/widget/ingame/color/HexColorEditBox.java @@ -0,0 +1,153 @@ +package dev.hephaestus.glowcase.client.gui.widget.ingame.color; + +import dev.hephaestus.glowcase.client.gui.widget.ingame.GlowcaseEditBox; +import dev.hephaestus.glowcase.client.gui.widget.ingame.color.functional.ColorGetter; +import dev.hephaestus.glowcase.client.gui.widget.ingame.color.functional.ColorSetter; +import dev.hephaestus.glowcase.client.gui.widget.ingame.color.picker.ColorPickerWidget; +import dev.hephaestus.glowcase.client.util.ColorUtil; +import net.minecraft.client.gui.Font; +import net.minecraft.client.input.CharacterEvent; +import net.minecraft.client.input.MouseButtonEvent; +import net.minecraft.network.chat.Component; +import org.jetbrains.annotations.Nullable; + +/** + * An EditBox Widget built for HEX colors, with automatic color (as an integer) getter & setter, and built-in {@link ColorPickerWidget} support.

+ * @author Superkat32 + */ +public class HexColorEditBox extends GlowcaseEditBox { + @Nullable + public final ColorPickerWidget colorPickerWidget; + public final ColorGetter colorGetter; + public final ColorSetter colorSetter; + public int fallbackColor; + public int color; + public boolean editableAlpha; + + public static HexColorEditBox.Builder builder(Font textRenderer, int x, int y, ColorGetter colorGetter, ColorSetter colorSetter) { + return new Builder(textRenderer, x, y, colorGetter, colorSetter); + } + + public HexColorEditBox( + Font textRenderer, int x, int y, int width, int height, + boolean editableAlpha, int fallbackColor, @Nullable ColorPickerWidget colorPickerWidget, + ColorGetter colorGetter, ColorSetter colorSetter + ) { + super(textRenderer, x, y, width, height, Component.empty()); + this.colorPickerWidget = colorPickerWidget; + this.colorGetter = colorGetter; + this.colorSetter = colorSetter; + this.fallbackColor = fallbackColor; + this.color = colorGetter.get(); + this.editableAlpha = editableAlpha; + + this.setResponder(string -> { + ColorUtil.parse(string, this.color).ifSuccess(this.colorSetter::set); + }); + + this.setTextFromColor(); + +// if (this.colorPickerWidget != null) { +// this.colorPickerWidget.target(this); +// this.colorPickerWidget.setup(this.color, true, this::setColor); +// } + } + + @Override + public void onClick(MouseButtonEvent event, boolean doubleClick) { + super.onClick(event, doubleClick); + if (this.colorPickerWidget != null) { + this.colorPickerWidget.target(this, this.color, true, this::setColor); + } + } + + @Override + public boolean charTyped(CharacterEvent event) { + if(super.charTyped(event)) { + if (this.colorPickerWidget != null) { + ColorUtil.parse(this.getValue(), this.color).ifSuccess(parsedColor -> { + this.color = parsedColor; + this.colorPickerWidget.setColor(parsedColor); + }); + } + return true; + } + return false; + } + + public void setTextFromColor() { + String hexString = this.formatColorAsHex(this.color); + this.setValue(hexString); + } + + public String formatColorAsHex(int color) { + if (this.editableAlpha) return ColorUtil.toAlphaHex(color); + return ColorUtil.toHex(color); + } + + public void setColor(int color) { + this.color = color; + this.setTextFromColor(); + } + + public static class Builder { + private static final int DEFAULT_WIDTH = 50; + private static final int DEFAULT_ALPHA_WIDTH = 64; + + private final ColorGetter colorGetter; + private final ColorSetter colorSetter; + private final Font textRenderer; + private final int x, y; + + private int width = DEFAULT_WIDTH; + private int height = 20; + private boolean editableAlpha = false; + private int fallbackColor; + private ColorPickerWidget colorPickerWidget = null; + + public Builder(Font textRenderer, int x, int y, ColorGetter colorGetter, ColorSetter colorSetter) { + this.colorGetter = colorGetter; + this.colorSetter = colorSetter; + this.textRenderer = textRenderer; + this.x = x; + this.y = y; + + this.fallbackColor = colorGetter.get(); + } + + public Builder setWidth(int width) { + this.width = width; + return this; + } + + public Builder setHeight(int height) { + this.height = height; + return this; + } + + public Builder setEditableAlpha(boolean editableAlpha) { + this.editableAlpha = editableAlpha; + if (this.width == DEFAULT_WIDTH) this.width = DEFAULT_ALPHA_WIDTH; + return this; + } + + public Builder setFallbackColor(int fallbackColor) { + this.fallbackColor = fallbackColor; + return this; + } + + public Builder setColorPickerWidget(ColorPickerWidget colorPickerWidget) { + this.colorPickerWidget = colorPickerWidget; + return this; + } + + public HexColorEditBox build() { + return new HexColorEditBox( + this.textRenderer, this.x, this.y, this.width, this.height, + this.editableAlpha, this.fallbackColor, this.colorPickerWidget, + this.colorGetter, this.colorSetter + ); + } + } + +} diff --git a/src/main/java/dev/hephaestus/glowcase/client/gui/widget/ingame/color/functional/ColorGetter.java b/src/main/java/dev/hephaestus/glowcase/client/gui/widget/ingame/color/functional/ColorGetter.java new file mode 100644 index 00000000..1f4602ed --- /dev/null +++ b/src/main/java/dev/hephaestus/glowcase/client/gui/widget/ingame/color/functional/ColorGetter.java @@ -0,0 +1,5 @@ +package dev.hephaestus.glowcase.client.gui.widget.ingame.color.functional; + +public interface ColorGetter { + int get(); +} diff --git a/src/main/java/dev/hephaestus/glowcase/client/gui/widget/ingame/color/functional/ColorSetter.java b/src/main/java/dev/hephaestus/glowcase/client/gui/widget/ingame/color/functional/ColorSetter.java new file mode 100644 index 00000000..8e97df43 --- /dev/null +++ b/src/main/java/dev/hephaestus/glowcase/client/gui/widget/ingame/color/functional/ColorSetter.java @@ -0,0 +1,5 @@ +package dev.hephaestus.glowcase.client.gui.widget.ingame.color.functional; + +public interface ColorSetter { + void set(int color); +} diff --git a/src/main/java/dev/hephaestus/glowcase/client/gui/widget/ingame/color/functional/PickerPresetListener.java b/src/main/java/dev/hephaestus/glowcase/client/gui/widget/ingame/color/functional/PickerPresetListener.java new file mode 100644 index 00000000..488e3d50 --- /dev/null +++ b/src/main/java/dev/hephaestus/glowcase/client/gui/widget/ingame/color/functional/PickerPresetListener.java @@ -0,0 +1,7 @@ +package dev.hephaestus.glowcase.client.gui.widget.ingame.color.functional; + +import dev.hephaestus.glowcase.client.gui.widget.ingame.color.picker.PickerPreset; + +public interface PickerPresetListener { + void onPresetClick(PickerPreset preset); +} diff --git a/src/main/java/dev/hephaestus/glowcase/client/gui/widget/ingame/color/picker/ColorPickerWidget.java b/src/main/java/dev/hephaestus/glowcase/client/gui/widget/ingame/color/picker/ColorPickerWidget.java new file mode 100644 index 00000000..cc283c10 --- /dev/null +++ b/src/main/java/dev/hephaestus/glowcase/client/gui/widget/ingame/color/picker/ColorPickerWidget.java @@ -0,0 +1,999 @@ +package dev.hephaestus.glowcase.client.gui.widget.ingame.color.picker; + +import dev.hephaestus.glowcase.Glowcase; +import dev.hephaestus.glowcase.client.gui.screen.ingame.ColorPickerIncludedScreen; +import dev.hephaestus.glowcase.client.gui.widget.ingame.color.functional.ColorSetter; +import dev.hephaestus.glowcase.client.gui.widget.ingame.color.functional.PickerPresetListener; +import dev.hephaestus.glowcase.client.util.ColorUtil; +import dev.hephaestus.glowcase.client.util.GuiGraphicsUtil; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiGraphicsExtractor; +import net.minecraft.client.gui.components.AbstractButton; +import net.minecraft.client.gui.components.AbstractWidget; +import net.minecraft.client.gui.components.events.GuiEventListener; +import net.minecraft.client.gui.narration.NarrationElementOutput; +import net.minecraft.client.input.InputWithModifiers; +import net.minecraft.client.input.MouseButtonEvent; +import net.minecraft.client.renderer.RenderPipelines; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.Identifier; +import net.minecraft.util.ARGB; +import net.minecraft.util.CommonColors; +import org.jetbrains.annotations.Nullable; +import org.jspecify.annotations.NonNull; + +import java.util.Iterator; +import java.util.List; + +/** + * Main color picker widget, including a preview box, saturation & value box, hue slider, optional alpha slider, and color presets.

+ * Each {@link ColorPickerIncludedScreen} has *one* Color Picker, which each widget uses. This means that position, showAlpha, and color values will be updated constantly.

+ * @author Superkat32 + */ +public class ColorPickerWidget extends AbstractButton { + // Okay, let's do this one last time. My name is Color-Picker Parker, and I was bitten by a radioactive Gradle Elephant, and for the last like 5 minutes, I've been the one and only Glowcase Color Picker... it's like 2am right now + + // To keep things simple (and keep me sane), sizes are fully locked and hardcoded + // Width calculated by: ((presetScale + padding) * presetsPerLine) + padding -> ((16 + 2) * 10) + 2 + // Height calculated by: Whatever my heart desired at the moment -> 116 and 146, apparently + // Alpha height difference: (presetScale + padding) + (alphaHeight + padding) -> (16 + 2) + (10 + 2) + private static final int DEFAULT_WIDTH = 182; + private static final int DEFAULT_HEIGHT = 116; + private static final int DEFAULT_ALPHA_HEIGHT = 146; + private static final Identifier BACKGROUND_TEXTURE = Identifier.withDefaultNamespace("textures/gui/inworld_menu_list_background.png"); + // Different alpha textures have different tile sizes to better match their background + private static final Identifier ALPHA_PREVIEW_TEXTURE = Glowcase.id("color_picker/alpha_preview"); + private static final Identifier ALPHA_SLIDER_TEXTURE = Glowcase.id("color_picker/alpha_slider"); + private static final Identifier ALPHA_THUMB_TEXTURE = Glowcase.id("color_picker/alpha_thumb"); + private static final Identifier ALPHA_PRESET_TEXTURE = Glowcase.id("color_picker/alpha_preset"); + private static final Identifier CONFIRM_TEXTURE = Identifier.withDefaultNamespace("pending_invite/accept"); + private static final Identifier CONFIRM_HIGHLIGHTED_TEXTURE = Identifier.withDefaultNamespace("pending_invite/accept_highlighted"); + private static final Identifier CANCEL_TEXTURE = Identifier.withDefaultNamespace("pending_invite/reject"); + private static final Identifier CANCEL_HIGHLIGHTED_TEXTURE = Identifier.withDefaultNamespace("pending_invite/reject_highlighted"); + + public final ColorPickerIncludedScreen screen; + @Nullable + public GuiEventListener targetElement = null; + @Nullable + public ColorSetter pickedColorListener = null; + @Nullable + public PickerPresetListener presetListener = null; + public boolean showAlpha = false; + + public final List clickableAreas; + public PickerArea previewArea; + public PickerArea satValueArea; + public PickerArea hueArea; + public PickerArea alphaArea; + public PickerArea presetsArea; + public List formattingPresetAreas; + public List alphaPresetAreas; + + @Nullable + public PickerArea currentClickedArea = null; // Used for allowing mouse drags beyond an area's boundaries + + public float hue, saturation, value, alpha; + public float prevHue, prevSaturation, prevValue, prevAlpha; + + public static ColorPickerWidget.Builder builder(ColorPickerIncludedScreen screen) { + return new Builder(screen); + } + + public ColorPickerWidget(ColorPickerIncludedScreen screen, int x, int y, int width, int height, Component message) { + super(x, y, width, height, message); + this.screen = screen; + + this.previewArea = new PickerArea(this, false); + this.satValueArea = new PickerArea(this, xLerp -> this.saturation = xLerp, yLerp -> this.value = 1f - yLerp); + this.hueArea = new PickerArea(this, xLerp -> this.hue = xLerp); + this.alphaArea = new PickerArea(this, xLerp -> this.alpha = xLerp); + this.presetsArea = new PickerArea(this, false); + this.formattingPresetAreas = PickerPreset.createFormattingPresets(this); + this.alphaPresetAreas = PickerPreset.createAlphaPresets(this); + this.updateAreas(); + +// this.areas = List.of(this.previewArea, this.satValueArea, this.hueArea, this.alphaArea, this.presetsArea); + this.clickableAreas = List.of(this.satValueArea, this.hueArea, this.alphaArea); + this.hide(); // Start hidden + } + + // Preset width & height: 16 + // Presets per row: 10 (2 rows by default, 3 if alpha is shown) + // Hue & Alpha slider heights: 10 + // Preview & Sat/value picker: Whatever height is left + // Preview width: 1/3 of picker padded width + // Sat/value picker: Whatever width is left from preview + // Padding among everything: 2 + public void updateAreas() { + int paddedX = this.getX() + 2; + int bottomY = this.getY() + this.getHeight() - 2; + int paddedWidth = this.getWidth() - 4; + + int presetsHeight = (16) * (this.showAlpha ? 3 : 2) + (this.showAlpha ? 4 : 2); + this.presetsArea.set(paddedX, bottomY - presetsHeight, paddedWidth, presetsHeight); + this.alphaArea.set(paddedX, presetsArea.getY() - 10 - 2, paddedWidth, this.showAlpha ? 10 : 0); + this.hueArea.set(paddedX, alphaArea.getY() - (showAlpha ? 10 + 2 : 0), paddedWidth, 10); + + int remainingHeight = this.hueArea.getY() - this.getY() - 4; + int remainingY = hueArea.getY() - remainingHeight - 2; + this.previewArea.set(paddedX, remainingY, paddedWidth / 3, remainingHeight); + int satValueWidth = this.getX() + this.getWidth() - previewArea.getX2() - 4; + this.satValueArea.set(previewArea.getX2() + 2, remainingY, satValueWidth, remainingHeight); + + for (int i = 0; i < this.formattingPresetAreas.size(); i++) { + PickerPreset preset = this.formattingPresetAreas.get(i); + int x = paddedX + ((i % 10) * 18); + int y = presetsArea.getY() + (18 * (i / 10)); + preset.set(x, y, 16, 16); + } + + if (this.showAlpha) { + for (int i = 0; i < this.alphaPresetAreas.size(); i++) { + PickerPreset preset = this.alphaPresetAreas.get(i); + int x = paddedX + ((i % 10) * 18); + int y = presetsArea.getY() + (18 * ((i / 10) + 2)); + preset.set(x, y, 16, 16); + } + } + } + + // Position the thumbs based on the current color + public void updateAreaThumbs() { + this.hueArea.lerpThumbX(this.hue); + this.satValueArea.lerpThumbX(this.saturation); + this.satValueArea.lerpThumbY(1f - this.value); + if (this.showAlpha) this.alphaArea.lerpThumbX(this.alpha); + } + + // region R.E.P.O - Render, Extract, and Position Operations + @Override + protected void extractContents(GuiGraphicsExtractor graphics, int mouseX, int mouseY, float delta) { + // Background + graphics.blit(RenderPipelines.GUI_TEXTURED, BACKGROUND_TEXTURE, this.getX(), this.getY(), 0, 0, this.getWidth(), this.getHeight(), 32, 32); + + // Render areas +// extractPreviewArea(this.previewArea, graphics, this.getColor()); + extractPreviewArea(this.previewArea, graphics); + extractSatValueArea(this.satValueArea, graphics); + extractHueArea(this.hueArea, graphics); + if (showAlpha) extractAlphaArea(this.alphaArea, graphics); + for (PickerPreset preset : this.formattingPresetAreas) { + extractPresetArea(preset, graphics, false); + } + if (showAlpha) { + for (PickerPreset preset : this.alphaPresetAreas) { + extractPresetArea(preset, graphics, true); + } + } +// extractPreviewArea(this.presetsArea, graphics, CommonColors.WHITE); + + // Render thumbs (to ensure they are above everything despite overlaps) + extractThumb(graphics, this.hueArea.getThumbX(), this.hueArea.getY() + 5, 6, 12, this.getHueColor()); + if (showAlpha) extractThumb(graphics, this.alphaArea.getThumbX(), this.alphaArea.getY() + 5, 6, 12, this.getColor(), true); + extractThumb(graphics, this.satValueArea.getThumbX(), this.satValueArea.getThumbY(), 8, 8, this.getColorNoAlpha()); + } + + public void extractPreviewArea(PickerArea area, GuiGraphicsExtractor graphics) { + // TODO - Precise tile of the background for my perfectionism here + // Alpha background texture (if needed) + if (this.showAlpha) graphics.blitSprite(RenderPipelines.GUI_TEXTURED, ALPHA_PREVIEW_TEXTURE, area.getX(), area.getY(), area.getWidth(), area.getHeight()); + + // Current color + graphics.fill(area.getX(), area.getY(), area.getX2(), area.getY2(), this.getColor()); + } + + public void extractSatValueArea(PickerArea area, GuiGraphicsExtractor graphics) { + // White to current hue, left to right + GuiGraphicsUtil.extractHorizontalGradient(graphics, area.getX(), area.getY(), area.getX2(), area.getY2(), ColorUtil.WHITE, this.getHueColor()); + + // Transparent to black, top to bottom + graphics.fillGradient(area.getX(), area.getY(), area.getX2(), area.getY2(), ColorUtil.TRANSPARENT, ColorUtil.BLACK); + } + + public void extractHueArea(PickerArea area, GuiGraphicsExtractor graphics) { + // Hue gradient, starting and ending on red + GuiGraphicsUtil.extractHueGradient(graphics, area.getX(), area.getY(), area.getX2(), area.getY2()); + } + + public void extractAlphaArea(PickerArea area, GuiGraphicsExtractor graphics) { + // Alpha background texture + graphics.blitSprite(RenderPipelines.GUI_TEXTURED, ALPHA_SLIDER_TEXTURE, area.getX(), area.getY(), area.getWidth(), area.getHeight()); + + // Transparent to current color, left to right + GuiGraphicsUtil.extractHorizontalGradient(graphics, area.getX(), area.getY(), area.getX2(), area.getY2(), ColorUtil.TRANSPARENT, this.getColorNoAlpha()); + } + + public void extractPresetArea(PickerPreset preset, GuiGraphicsExtractor graphics, boolean alphaPreset) { + // Alpha background texture (if needed) + if (alphaPreset) graphics.blitSprite(RenderPipelines.GUI_TEXTURED, ALPHA_PRESET_TEXTURE, preset.getX(), preset.getY(), preset.getWidth(), preset.getHeight()); + graphics.fill(preset.getX(), preset.getY(), preset.getX2(), preset.getY2(), preset.getPresetColor()); + + if (alphaPreset) { + // FIXME - Please figure out a better way of doing this than whatever on earth this is + String hex = ColorUtil.toAlphaHex(preset.getPresetColor()); + graphics.text(Minecraft.getInstance().font, String.valueOf(hex.charAt(1)) + String.valueOf(hex.charAt(2)), preset.getX(), preset.getY() + 8, ColorUtil.WHITE); + } + } + + public void extractThumb(GuiGraphicsExtractor graphics, int thumbX, int thumbY, int thumbWidth, int thumbHeight, int thumbColor) { + this.extractThumb(graphics, thumbX, thumbY, thumbWidth, thumbHeight, thumbColor, false); + } + + public void extractThumb(GuiGraphicsExtractor graphics, int thumbX, int thumbY, int thumbWidth, int thumbHeight, int thumbColor, boolean alphaBackground) { + int halfWidth = thumbWidth / 2; + int halfHeight = thumbHeight / 2; + + int x = thumbX - halfWidth; + int y = thumbY - halfHeight; + int x2 = thumbX + halfWidth; + int y2 = thumbY + halfHeight; + + if (alphaBackground) graphics.blitSprite(RenderPipelines.GUI_TEXTURED, ALPHA_THUMB_TEXTURE, x, y, thumbWidth, thumbHeight); + graphics.fill(x, y, x2, y2, thumbColor); + graphics.outline(x, y, thumbWidth, thumbHeight, ColorUtil.WHITE); + } + + // endregion + + /** + * Position & set up the Color Picker based on a widget and its needs. Positioning accounts for screen size, ensuring the color picker never goes off-screen. + * @param widget The Widget to position the Color Picker too + * @param initColor The initial color the Color Picker should be, and should revert to if canceled/undone + * @param showAlpha Whether the alpha should be editable, and the alpha slider visible + * @param pickedColorSetterListener What to do with the picked color, as an integer + */ + public void target(AbstractWidget widget, int initColor, boolean showAlpha, ColorSetter pickedColorSetterListener) { + this.visible = true; + this.active = true; + this.targetElement = widget; + + // TODO - right-aligned option + int x = Math.min(Minecraft.getInstance().screen.width - this.getWidth() - 2, widget.getX()); + int y = widget.getY() + widget.getHeight(); + this.setX(x); + this.setY(y); + + this.setPrevColor(initColor); + this.setColor(initColor); + + this.showAlpha = showAlpha; + this.setHeight(this.showAlpha ? DEFAULT_ALPHA_HEIGHT : DEFAULT_HEIGHT); + + this.pickedColorListener = pickedColorSetterListener; + this.presetListener = preset -> { // Default preset behaviour, just set the picker color + if (preset.isAlphaPreset()) { + this.alpha = preset.getAlpha(); + this.updateAreaThumbs(); + } else { + this.setColor(preset.getPresetColor(), false); + } + }; + + this.updateAreas(); + this.updateAreaThumbs(); + } + + public void setPresetListener(PickerPresetListener presetListener) { + this.presetListener = presetListener; + } + + public void setColor(int color) { + this.setColor(color, true); + } + + /** + * Set the Color Picker's color from an integer. Intended for something like the {@link dev.hephaestus.glowcase.client.gui.widget.ingame.color.HexColorEditBox} when a user edits the HEX string, and the color picker needs to reflect that update. + */ + public void setColor(int color, boolean setAlpha) { + float[] HSBA = ColorUtil.ARGBToHSBA(color); + this.hue = HSBA[0]; + this.saturation = HSBA[1]; + this.value = HSBA[2]; + if (setAlpha) this.alpha = HSBA[3]; + + this.updateAreaThumbs(); + } + + /** + * The color to revert/undo to in case the user presses cancel. + */ + public void setPrevColor(int color) { + float[] HSBA = ColorUtil.ARGBToHSBA(color); + this.prevHue = HSBA[0]; + this.prevSaturation = HSBA[1]; + this.prevValue = HSBA[2]; + this.prevAlpha = HSBA[3]; + } + + public void cancel() { + int prevColor = ColorUtil.HSBAtoARGB(this.prevHue, this.prevSaturation, this.prevValue, this.showAlpha ? this.prevAlpha : 1f); + this.setColor(prevColor); + this.onColorPicked(); + this.hide(); + } + + public void hide() { + this.active = false; + this.visible = false; + this.setFocused(false); + + this.pickedColorListener = null; + this.presetListener = null; + } + + @Override + public void onClick(@NonNull MouseButtonEvent event, boolean doubleClick) { + this.tryClickAreas(event); + } + + @Override + protected void onDrag(@NonNull MouseButtonEvent event, double dx, double dy) { + this.tryClickAreas(event); + } + + @Override + public void onRelease(@NonNull MouseButtonEvent event) { + if (this.currentClickedArea != null) { + this.currentClickedArea.mouseReleased(); + this.currentClickedArea = null; + } + } + + public void tryClickAreas(MouseButtonEvent event) { + double x = event.x(); + double y = event.y(); + + // Current clicked area gets full click priority + if (this.currentClickedArea != null) { + if (this.currentClickedArea.mouseClicked(x, y)) { + this.onColorPicked(); + } + return; + } + + // No area is currently clicked, so search for one to click, and return if found + for (PickerArea area : clickableAreas) { + if (area.mouseClicked(x, y)) { + this.currentClickedArea = area; + this.onColorPicked(); + return; + } + } + + for (PickerPreset preset : formattingPresetAreas) { + if (preset.mouseClicked(x, y)) { + this.currentClickedArea = preset; + this.onColorPicked(); + return; + } + } + + for (PickerPreset preset : alphaPresetAreas) { + if (preset.mouseClicked(x, y)) { + this.currentClickedArea = preset; + this.onColorPicked(); + return; + } + } + } + + public void onPresetClick(PickerPreset preset) { + if (this.presetListener != null) { + this.presetListener.onPresetClick(preset); + } + } + + public void onColorPicked() { + if (this.pickedColorListener != null) { + int pickedColor = this.showAlpha ? this.getColor() : this.getColorNoAlpha(); + this.pickedColorListener.set(pickedColor); + } + } + + /** + * @return The Color Picker's picked color, as an integer + */ + public int getColor() { + float returnedAlpha = this.showAlpha ? this.alpha : 1f; + return ColorUtil.HSBAtoARGB(this.hue, this.saturation, this.value, returnedAlpha); + } + + public int getColorNoAlpha() { + return ColorUtil.HSBtoRGB(this.hue, this.saturation, this.value); + } + + public int getHueColor() { + return ColorUtil.HSBtoRGB(this.hue, 1f, 1f); + } + + // region Unused + @Override + public void onPress(@NonNull InputWithModifiers input) {} + + @Override + protected void updateWidgetNarration(@NonNull NarrationElementOutput output) {} + // endregion + + public static class Builder { + private final ColorPickerIncludedScreen screen; + + public Builder(ColorPickerIncludedScreen screen) { + this.screen = screen; + } + + public ColorPickerWidget build() { + return new ColorPickerWidget(screen, 0, 0, DEFAULT_WIDTH, DEFAULT_HEIGHT, Component.nullToEmpty("")); + } + } + + +// public final ColorPickerIncludedScreen screen; +// public GuiEventListener targetElement; +// public Color color = Color.red; +// public boolean includePresets = true; +// public ArrayList presetWidgets = Lists.newArrayList(); +// public boolean confirmOrCancelButtonDown = false; +// public IconButtonWidget confirmButton; +// public IconButtonWidget cancelButton; +// private Consumer changeListener; +// private BiConsumer presetListener; +// private Consumer onAccept; +// private Consumer onCancel; +// +// private boolean mouseDown = false; +// private int presetY, presetSize, presetPadding, presetHeight; +// private boolean presetDown = false; +// private int previewX, previewY, previewWidth, previewHeight; +// private int hueX, hueY, hueWidth, hueHeight; +// private boolean hueDown = false; +// private int satLightX, satLightY, satLightWidth, satLightHeight; +// private boolean satLightDown = false; +// public int hueThumbX; +// public int satLightThumbX, satLightThumbY; +// +// private float[] HSL; +// private float hue; +// private float saturation; +// private float light; +// +// public static ColorPickerWidget.Builder builder(ColorPickerIncludedScreen screen, int x, int y) { +// return new ColorPickerWidget.Builder(screen, x, y); +// } +// +// public ColorPickerWidget(ColorPickerIncludedScreen screen, int x, int y, int width, int height, Component message) { +// super(x, y, width, height, message); +// this.screen = screen; +// +// this.confirmButton = IconButtonWidget.builder(CONFIRM_TEXTURE, action -> this.confirmColor()) +// .hoverIcon(CONFIRM_HIGHLIGHTED_TEXTURE).build(); +// +// this.cancelButton = IconButtonWidget.builder(CANCEL_TEXTURE, action -> this.cancel()) +// .hoverIcon(CANCEL_HIGHLIGHTED_TEXTURE).build(); +// +// updatePositions(); +// updateHSL(); +// updateThumbPositions(); +// } +// +// public void setTargetElement(GuiEventListener element) { +// this.targetElement = element; +// } +// +// public void setIncludePresets(boolean shouldInclude) { +// this.includePresets = shouldInclude; +// } +// +// public void setPresets(boolean includeDefaultPresets, List addedPresets) { +// if (includeDefaultPresets) { +// addDefaultPresets(); +// } +// if (!addedPresets.isEmpty()) { +// for (Color preset : addedPresets) { +// this.presetWidgets.add(ColorPresetWidget.fromColor(this, preset)); +// } +// } +// } +// +// public void confirmColor() { +// if (this.onAccept != null) { +// this.onAccept.accept(this); +// } +// +// this.toggle(false); +// } +// +// public void cancel() { +// if (this.onCancel != null) { +// this.onCancel.accept(this); +// } +// +// this.toggle(false); +// } +// +// public void toggle(boolean active) { +// this.active = active; +// this.visible = active; +// if (this.active) { +// this.updatePositions(); +// this.updateHSL(); +// this.updateThumbPositions(); +// } +// } +// +// public void insertColor(Color color) { +// String hex = getHexCode(color); +// this.screen.insertHexTag(hex); +// } +// +// public void insertFormatting(ChatFormatting formatting) { +// this.screen.insertFormattingTag(formatting); +// } +// +// public void setColor(Color color) { +// this.color = color; +// this.updateHSL(); +// this.updateThumbPositions(); +// } +// +// @Override +// protected void extractContents(GuiGraphicsExtractor graphics, int mouseX, int mouseY, float delta) { +// if (!visible) return; +// updateHSL(); +// +// //graphics.setShaderColor(1f, 1f, 1f, this.alpha); +// /*RenderSystem.enableBlend(); +// RenderSystem.enableDepthTest();*/ +// Matrix3x2fStack matrices = graphics.pose(); +// //graphics.applyBlur(); +// +// graphics.nextStratum(); +// matrices.pushMatrix(); +// +// int x = this.getX(); +// int y = this.getY(); +// int z = 1; +// int width = this.getWidth(); +// int height = this.getHeight(); +// +// //background +// graphics.blit(RenderPipelines.GUI_TEXTURED, Identifier.withDefaultNamespace("textures/gui/inworld_menu_list_background.png"), x, y, 0, 0, width, height, 32, 32); +// if (this.isHoveredOrFocused()) { +// //outline +// drawOutline(graphics, x, y, width, height, Color.white); +// } +// +// //color picker stuff +// updatePositions(); +// this.confirmButton.setPosition(x + width - presetSize - presetPadding, y + height - presetSize - 2, z + 1, presetSize, presetSize + 2); +// this.cancelButton.setPosition(x + width - presetSize * 2 - presetPadding * 2 - 1, y + height - presetSize - 2, z + 1, presetSize, presetSize + 2); +// +// drawColorPreview(graphics, previewX, previewY, previewWidth, previewHeight); +// drawSatLight(graphics, satLightX, satLightY, satLightWidth, satLightHeight); +// drawHueBar(graphics, hueX, hueY, hueWidth, hueHeight, z + 1); +// if (this.includePresets) { +// //sorta dynamic but also really specific to keep it all aligned +// //I'm not going to worry about it a lot though because I do not see the custom preset thing being used a lot if at all +// drawPresets(graphics, mouseX, mouseY, delta, previewX, presetY, y + height - presetY, z + 1, presetSize, width / (presetSize + presetPadding), presetPadding); +// } +// +// this.confirmButton.extractRenderState(graphics, mouseX, mouseY, delta); +// this.cancelButton.extractRenderState(graphics, mouseX, mouseY, delta); +// +// +// matrices.popMatrix(); +// +// //graphics.setShaderColor(1f, 1f, 1f, 1f); +// } +// +// public void updatePositions() { +// int x = this.getX(); +// int y = this.getY(); +// int width = this.getWidth(); +// int height = this.getHeight(); +// +// presetSize = (int) (height / 6.5); +// presetPadding = 2; +// presetHeight = presetSize * 2 + presetPadding * 2; +// +// previewX = x + 2; +// previewY = y + 2; +// previewWidth = width / 3; +// previewHeight = height - 16 - (includePresets ? presetHeight : 0); +// satLightX = previewX + previewWidth + 2; +// satLightY = y + 2; +// satLightWidth = width - previewWidth - 6; +// satLightHeight = previewHeight; +// hueX = x + 2; +// hueY = previewY + previewHeight + 2; +// hueWidth = width - 4; +// hueHeight = height - previewHeight - 6 - (includePresets ? presetHeight : 0); +// presetY = hueY + hueHeight + presetPadding; +// } +// +// private void drawColorPreview(GuiGraphicsExtractor graphics, int x, int y, int width, int height) { +// graphics.fill(x, y, x + width, y + height, this.color.getRGB()); +// } +// +// private void drawHueBar(GuiGraphicsExtractor graphics, int x, int y, int width, int height, int z) { +// //rainbow gradient +// int[] colors = new int[]{ +// Color.red.getRGB(), Color.yellow.getRGB(), Color.green.getRGB(), +// Color.cyan.getRGB(), Color.blue.getRGB(), Color.magenta.getRGB(), +// Color.red.getRGB() +// }; +// +// int maxColors = colors.length - 1; +// for (int color = 0; color < maxColors; color++) { +// sidewaysGradient( +// graphics, +// x + (width / maxColors * (color)), y, +// width / maxColors, height, +// colors[color], colors[color + 1] +// ); +// } +// +// //thumb +// graphics.fill(hueThumbX - 3, y - 1, hueThumbX + 3, y + height + 1, getRgbFromHueThumb()); +// drawOutline(graphics, hueThumbX - 3, y - 1, 6, height + 2, Color.white); +// } +// +// private void drawSatLight(GuiGraphicsExtractor graphics, int x, int y, int width, int height) { +// //white to current color's hue, left to right +// sidewaysGradient(graphics, x, y, width, height, Color.white.getRGB(), getRgbFromHueThumb()); +// +// //transparent to black, top to bottom +// graphics.fillGradient(x, y, x + width, y + height, 0x00000000, Color.black.getRGB()); +// +// //thumb +// graphics.fill(satLightThumbX - 4, satLightThumbY - 4, satLightThumbX + 4, satLightThumbY + 4, this.color.getRGB()); +// drawOutline(graphics, satLightThumbX - 4, satLightThumbY - 4, 8, 8, Color.white); +// } +// +// private void drawOutline(GuiGraphicsExtractor graphics, int x, int y, int width, int height, Color outlineColor) { +// int color = outlineColor.getRGB(); +// graphics.fill(x, y, x + width, y + 1, color); +// graphics.fill(x, y, x + 1, y + height, color); +// graphics.fill(x + width, y, x + width - 1, y + height, color); +// graphics.fill(x, y + height, x + width, y + height - 1, color); +// } +// +// private void sidewaysGradient(GuiGraphicsExtractor graphics, int x, int y, int width, int height, int startColor, int endColor) { +// graphics.guiRenderState.addGuiElement(new GuiElementRenderState() { +// +// @Override +// public ScreenRectangle bounds() { +// return new ScreenRectangle(x, y, width, height).transformMaxBounds(graphics.pose()); +// } +// +// @Override +// public void buildVertices(VertexConsumer vertices) { +// Matrix3x2fStack matrix = graphics.pose(); +// vertices.addVertexWith2DPose(matrix, x, y).setColor(startColor); +// vertices.addVertexWith2DPose(matrix, x, y + height).setColor(startColor); +// vertices.addVertexWith2DPose(matrix, x + width, y + height).setColor(endColor); +// vertices.addVertexWith2DPose(matrix, x + width, y).setColor(endColor); +// } +// +// @Override +// public RenderPipeline pipeline() { +// return RenderPipelines.GUI; +// } +// +// @Override +// public TextureSetup textureSetup() { +// return TextureSetup.noTexture(); +// } +// +// @Override +// public @Nullable ScreenRectangle scissorArea() { +// return null; +// } +// }); +// } +// +// private void drawPresets(GuiGraphicsExtractor graphics, int mouseX, int mouseY, float delta, int x, int y, int height, int z, int presetSize, int presetsPerLine, int presetPadding) { +// int presetX = x; +// int presetY = y; +// int renderedPresets = 0; +// for (ColorPresetWidget preset : this.presetWidgets) { +// preset.setPosition(presetX, presetY, z, presetSize); +// preset.extractRenderState(graphics, mouseX, mouseY, delta); +// presetX += presetSize + presetPadding; +// renderedPresets++; +// if (renderedPresets % presetsPerLine == 0) { +// presetY += presetSize + presetPadding; +// if (presetY > y + height) { //prevent overflow +// return; +// } +// presetX = x; +// } +// } +// } +// +// //done manually to keep list order instead of looping through Formatting.values() +// public void addDefaultPresets() { +// ColorPresetWidget darkRed = ColorPresetWidget.fromFormatting(this, ChatFormatting.DARK_RED); +// ColorPresetWidget red = ColorPresetWidget.fromFormatting(this, ChatFormatting.RED); +// ColorPresetWidget gold = ColorPresetWidget.fromFormatting(this, ChatFormatting.GOLD); +// ColorPresetWidget yellow = ColorPresetWidget.fromFormatting(this, ChatFormatting.YELLOW); +// ColorPresetWidget green = ColorPresetWidget.fromFormatting(this, ChatFormatting.GREEN); +// ColorPresetWidget darkGreen = ColorPresetWidget.fromFormatting(this, ChatFormatting.DARK_GREEN); +// ColorPresetWidget aqua = ColorPresetWidget.fromFormatting(this, ChatFormatting.AQUA); +// ColorPresetWidget darkAqua = ColorPresetWidget.fromFormatting(this, ChatFormatting.DARK_AQUA); +// ColorPresetWidget blue = ColorPresetWidget.fromFormatting(this, ChatFormatting.BLUE); +// ColorPresetWidget darkBlue = ColorPresetWidget.fromFormatting(this, ChatFormatting.DARK_BLUE); +// ColorPresetWidget lightPurple = ColorPresetWidget.fromFormatting(this, ChatFormatting.LIGHT_PURPLE); +// ColorPresetWidget darkPurple = ColorPresetWidget.fromFormatting(this, ChatFormatting.DARK_PURPLE); +// ColorPresetWidget white = ColorPresetWidget.fromFormatting(this, ChatFormatting.WHITE); +// ColorPresetWidget grey = ColorPresetWidget.fromFormatting(this, ChatFormatting.GRAY); +// ColorPresetWidget darkGrey = ColorPresetWidget.fromFormatting(this, ChatFormatting.DARK_GRAY); +// ColorPresetWidget black = ColorPresetWidget.fromFormatting(this, ChatFormatting.BLACK); +// this.presetWidgets.addAll(List.of(darkRed, red, gold, yellow, green, darkGreen, aqua, darkAqua, +// blue, darkBlue, lightPurple, darkPurple, white, grey, darkGrey, black)); +// } +// +// @Override +// public void onClick(MouseButtonEvent event, boolean doubleClick) { +// this.mouseDown = true; +// this.satLightDown = false; +// this.hueDown = false; +// this.presetDown = false; +// this.confirmOrCancelButtonDown = false; +// setColorFromMouse(event, doubleClick); +// } +// +// public void setColorFromMouse(MouseButtonEvent event, boolean doubleClick) { +// int colorAlpha = color.getAlpha(); +// +// double mouseX = event.x(); +// double mouseY = event.y(); +// if (clickedSatLight(mouseX, mouseY)) { +// setSatLightFromMouse(mouseX, mouseY); +// } else if (clickedHue(mouseX, mouseY)) { +// setHueFromMouse(mouseX); +// } else if (this.confirmButton.isMouseOver(mouseX, mouseY)) { +// if (satLightDown || hueDown || presetDown || confirmOrCancelButtonDown) return; +// this.confirmButton.onClick(event, doubleClick); +// confirmOrCancelButtonDown = true; +// } else if (this.cancelButton.isMouseOver(mouseX, mouseY)) { +// if (satLightDown || hueDown || presetDown || confirmOrCancelButtonDown) return; +// this.cancelButton.onClick(event, doubleClick); +// confirmOrCancelButtonDown = true; +// } else { +// //clickedPreset also sets the preset to avoid an extra calculation +// checkAndSetPreset(event, doubleClick); +// } +// +// if (this.changeListener != null) { +// this.changeListener.accept(this.color); +// } +// } +// +// public boolean clickedSatLight(double mouseX, double mouseY) { +// if (hueDown || presetDown || confirmOrCancelButtonDown) return false; +// +// if (mouseX >= satLightX +// && mouseX <= satLightX + satLightWidth +// && mouseY >= satLightY +// && mouseY <= satLightY + satLightHeight) { +// satLightDown = true; +// } +// +// if (satLightDown) { +// satLightThumbX = (int) Math.clamp(mouseX, satLightX, satLightX + satLightWidth); +// satLightThumbY = (int) Math.clamp(mouseY, satLightY, satLightY + satLightHeight); +// } +// return satLightDown; +// } +// +// public boolean clickedHue(double mouseX, double mouseY) { +// if (satLightDown || presetDown || confirmOrCancelButtonDown) return false; +// +// if (mouseY >= hueY && mouseY <= hueY + hueHeight +// && mouseX >= hueX && mouseX <= hueX + hueWidth) { +// hueDown = true; +// } +// +// if (hueDown) { +// hueThumbX = (int) Math.clamp(mouseX, hueX, hueX + hueWidth); +// } +// return hueDown; +// } +// +// public boolean checkAndSetPreset(MouseButtonEvent event, boolean doubleClick) { +// if (satLightDown || hueDown || presetDown || confirmOrCancelButtonDown) return false; +// +// //just checks for each preset here, and also sets here so it doesn't have to check again +// for (ColorPresetWidget preset : this.presetWidgets) { +// if (preset.isMouseOver(event.x(), event.y())) { +// preset.onClick(event, doubleClick); +// //even though the preset closes the color picker, +// //this is added to prevent spamming tags when holding down the mouse button +// presetDown = true; +// } +// } +// return presetDown; +// } +// +// @Override +// protected void onDrag(MouseButtonEvent event, double dx, double dy) { +// if (mouseDown || isMouseOver(event.x(), event.y())) { +// setColorFromMouse(event, false); +// } +// } +// +// @Override +// public void onRelease(MouseButtonEvent event) { +// this.mouseDown = false; +// } +// +// @Override +// public boolean isMouseOver(double mouseX, double mouseY) { +// return super.isMouseOver(mouseX, mouseY); +// } +// +// @Override +// public void onPress(InputWithModifiers input) { +// } +// +// +// public void setSatLightFromMouse(double mouseX, double mouseY) { +// if (mouseX < satLightX) { +// this.saturation = 0f; +// } else if (mouseX > satLightX + satLightWidth) { +// this.saturation = 1f; +// } else { +// float newSat = (float) (mouseX - satLightX) / satLightWidth; +// this.saturation = Math.clamp(newSat, 0f, 1f); +// } +// +// if (mouseY < satLightY) { +// this.light = 1f; +// } else if (mouseY > satLightY + satLightHeight) { +// this.light = 0f; +// } else { +// float newLight = (float) (mouseY - satLightY) / satLightHeight; +// this.light = Math.clamp(1f - newLight, 0f, 1f); +// } +// +// setColorFromHSL(); +// } +// +// public void setHueFromMouse(double mouseX) { +// if (mouseX < hueX) { +// this.hue = 0f; +// } else if (mouseX > hueX + hueWidth) { +// this.hue = 1f; +// } else { +// float newHue = (float) (mouseX - hueX) / hueWidth; +// this.hue = Math.clamp(newHue, 0f, 1f); +// } +// +// setColorFromHSL(); +// } +// +// public void updateThumbPositions() { +// this.satLightThumbX = getSatLightThumbX(); +// this.satLightThumbY = getSatLightThumbY(); +// this.hueThumbX = getHueThumbX(); +// } +// +// private int getSatLightThumbX() { +// int min = satLightX; +// int max = satLightX + satLightWidth; +// int value = (int) (min + (satLightWidth * this.saturation)); +// return Math.clamp(value, min, max); +// } +// +// private int getSatLightThumbY() { +// int min = satLightY; +// int max = satLightY + satLightHeight; +// int value = (int) (min + (satLightHeight * (1.0f - this.light))); +// return Math.clamp(value, min, max); +// } +// +// private int getHueThumbX() { +// int min = hueX; +// int max = hueX + hueWidth; +// int value = (int) (min + hueWidth * this.hue); +// return Math.clamp(value, min, max); +// } +// +// public Color getCurrentColor() { +// return this.color; +// } +// +// public void setColorFromHSL() { +// float trueHue = (float) (hueThumbX - hueX) / hueWidth; +// this.color = Color.getHSBColor(trueHue, this.saturation, this.light); +// } +// +// public int getRgbFromHueThumb() { +// float trueHue = (float) (hueThumbX - hueX) / hueWidth; +// return Color.HSBtoRGB(trueHue, 1, 1); +// } +// +// public void updateHSL() { +// this.HSL = getHSL(); +// this.hue = HSL[0]; +// this.saturation = HSL[1]; +// this.light = HSL[2]; +// } +// +// protected float[] getHSL() { +// return Color.RGBtoHSB(this.color.getRed(), this.color.getGreen(), this.color.getBlue(), null); +// } +// +// @Override +// public void updateWidgetNarration(NarrationElementOutput builder) { +// this.defaultButtonNarrationText(builder); +// } +// +// public void setChangeListener(Consumer changeListener) { +// this.changeListener = changeListener; +// } +// +// public void setPresetListener(BiConsumer presetListener) { +// this.presetListener = presetListener; +// } +// +// public void setOnAccept(Consumer onAccept) { +// this.onAccept = onAccept; +// } +// +// public void setOnCancel(Consumer onCancel) { +// this.onCancel = onCancel; +// } +// +// public BiConsumer getPresetListener() { +// return presetListener; +// } +// +// public static String getHexCode(Color color) { +// return "#" + String.format("%1$06X", color.getRGB() & 0x00FFFFFF); +// } +// +// @Environment(EnvType.CLIENT) +// public static class Builder { +// private final ColorPickerIncludedScreen screen; +// private final int x; +// private final int y; +// private int width = 150; +// private int height = 200; +// private boolean includePresets = true; +// private boolean includeDefaultPresets = true; +// private final List presets = Lists.newArrayList(); +// +// public Builder(ColorPickerIncludedScreen screen, int x, int y) { +// this.screen = screen; +// this.x = x; +// this.y = y; +// } +// +// public ColorPickerWidget.Builder size(int width, int height) { +// this.width = width; +// this.height = height; +// return this; +// } +// +// public ColorPickerWidget.Builder includePresets(boolean shouldInclude) { +// this.includePresets = shouldInclude; +// return this; +// } +// +// public ColorPickerWidget.Builder withPreset(boolean includeDefault, Color... presets) { +// this.includeDefaultPresets = includeDefault; +// this.presets.addAll(Arrays.asList(presets)); +// return this; +// } +// +// public ColorPickerWidget build() { +// ColorPickerWidget colorPickerWidget = new ColorPickerWidget(this.screen, this.x, this.y, this.width, this.height, Component.nullToEmpty("")); +// colorPickerWidget.setIncludePresets(this.includePresets); +// if (this.includePresets) { +// colorPickerWidget.setPresets(this.includeDefaultPresets, this.presets); +// } +// return colorPickerWidget; +// } +// } +} diff --git a/src/main/java/dev/hephaestus/glowcase/client/gui/widget/ingame/color/picker/PickerArea.java b/src/main/java/dev/hephaestus/glowcase/client/gui/widget/ingame/color/picker/PickerArea.java new file mode 100644 index 00000000..ce5edc5d --- /dev/null +++ b/src/main/java/dev/hephaestus/glowcase/client/gui/widget/ingame/color/picker/PickerArea.java @@ -0,0 +1,155 @@ +package dev.hephaestus.glowcase.client.gui.widget.ingame.color.picker; + +import net.minecraft.util.Mth; +import org.jetbrains.annotations.Nullable; + +/** + * Clickable area within a {@link ColorPickerWidget}, such as the hue slider, saturation/light picker, alpha slider, and presets.

+ * Allows for definable position & dimensions for a clickable area, and a listener for what to do when clicked (e.g. set ColorPicker hue/sat./light/alpha). + * + * @see ColorPickerWidget + */ +public class PickerArea { + private final ColorPickerWidget colorPicker; + @Nullable + private final AreaSetter xLerpSetter; + @Nullable + private final AreaSetter yLerpSetter; + private final boolean clickable; + private int x, y, width, height; + private int thumbX, thumbY; + private boolean hasMouseDown = false; + + public PickerArea(ColorPickerWidget colorPicker, boolean clickable) { + this(colorPicker, false, null, null); + } + + public PickerArea(ColorPickerWidget colorPicker, @Nullable AreaSetter xLerp) { + this(colorPicker, true, xLerp, null); + } + + public PickerArea(ColorPickerWidget colorPicker, @Nullable AreaSetter xLerp, @Nullable AreaSetter yLerp) { + this(colorPicker, true, xLerp, yLerp); + } + + public PickerArea(ColorPickerWidget colorPicker, boolean clickable, @Nullable AreaSetter xLerp, @Nullable AreaSetter yLerp) { + this.colorPicker = colorPicker; + this.clickable = clickable; + this.xLerpSetter = xLerp; + this.yLerpSetter = yLerp; + } + + public boolean mouseClicked(double mouseX, double mouseY) { + if (!this.clickable) return false; + + if (isMouseOver(mouseX, mouseY)) { + this.hasMouseDown = true; + } + + if (this.hasMouseDown) { + // Assume horizontal / x movement is possible + if (this.xLerpSetter != null) { + this.thumbX = (int) Mth.clamp(mouseX, this.getX(), this.getX2()); + + float xLerp = calcLerp(mouseX, this.getX(), this.getX2()); + this.xLerpSetter.set(xLerp); + } + + // Assume vertical / y movement is possible + if (this.yLerpSetter != null) { + this.thumbY = (int) Mth.clamp(mouseY, this.getY(), this.getY2()); + + float yLerp = calcLerp(mouseY, this.getY(), this.getY2()); + this.yLerpSetter.set(yLerp); + } + } + + return this.hasMouseDown; + } + + public void mouseReleased() { + this.hasMouseDown = false; + } + + public boolean isMouseOver(double mouseX, double mouseY) { + return (mouseY > this.getY() && mouseY < this.getY2()) + && (mouseX > this.getX() && mouseX < this.getX2()); + } + + private float calcLerp(double mousePos, int minPos, int maxPos) { + if (mousePos < minPos) return 0f; + if (mousePos > maxPos) return 1f; + float width = maxPos - minPos; + return Mth.clamp(((float) mousePos - minPos) / width, 0f, 1f); + } + + public void lerpThumbX(float lerp) { + this.thumbX = (int) Mth.clamp(this.getX() + (this.getWidth() * lerp), this.getX(), this.getX2()); + } + + public void lerpThumbY(float lerp) { + this.thumbY = (int) Mth.clamp(this.getY() + (this.getHeight() * lerp), this.getY(), this.getY2()); + } + + // region Getters & Setters + public void set(int x, int y, int width, int height) { + this.setPos(x, y); + this.setDimensions(width, height); + } + + public void setPos(int x, int y) { + this.x = x; + this.y = y; + } + + public void setDimensions(int width, int height) { + this.width = width; + this.height = height; + } + + public int getX() { + return x; + } + + public int getY() { + return y; + } + + public int getX2() { + return this.getX() + this.getWidth(); + } + + public int getY2() { + return this.getY() + this.getHeight(); + } + + public int getWidth() { + return width; + } + + public int getHeight() { + return height; + } + + public int getThumbX() { + return thumbX; + } + + public int getThumbY() { + return thumbY; + } + + public boolean hasMouseDown() { + return this.hasMouseDown; + } + + public ColorPickerWidget getColorPicker() { + return colorPicker; + } + + // endregion + + public interface AreaSetter { + void set(float value); + } +} diff --git a/src/main/java/dev/hephaestus/glowcase/client/gui/widget/ingame/color/picker/PickerPreset.java b/src/main/java/dev/hephaestus/glowcase/client/gui/widget/ingame/color/picker/PickerPreset.java new file mode 100644 index 00000000..cd679fa5 --- /dev/null +++ b/src/main/java/dev/hephaestus/glowcase/client/gui/widget/ingame/color/picker/PickerPreset.java @@ -0,0 +1,86 @@ +package dev.hephaestus.glowcase.client.gui.widget.ingame.color.picker; + +import net.minecraft.ChatFormatting; +import net.minecraft.util.ARGB; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.List; + +public class PickerPreset extends PickerArea { + public static final ChatFormatting[] FORMATTING_PRESETS = new ChatFormatting[]{ + ChatFormatting.DARK_RED, ChatFormatting.RED, ChatFormatting.GOLD, ChatFormatting.YELLOW, + ChatFormatting.GREEN, ChatFormatting.DARK_GREEN, ChatFormatting.AQUA, ChatFormatting.DARK_AQUA, + ChatFormatting.BLUE, ChatFormatting.DARK_BLUE, ChatFormatting.LIGHT_PURPLE, ChatFormatting.DARK_PURPLE, + ChatFormatting.WHITE, ChatFormatting.GRAY, ChatFormatting.DARK_GRAY, ChatFormatting.BLACK + }; + + public static final Integer[] ALPHA_PRESETS = new Integer[]{ + 0x00000000, 0x40000000, 0x55000000, 0x77000000, 0x99000000, 0xAA000000, 0xCC000000, 0xFF000000 + }; + + public static List createFormattingPresets(ColorPickerWidget colorPicker) { + List presets = new ArrayList<>(); + for (ChatFormatting formattingPreset : FORMATTING_PRESETS) { + //noinspection DataFlowIssue - We can assume that the presets in this array have their color ints + presets.add(new PickerPreset(colorPicker, ARGB.color(1f, formattingPreset.getColor()), formattingPreset, false)); + } + return presets; + } + + public static List createAlphaPresets(ColorPickerWidget colorPicker) { + List presets = new ArrayList<>(); + for (Integer alphaColor : ALPHA_PRESETS) { + presets.add(new PickerPreset(colorPicker, alphaColor, null, true)); + } + return presets; + } + + private final int presetColor; + @Nullable + private final ChatFormatting presetFormatting; + private final boolean isAlphaPreset; + + public PickerPreset(ColorPickerWidget colorPicker, int presetColor, @Nullable ChatFormatting presetFormatting, boolean isAlphaPreset) { + super(colorPicker, true, null, null); + this.presetColor = presetColor; + this.presetFormatting = presetFormatting; + this.isAlphaPreset = isAlphaPreset; + } + + @Override + public boolean mouseClicked(double mouseX, double mouseY) { + if(super.mouseClicked(mouseX, mouseY)) { + this.getColorPicker().onPresetClick(this); + return true; + } + return false; + } + + public int getPresetColor() { + if (this.presetFormatting != null && this.presetFormatting.isColor() && this.presetFormatting.getColor() != null) { + // Needed otherwise it's transparent for some reason + return ARGB.color(1f, this.presetFormatting.getColor()); + } + return this.presetColor; + } + + public @Nullable ChatFormatting getPresetFormatting() { + return presetFormatting; + } + +// public int getFormattingColorOrDefault() { +// if (this.presetFormatting != null && this.presetFormatting.isColor() && this.presetFormatting.getColor() != null) { +// return ARGB.color(1f, this.presetFormatting.getColor()); +// } +// return this.getPresetColor(); +// } + + public boolean isAlphaPreset() { + return isAlphaPreset; + } + + public float getAlpha() { + return ARGB.alphaFloat(this.presetColor); + } +} diff --git a/src/main/java/dev/hephaestus/glowcase/client/util/ColorUtil.java b/src/main/java/dev/hephaestus/glowcase/client/util/ColorUtil.java index 2649758e..570b7d2f 100644 --- a/src/main/java/dev/hephaestus/glowcase/client/util/ColorUtil.java +++ b/src/main/java/dev/hephaestus/glowcase/client/util/ColorUtil.java @@ -2,6 +2,7 @@ import com.mojang.serialization.DataResult; import net.minecraft.ChatFormatting; +import net.minecraft.util.ARGB; /** * @author Ampflower @@ -16,7 +17,16 @@ public final class ColorUtil { public static final int RGB_MASK = (1 << RGB_BITS) - 1; public static final int ALPHA_MASK = CHANNEL_MASK << RGB_BITS; + + public static final int RED = 0xFFFF0000; + public static final int YELLOW = 0xFFFFFF00; + public static final int GREEN = 0xFF00FF00; + public static final int CYAN = 0xFF00FFFF; + public static final int BLUE = 0xFF0000FF; + public static final int MAGENTA = 0xFFFF00FF; + public static final int WHITE = ALPHA_MASK | RGB_MASK; + public static final int BLACK = 0xFF000000; public static final int TRANSPARENT = 0; public static int transferAlpha(int oldColor, int newColor) { @@ -80,6 +90,10 @@ public static String toAlphaHex(int color) { return String.format("#%1$08X", color); } + public static String toHex(int color) { + return "#" + String.format("%1$06X", color & 0x00FFFFFF); + } + private static int upcast(int color) { int r = (color & 0x000F) * 0x00000011; int g = (color & 0x00F0) * 0x00000110; @@ -87,4 +101,120 @@ private static int upcast(int color) { int a = (color & 0xF000) * 0x00011000; return r | g | b | a; } + + /** + * Convert an integer color to hue, saturation, brightness/value, and alpha. + */ + public static float[] ARGBToHSBA(int color) { + int red = ARGB.red(color); + int green = ARGB.green(color); + int blue = ARGB.blue(color); + float[] HSBA = new float[4]; + RGBtoHSB(red, green, blue, HSBA); + + HSBA[3] = ARGB.alphaFloat(color); + return HSBA; + } + + /** + * Converts RGB to HSB (hue, saturation, brightness/value).

+ * + * Custom method here used in favor of java.awt.Color's to prevent possible crashes on Mac. + * @see java.awt.Color#RGBtoHSB(int, int, int, float[]) + */ + public static float[] RGBtoHSB(int r, int g, int b, float[] hsbvals) { + float hue, saturation, brightness; + if (hsbvals == null) { + hsbvals = new float[3]; + } + int cmax = (r > g) ? r : g; + if (b > cmax) cmax = b; + int cmin = (r < g) ? r : g; + if (b < cmin) cmin = b; + + brightness = ((float) cmax) / 255.0f; + if (cmax != 0) + saturation = ((float) (cmax - cmin)) / ((float) cmax); + else + saturation = 0; + if (saturation == 0) + hue = 0; + else { + float redc = ((float) (cmax - r)) / ((float) (cmax - cmin)); + float greenc = ((float) (cmax - g)) / ((float) (cmax - cmin)); + float bluec = ((float) (cmax - b)) / ((float) (cmax - cmin)); + if (r == cmax) + hue = bluec - greenc; + else if (g == cmax) + hue = 2.0f + redc - bluec; + else + hue = 4.0f + greenc - redc; + hue = hue / 6.0f; + if (hue < 0) + hue = hue + 1.0f; + } + hsbvals[0] = hue; + hsbvals[1] = saturation; + hsbvals[2] = brightness; + return hsbvals; + } + + /** + * Convert hue, saturation, brightness/value, and alpha to an integer of ARGB. + */ + public static int HSBAtoARGB(float hue, float saturation, float brightness, float alpha) { + return ARGB.color(alpha, HSBtoRGB(hue, saturation,brightness)); + } + + /** + * Converts HSB (hue, saturation, brightness/value) to RGB.

+ * + * Custom method here used in favor of java.awt.Color's to prevent possible crashes on Mac. + * @see java.awt.Color#HSBtoRGB(float, float, float) + */ + public static int HSBtoRGB(float hue, float saturation, float brightness) { + int r = 0, g = 0, b = 0; + if (saturation == 0) { + r = g = b = (int) (brightness * 255.0f + 0.5f); + } else { + float h = (hue - (float)Math.floor(hue)) * 6.0f; + float f = h - (float)java.lang.Math.floor(h); + float p = brightness * (1.0f - saturation); + float q = brightness * (1.0f - saturation * f); + float t = brightness * (1.0f - (saturation * (1.0f - f))); + switch ((int) h) { + case 0: + r = (int) (brightness * 255.0f + 0.5f); + g = (int) (t * 255.0f + 0.5f); + b = (int) (p * 255.0f + 0.5f); + break; + case 1: + r = (int) (q * 255.0f + 0.5f); + g = (int) (brightness * 255.0f + 0.5f); + b = (int) (p * 255.0f + 0.5f); + break; + case 2: + r = (int) (p * 255.0f + 0.5f); + g = (int) (brightness * 255.0f + 0.5f); + b = (int) (t * 255.0f + 0.5f); + break; + case 3: + r = (int) (p * 255.0f + 0.5f); + g = (int) (q * 255.0f + 0.5f); + b = (int) (brightness * 255.0f + 0.5f); + break; + case 4: + r = (int) (t * 255.0f + 0.5f); + g = (int) (p * 255.0f + 0.5f); + b = (int) (brightness * 255.0f + 0.5f); + break; + case 5: + r = (int) (brightness * 255.0f + 0.5f); + g = (int) (p * 255.0f + 0.5f); + b = (int) (q * 255.0f + 0.5f); + break; + } + } + return 0xff000000 | (r << 16) | (g << 8) | (b << 0); + } } diff --git a/src/main/java/dev/hephaestus/glowcase/client/util/GuiGraphicsUtil.java b/src/main/java/dev/hephaestus/glowcase/client/util/GuiGraphicsUtil.java new file mode 100644 index 00000000..3ee54bd3 --- /dev/null +++ b/src/main/java/dev/hephaestus/glowcase/client/util/GuiGraphicsUtil.java @@ -0,0 +1,92 @@ +package dev.hephaestus.glowcase.client.util; + +import com.mojang.blaze3d.pipeline.RenderPipeline; +import com.mojang.blaze3d.textures.GpuTexture; +import com.mojang.blaze3d.textures.GpuTextureView; +import com.mojang.blaze3d.vertex.VertexConsumer; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiGraphicsExtractor; +import net.minecraft.client.gui.navigation.ScreenRectangle; +import net.minecraft.client.gui.render.TextureSetup; +import net.minecraft.client.renderer.RenderPipelines; +import net.minecraft.client.renderer.state.gui.GuiElementRenderState; +import net.minecraft.client.renderer.texture.AbstractTexture; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.data.AtlasIds; +import net.minecraft.resources.Identifier; +import org.joml.Matrix3x2fStack; +import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.Nullable; + +public class GuiGraphicsUtil { + public static final int[] HUE_GRADIENT_COLORS = new int[]{ + ColorUtil.RED, ColorUtil.YELLOW, ColorUtil.GREEN, ColorUtil.CYAN, ColorUtil.BLUE, ColorUtil.MAGENTA, ColorUtil.RED + }; + + /** + * Fill a horizontal gradient between two colors. + * @apiNote Do not replace the position floats with integers! {@link GuiGraphicsUtil#extractHueGradient(GuiGraphicsExtractor, int, int, int, int)} relies on float position to ensure its gradients can be fully rendered across any specified integer length, instead of requiring the length to be perfectly divisible by a specific number (7 I think) or else it leaves an empty gap. + * @see GuiGraphicsExtractor#fillGradient + */ + public static void extractHorizontalGradient(GuiGraphicsExtractor graphics, float x0, float y0, float x1, float y1, int startColor, int endColor) { + graphics.guiRenderState.addGuiElement( + new GuiElementRenderState() { + @Override + public void buildVertices(@NonNull VertexConsumer vertexConsumer) { + Matrix3x2fStack matrix = graphics.pose(); + vertexConsumer.addVertexWith2DPose(matrix, x0, y0).setColor(startColor); + vertexConsumer.addVertexWith2DPose(matrix, x0, y1).setColor(startColor); + vertexConsumer.addVertexWith2DPose(matrix, x1, y1).setColor(endColor); + vertexConsumer.addVertexWith2DPose(matrix, x1, y0).setColor(endColor); + } + + @Override + public @NonNull RenderPipeline pipeline() { + return RenderPipelines.GUI; + } + + @Override + public @NonNull TextureSetup textureSetup() { + return TextureSetup.noTexture(); + } + + @Override + public @Nullable ScreenRectangle scissorArea() { + return null; + } + + @Override + public @NonNull ScreenRectangle bounds() { + return new ScreenRectangle((int) x0, (int) y0, (int) (x1 - x0), (int) (y1 - y0)).transformMaxBounds(graphics.pose()); + } + } + ); + } + + /** + * Render a hue gradient, starting and ending on red. + * @apiNote Do not replace the width float with an integer! See {@link GuiGraphicsUtil#extractHorizontalGradient(GuiGraphicsExtractor, float, float, float, float, int, int)}'s API Note for details. + */ + public static void extractHueGradient(GuiGraphicsExtractor graphics, int x0, int y0, int x1, int y1) { + float width = x1 - x0; + int colorCount = HUE_GRADIENT_COLORS.length - 1; + for (int i = 0; i < colorCount; i++) { + extractHorizontalGradient( + graphics, + x0 + (width / colorCount * i), y0, + x0 + (width / colorCount * (i + 1)), y1, + HUE_GRADIENT_COLORS[i], HUE_GRADIENT_COLORS[i + 1] + ); + } + } + +// public static void drawPreciseTile(GuiGraphicsExtractor graphics, Identifier spriteId, int x0, int y0, int x1, int y1, float rows, float columns) { +// TextureAtlasSprite sprite = Minecraft.getInstance().getAtlasManager().getAtlasOrThrow(AtlasIds.GUI).getSprite(spriteId); +// AbstractTexture spriteTexture = Minecraft.getInstance().getTextureManager().getTexture(sprite.atlasLocation()); +// GpuTextureView texture = spriteTexture.getTextureView(); +// +// } +// +// public static void drawPreciseTexture(GuiGraphicsExtractor graphics, GpuTexture) + +} diff --git a/src/main/resources/assets/glowcase/lang/en_us.json b/src/main/resources/assets/glowcase/lang/en_us.json index cd13ddd9..37870e38 100644 --- a/src/main/resources/assets/glowcase/lang/en_us.json +++ b/src/main/resources/assets/glowcase/lang/en_us.json @@ -101,8 +101,8 @@ "gui.glowcase.volume": "Volume", "gui.glowcase.pitch": "Pitch", "gui.glowcase.yaw": "Yaw", - "gui.glowcase.color": "Color", - "gui.glowcase.background_color": "Background Color", + "gui.glowcase.color": "Color (ARGB)", + "gui.glowcase.background_color": "Background Color (ARGB)", "gui.glowcase.repeat_delay": "Repeat Delay", "gui.glowcase.distance": "Distance", "gui.glowcase.sound_category": "%s", diff --git a/src/main/resources/assets/glowcase/textures/gui/sprites/color_picker/alpha_preset.png b/src/main/resources/assets/glowcase/textures/gui/sprites/color_picker/alpha_preset.png new file mode 100644 index 0000000000000000000000000000000000000000..137d044f16c9ee94bec21ba0df19f0cdf5f04b91 GIT binary patch literal 117 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|^gUf1Lo9le z|NQ^|zn;zJ!JC_#e=L!l@!^yZqZ_XT58DQTuJq*OU|@I<%h~!%yP*K6 OmBG{1&t;ucLK6Uur6z>{ literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/glowcase/textures/gui/sprites/color_picker/alpha_preset.png.mcmeta b/src/main/resources/assets/glowcase/textures/gui/sprites/color_picker/alpha_preset.png.mcmeta new file mode 100644 index 00000000..920b97f9 --- /dev/null +++ b/src/main/resources/assets/glowcase/textures/gui/sprites/color_picker/alpha_preset.png.mcmeta @@ -0,0 +1,10 @@ +{ + "gui": { + "scaling": { + "type": "tile", + "width": 16, + "height": 16, + "border": 2 + } + } +} diff --git a/src/main/resources/assets/glowcase/textures/gui/sprites/color_picker/alpha_preview.png b/src/main/resources/assets/glowcase/textures/gui/sprites/color_picker/alpha_preview.png new file mode 100644 index 0000000000000000000000000000000000000000..137d044f16c9ee94bec21ba0df19f0cdf5f04b91 GIT binary patch literal 117 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|^gUf1Lo9le z|NQ^|zn;zJ!JC_#e=L!l@!^yZqZ_XT58DQTuJq*OU|@I<%h~!%yP*K6 OmBG{1&t;ucLK6Uur6z>{ literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/glowcase/textures/gui/sprites/color_picker/alpha_preview.png.mcmeta b/src/main/resources/assets/glowcase/textures/gui/sprites/color_picker/alpha_preview.png.mcmeta new file mode 100644 index 00000000..fdc0c74a --- /dev/null +++ b/src/main/resources/assets/glowcase/textures/gui/sprites/color_picker/alpha_preview.png.mcmeta @@ -0,0 +1,10 @@ +{ + "gui": { + "scaling": { + "type": "tile", + "width": 20, + "height": 20, + "border": 2 + } + } +} diff --git a/src/main/resources/assets/glowcase/textures/gui/sprites/color_picker/alpha_slider.png b/src/main/resources/assets/glowcase/textures/gui/sprites/color_picker/alpha_slider.png new file mode 100644 index 0000000000000000000000000000000000000000..137d044f16c9ee94bec21ba0df19f0cdf5f04b91 GIT binary patch literal 117 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|^gUf1Lo9le z|NQ^|zn;zJ!JC_#e=L!l@!^yZqZ_XT58DQTuJq*OU|@I<%h~!%yP*K6 OmBG{1&t;ucLK6Uur6z>{ literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/glowcase/textures/gui/sprites/color_picker/alpha_slider.png.mcmeta b/src/main/resources/assets/glowcase/textures/gui/sprites/color_picker/alpha_slider.png.mcmeta new file mode 100644 index 00000000..3fdfad94 --- /dev/null +++ b/src/main/resources/assets/glowcase/textures/gui/sprites/color_picker/alpha_slider.png.mcmeta @@ -0,0 +1,10 @@ +{ + "gui": { + "scaling": { + "type": "tile", + "width": 10, + "height": 10, + "border": 2 + } + } +} diff --git a/src/main/resources/assets/glowcase/textures/gui/sprites/color_picker/alpha_thumb.png b/src/main/resources/assets/glowcase/textures/gui/sprites/color_picker/alpha_thumb.png new file mode 100644 index 0000000000000000000000000000000000000000..137d044f16c9ee94bec21ba0df19f0cdf5f04b91 GIT binary patch literal 117 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|^gUf1Lo9le z|NQ^|zn;zJ!JC_#e=L!l@!^yZqZ_XT58DQTuJq*OU|@I<%h~!%yP*K6 OmBG{1&t;ucLK6Uur6z>{ literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/glowcase/textures/gui/sprites/color_picker/alpha_thumb.png.mcmeta b/src/main/resources/assets/glowcase/textures/gui/sprites/color_picker/alpha_thumb.png.mcmeta new file mode 100644 index 00000000..0382014c --- /dev/null +++ b/src/main/resources/assets/glowcase/textures/gui/sprites/color_picker/alpha_thumb.png.mcmeta @@ -0,0 +1,10 @@ +{ + "gui": { + "scaling": { + "type": "tile", + "width": 12, + "height": 12, + "border": 2 + } + } +} From 26e11728d0db80e39ac35e9f2e2e21ef20707006 Mon Sep 17 00:00:00 2001 From: Kat Date: Fri, 17 Jul 2026 10:12:52 -0400 Subject: [PATCH 2/9] Feat: Re-add Color Picker confirm/cancel buttons, allow color picker formatting --- .../ingame/ColorPickerIncludedScreen.java | 7 +- .../gui/screen/ingame/TextEditorScreen.java | 8 ++ .../color/picker/ColorPickerWidget.java | 114 ++++++++++++------ .../ingame/color/picker/PickerArea.java | 5 + .../ingame/color/picker/PickerButton.java | 43 +++++++ 5 files changed, 141 insertions(+), 36 deletions(-) create mode 100644 src/main/java/dev/hephaestus/glowcase/client/gui/widget/ingame/color/picker/PickerButton.java diff --git a/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/ColorPickerIncludedScreen.java b/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/ColorPickerIncludedScreen.java index f4560423..41f7e87e 100644 --- a/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/ColorPickerIncludedScreen.java +++ b/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/ColorPickerIncludedScreen.java @@ -1,6 +1,7 @@ package dev.hephaestus.glowcase.client.gui.screen.ingame; import dev.hephaestus.glowcase.client.gui.widget.ingame.color.picker.ColorPickerWidget; +import dev.hephaestus.glowcase.client.util.ColorUtil; import net.minecraft.ChatFormatting; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.components.AbstractWidget; @@ -42,7 +43,7 @@ default boolean keyPressedColorPicker(KeyEvent event) { if (colorPickerWidget.isActive()) { Screen self = (Screen) this; switch (keyCode) { - case GLFW.GLFW_KEY_ENTER, GLFW.GLFW_KEY_KP_ENTER -> colorPickerWidget.hide(); + case GLFW.GLFW_KEY_ENTER, GLFW.GLFW_KEY_KP_ENTER -> colorPickerWidget.confirm(); case GLFW.GLFW_KEY_ESCAPE -> colorPickerWidget.cancel(); default -> { GuiEventListener pickerTarget = colorPickerWidget.targetElement; @@ -70,4 +71,8 @@ default void hideColorPickerWidget() { // TODO - break this into FormattableScreen void insertHexTag(String hex); void insertFormattingTag(ChatFormatting formatting); + default void insertHexColor(int color) { + String hex = ColorUtil.toHex(color); + this.insertHexTag(hex); + } } diff --git a/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/TextEditorScreen.java b/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/TextEditorScreen.java index aa1f9102..3f096102 100644 --- a/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/TextEditorScreen.java +++ b/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/TextEditorScreen.java @@ -1,6 +1,7 @@ package dev.hephaestus.glowcase.client.gui.screen.ingame; import dev.hephaestus.glowcase.client.gui.widget.ingame.color.picker.ColorPickerWidget; +import dev.hephaestus.glowcase.client.util.ColorUtil; import eu.pb4.placeholders.api.parsers.tag.TagRegistry; import eu.pb4.placeholders.api.parsers.tag.TextTag; import net.minecraft.ChatFormatting; @@ -47,6 +48,13 @@ protected void addFormattingButtons(int x, int y, int innerPadding, int buttonSi buttonX += buttonSize + buttonPadding; // + 4? (only works on padding of 2) this.colorText = Button.builder(Component.literal("\uD83D\uDD8C"), action -> { + ColorPickerWidget colorPickerWidget = this.getColorPickerWidget(); + colorPickerWidget.target(this.colorText, ColorUtil.RED, false, true, pickedColor -> {}); + colorPickerWidget.setConfirmListener(this::insertHexColor); + colorPickerWidget.setPresetListener(preset -> { + if (preset.getPresetFormatting() != null) this.insertFormattingTag(preset.getPresetFormatting()); + colorPickerWidget.hide(); + }); // ColorPickerWidget colorPickerWidget = getColorPickerWidget(); // colorPickerWidget.setPosition(216, 10); // colorPickerWidget.setTargetElement(this.colorText); diff --git a/src/main/java/dev/hephaestus/glowcase/client/gui/widget/ingame/color/picker/ColorPickerWidget.java b/src/main/java/dev/hephaestus/glowcase/client/gui/widget/ingame/color/picker/ColorPickerWidget.java index cc283c10..e42b156d 100644 --- a/src/main/java/dev/hephaestus/glowcase/client/gui/widget/ingame/color/picker/ColorPickerWidget.java +++ b/src/main/java/dev/hephaestus/glowcase/client/gui/widget/ingame/color/picker/ColorPickerWidget.java @@ -24,6 +24,7 @@ import java.util.Iterator; import java.util.List; +import java.util.function.Consumer; /** * Main color picker widget, including a preview box, saturation & value box, hue slider, optional alpha slider, and color presets.

@@ -41,15 +42,12 @@ public class ColorPickerWidget extends AbstractButton { private static final int DEFAULT_HEIGHT = 116; private static final int DEFAULT_ALPHA_HEIGHT = 146; private static final Identifier BACKGROUND_TEXTURE = Identifier.withDefaultNamespace("textures/gui/inworld_menu_list_background.png"); + // Different alpha textures have different tile sizes to better match their background private static final Identifier ALPHA_PREVIEW_TEXTURE = Glowcase.id("color_picker/alpha_preview"); private static final Identifier ALPHA_SLIDER_TEXTURE = Glowcase.id("color_picker/alpha_slider"); private static final Identifier ALPHA_THUMB_TEXTURE = Glowcase.id("color_picker/alpha_thumb"); private static final Identifier ALPHA_PRESET_TEXTURE = Glowcase.id("color_picker/alpha_preset"); - private static final Identifier CONFIRM_TEXTURE = Identifier.withDefaultNamespace("pending_invite/accept"); - private static final Identifier CONFIRM_HIGHLIGHTED_TEXTURE = Identifier.withDefaultNamespace("pending_invite/accept_highlighted"); - private static final Identifier CANCEL_TEXTURE = Identifier.withDefaultNamespace("pending_invite/reject"); - private static final Identifier CANCEL_HIGHLIGHTED_TEXTURE = Identifier.withDefaultNamespace("pending_invite/reject_highlighted"); public final ColorPickerIncludedScreen screen; @Nullable @@ -58,6 +56,8 @@ public class ColorPickerWidget extends AbstractButton { public ColorSetter pickedColorListener = null; @Nullable public PickerPresetListener presetListener = null; + @Nullable + public Consumer confirmListener = null; public boolean showAlpha = false; public final List clickableAreas; @@ -68,6 +68,7 @@ public class ColorPickerWidget extends AbstractButton { public PickerArea presetsArea; public List formattingPresetAreas; public List alphaPresetAreas; + public List buttonAreas; @Nullable public PickerArea currentClickedArea = null; // Used for allowing mouse drags beyond an area's boundaries @@ -90,14 +91,14 @@ public ColorPickerWidget(ColorPickerIncludedScreen screen, int x, int y, int wid this.presetsArea = new PickerArea(this, false); this.formattingPresetAreas = PickerPreset.createFormattingPresets(this); this.alphaPresetAreas = PickerPreset.createAlphaPresets(this); + this.buttonAreas = PickerButton.createButtons(this); this.updateAreas(); -// this.areas = List.of(this.previewArea, this.satValueArea, this.hueArea, this.alphaArea, this.presetsArea); this.clickableAreas = List.of(this.satValueArea, this.hueArea, this.alphaArea); this.hide(); // Start hidden } - // Preset width & height: 16 + // Preset & button width & height: 16 // Presets per row: 10 (2 rows by default, 3 if alpha is shown) // Hue & Alpha slider heights: 10 // Preview & Sat/value picker: Whatever height is left @@ -135,6 +136,14 @@ public void updateAreas() { preset.set(x, y, 16, 16); } } + + for (int i = 0; i < this.buttonAreas.size(); i++) { + // First button is confirm, second is cancel, so start from far right and shift left + PickerButton button = this.buttonAreas.get(i); + int x = this.getX() + this.getWidth() - (18 * (i + 1)); + int y = this.presetsArea.getY() + (18 * (this.showAlpha ? 2 : 1)); + button.set(x, y, 16, 16); + } } // Position the thumbs based on the current color @@ -152,67 +161,78 @@ protected void extractContents(GuiGraphicsExtractor graphics, int mouseX, int mo graphics.blit(RenderPipelines.GUI_TEXTURED, BACKGROUND_TEXTURE, this.getX(), this.getY(), 0, 0, this.getWidth(), this.getHeight(), 32, 32); // Render areas -// extractPreviewArea(this.previewArea, graphics, this.getColor()); - extractPreviewArea(this.previewArea, graphics); - extractSatValueArea(this.satValueArea, graphics); - extractHueArea(this.hueArea, graphics); - if (showAlpha) extractAlphaArea(this.alphaArea, graphics); + this.extractPreviewArea(this.previewArea, graphics); + this.extractSatValueArea(this.satValueArea, graphics, mouseX, mouseY); + this.extractHueArea(this.hueArea, graphics, mouseX, mouseY); + if (showAlpha) this.extractAlphaArea(this.alphaArea, graphics, mouseX, mouseY); for (PickerPreset preset : this.formattingPresetAreas) { - extractPresetArea(preset, graphics, false); + this.extractPresetArea(preset, graphics, false, mouseX, mouseY); } if (showAlpha) { for (PickerPreset preset : this.alphaPresetAreas) { - extractPresetArea(preset, graphics, true); + this.extractPresetArea(preset, graphics, true, mouseX, mouseY); } } -// extractPreviewArea(this.presetsArea, graphics, CommonColors.WHITE); + for (PickerButton button : buttonAreas) { + this.extractButtonArea(button, graphics, mouseX, mouseY); + } // Render thumbs (to ensure they are above everything despite overlaps) - extractThumb(graphics, this.hueArea.getThumbX(), this.hueArea.getY() + 5, 6, 12, this.getHueColor()); - if (showAlpha) extractThumb(graphics, this.alphaArea.getThumbX(), this.alphaArea.getY() + 5, 6, 12, this.getColor(), true); - extractThumb(graphics, this.satValueArea.getThumbX(), this.satValueArea.getThumbY(), 8, 8, this.getColorNoAlpha()); + this.extractThumb(graphics, this.hueArea.getThumbX(), this.hueArea.getY() + 5, 6, 12, this.getHueColor()); + if (showAlpha) this.extractThumb(graphics, this.alphaArea.getThumbX(), this.alphaArea.getY() + 5, 6, 12, this.getColor(), true); + this.extractThumb(graphics, this.satValueArea.getThumbX(), this.satValueArea.getThumbY(), 8, 8, this.getColorNoAlpha()); } public void extractPreviewArea(PickerArea area, GuiGraphicsExtractor graphics) { // TODO - Precise tile of the background for my perfectionism here // Alpha background texture (if needed) if (this.showAlpha) graphics.blitSprite(RenderPipelines.GUI_TEXTURED, ALPHA_PREVIEW_TEXTURE, area.getX(), area.getY(), area.getWidth(), area.getHeight()); - // Current color graphics.fill(area.getX(), area.getY(), area.getX2(), area.getY2(), this.getColor()); } - public void extractSatValueArea(PickerArea area, GuiGraphicsExtractor graphics) { + public void extractSatValueArea(PickerArea area, GuiGraphicsExtractor graphics, int mouseX, int mouseY) { // White to current hue, left to right GuiGraphicsUtil.extractHorizontalGradient(graphics, area.getX(), area.getY(), area.getX2(), area.getY2(), ColorUtil.WHITE, this.getHueColor()); - // Transparent to black, top to bottom graphics.fillGradient(area.getX(), area.getY(), area.getX2(), area.getY2(), ColorUtil.TRANSPARENT, ColorUtil.BLACK); + // Outline + if (area.shouldOutline(mouseX, mouseY)) graphics.outline(area.getX(), area.getY(), area.getWidth(), area.getHeight(), ColorUtil.WHITE); } - public void extractHueArea(PickerArea area, GuiGraphicsExtractor graphics) { + public void extractHueArea(PickerArea area, GuiGraphicsExtractor graphics, int mouseX, int mouseY) { // Hue gradient, starting and ending on red GuiGraphicsUtil.extractHueGradient(graphics, area.getX(), area.getY(), area.getX2(), area.getY2()); + // Outline + if (area.shouldOutline(mouseX, mouseY)) graphics.outline(area.getX(), area.getY(), area.getWidth(), area.getHeight(), ColorUtil.WHITE); } - public void extractAlphaArea(PickerArea area, GuiGraphicsExtractor graphics) { + public void extractAlphaArea(PickerArea area, GuiGraphicsExtractor graphics, int mouseX, int mouseY) { // Alpha background texture graphics.blitSprite(RenderPipelines.GUI_TEXTURED, ALPHA_SLIDER_TEXTURE, area.getX(), area.getY(), area.getWidth(), area.getHeight()); - // Transparent to current color, left to right GuiGraphicsUtil.extractHorizontalGradient(graphics, area.getX(), area.getY(), area.getX2(), area.getY2(), ColorUtil.TRANSPARENT, this.getColorNoAlpha()); + // Outline + if (area.shouldOutline(mouseX, mouseY)) graphics.outline(area.getX(), area.getY(), area.getWidth(), area.getHeight(), ColorUtil.WHITE); } - public void extractPresetArea(PickerPreset preset, GuiGraphicsExtractor graphics, boolean alphaPreset) { + public void extractPresetArea(PickerPreset preset, GuiGraphicsExtractor graphics, boolean alphaPreset, int mouseX, int mouseY) { // Alpha background texture (if needed) if (alphaPreset) graphics.blitSprite(RenderPipelines.GUI_TEXTURED, ALPHA_PRESET_TEXTURE, preset.getX(), preset.getY(), preset.getWidth(), preset.getHeight()); graphics.fill(preset.getX(), preset.getY(), preset.getX2(), preset.getY2(), preset.getPresetColor()); - + // Alpha preset tooltip if (alphaPreset) { - // FIXME - Please figure out a better way of doing this than whatever on earth this is - String hex = ColorUtil.toAlphaHex(preset.getPresetColor()); - graphics.text(Minecraft.getInstance().font, String.valueOf(hex.charAt(1)) + String.valueOf(hex.charAt(2)), preset.getX(), preset.getY() + 8, ColorUtil.WHITE); + // I'll be honest I have no clue how this works, I just got lucky + String hex = String.format("%1$02X", ARGB.alpha(preset.getPresetColor())); + graphics.text(Minecraft.getInstance().font, hex, preset.getX() + 1, preset.getY() + 7, ColorUtil.WHITE); } + // Outline + if (preset.shouldOutline(mouseX, mouseY)) graphics.outline(preset.getX(), preset.getY(), preset.getWidth(), preset.getHeight(), ColorUtil.WHITE); + } + + public void extractButtonArea(PickerButton button, GuiGraphicsExtractor graphics, int mouseX, int mouseY) { + // TODO - PLEASE precise texture this it'll annoy me so much + graphics.blitSprite(RenderPipelines.GUI_TEXTURED, button.getTexture(mouseX, mouseY), button.getX(), button.getY(), button.getWidth(), button.getHeight()); } public void extractThumb(GuiGraphicsExtractor graphics, int thumbX, int thumbY, int thumbWidth, int thumbHeight, int thumbColor) { @@ -235,20 +255,26 @@ public void extractThumb(GuiGraphicsExtractor graphics, int thumbX, int thumbY, // endregion + public void target(AbstractWidget widget, int initColor, boolean showAlpha, ColorSetter pickedColorListener) { + this.target(widget, initColor, showAlpha, false, pickedColorListener); + } + /** * Position & set up the Color Picker based on a widget and its needs. Positioning accounts for screen size, ensuring the color picker never goes off-screen. - * @param widget The Widget to position the Color Picker too - * @param initColor The initial color the Color Picker should be, and should revert to if canceled/undone - * @param showAlpha Whether the alpha should be editable, and the alpha slider visible - * @param pickedColorSetterListener What to do with the picked color, as an integer + * @param widget The Widget to position the Color Picker too. + * @param initColor The initial color the Color Picker should be, and should revert to if canceled/undone. + * @param showAlpha Whether the alpha should be editable, and the alpha slider visible. + * @param rightAligned If the Color Picker Widget should align itself to the right side of the widget instead of the left side . + * @param pickedColorListener What to do with the picked color, as an integer. */ - public void target(AbstractWidget widget, int initColor, boolean showAlpha, ColorSetter pickedColorSetterListener) { + public void target(AbstractWidget widget, int initColor, boolean showAlpha, boolean rightAligned, ColorSetter pickedColorListener) { this.visible = true; this.active = true; this.targetElement = widget; - // TODO - right-aligned option + // Ensure at least 2 pixels of padding between screen edges int x = Math.min(Minecraft.getInstance().screen.width - this.getWidth() - 2, widget.getX()); + if (rightAligned) x = Math.max(2, widget.getX() + widget.getWidth() - this.getWidth() + 2); int y = widget.getY() + widget.getHeight(); this.setX(x); this.setY(y); @@ -259,7 +285,7 @@ public void target(AbstractWidget widget, int initColor, boolean showAlpha, Colo this.showAlpha = showAlpha; this.setHeight(this.showAlpha ? DEFAULT_ALPHA_HEIGHT : DEFAULT_HEIGHT); - this.pickedColorListener = pickedColorSetterListener; + this.pickedColorListener = pickedColorListener; this.presetListener = preset -> { // Default preset behaviour, just set the picker color if (preset.isAlphaPreset()) { this.alpha = preset.getAlpha(); @@ -268,6 +294,7 @@ public void target(AbstractWidget widget, int initColor, boolean showAlpha, Colo this.setColor(preset.getPresetColor(), false); } }; + this.confirmListener = null; this.updateAreas(); this.updateAreaThumbs(); @@ -277,6 +304,10 @@ public void setPresetListener(PickerPresetListener presetListener) { this.presetListener = presetListener; } + public void setConfirmListener(Consumer confirmListener) { + this.confirmListener = confirmListener; + } + public void setColor(int color) { this.setColor(color, true); } @@ -305,6 +336,11 @@ public void setPrevColor(int color) { this.prevAlpha = HSBA[3]; } + public void confirm() { + if (this.confirmListener != null) this.confirmListener.accept(this.getColor()); + this.hide(); + } + public void cancel() { int prevColor = ColorUtil.HSBAtoARGB(this.prevHue, this.prevSaturation, this.prevValue, this.showAlpha ? this.prevAlpha : 1f); this.setColor(prevColor); @@ -319,6 +355,7 @@ public void hide() { this.pickedColorListener = null; this.presetListener = null; + this.confirmListener = null; } @Override @@ -375,6 +412,13 @@ public void tryClickAreas(MouseButtonEvent event) { return; } } + + for (PickerButton button : buttonAreas) { + if (button.mouseClicked(x, y)) { + this.currentClickedArea = button; + return; + } + } } public void onPresetClick(PickerPreset preset) { diff --git a/src/main/java/dev/hephaestus/glowcase/client/gui/widget/ingame/color/picker/PickerArea.java b/src/main/java/dev/hephaestus/glowcase/client/gui/widget/ingame/color/picker/PickerArea.java index ce5edc5d..6ebc1289 100644 --- a/src/main/java/dev/hephaestus/glowcase/client/gui/widget/ingame/color/picker/PickerArea.java +++ b/src/main/java/dev/hephaestus/glowcase/client/gui/widget/ingame/color/picker/PickerArea.java @@ -76,6 +76,11 @@ public boolean isMouseOver(double mouseX, double mouseY) { && (mouseX > this.getX() && mouseX < this.getX2()); } + public boolean shouldOutline(int mouseX, int mouseY) { + // Outline if mouse down, or if the mouse over AND no other area has the mouse down + return this.hasMouseDown() || (this.isMouseOver(mouseX, mouseY) && this.getColorPicker().currentClickedArea == null); + } + private float calcLerp(double mousePos, int minPos, int maxPos) { if (mousePos < minPos) return 0f; if (mousePos > maxPos) return 1f; diff --git a/src/main/java/dev/hephaestus/glowcase/client/gui/widget/ingame/color/picker/PickerButton.java b/src/main/java/dev/hephaestus/glowcase/client/gui/widget/ingame/color/picker/PickerButton.java new file mode 100644 index 00000000..24a76ff0 --- /dev/null +++ b/src/main/java/dev/hephaestus/glowcase/client/gui/widget/ingame/color/picker/PickerButton.java @@ -0,0 +1,43 @@ +package dev.hephaestus.glowcase.client.gui.widget.ingame.color.picker; + +import net.minecraft.resources.Identifier; + +import java.util.List; + +public class PickerButton extends PickerArea { + private static final Identifier CONFIRM_TEXTURE = Identifier.withDefaultNamespace("pending_invite/accept"); + private static final Identifier CONFIRM_HIGHLIGHTED_TEXTURE = Identifier.withDefaultNamespace("pending_invite/accept_highlighted"); + private static final Identifier CANCEL_TEXTURE = Identifier.withDefaultNamespace("pending_invite/reject"); + private static final Identifier CANCEL_HIGHLIGHTED_TEXTURE = Identifier.withDefaultNamespace("pending_invite/reject_highlighted"); + + private final Identifier texture; + private final Identifier hoverTexture; + private final Runnable clickListener; + + public static List createButtons(ColorPickerWidget colorPickerWidget) { + return List.of( + new PickerButton(colorPickerWidget, CONFIRM_TEXTURE, CONFIRM_HIGHLIGHTED_TEXTURE, colorPickerWidget::confirm), + new PickerButton(colorPickerWidget, CANCEL_TEXTURE, CANCEL_HIGHLIGHTED_TEXTURE, colorPickerWidget::cancel) + ); + } + + public PickerButton(ColorPickerWidget colorPicker, Identifier texture, Identifier hoverTexture, Runnable clickListener) { + super(colorPicker, true, null, null); + this.texture = texture; + this.hoverTexture = hoverTexture; + this.clickListener = clickListener; + } + + @Override + public boolean mouseClicked(double mouseX, double mouseY) { + if (this.isMouseOver(mouseX, mouseY)) { + this.clickListener.run(); + return true; + } + return super.mouseClicked(mouseX, mouseY); + } + + public Identifier getTexture(int mouseX, int mouseY) { + return this.isMouseOver(mouseX, mouseY) ? this.hoverTexture : this.texture; + } +} From 692b243566c43e87205cc79503a6df6017bd5546 Mon Sep 17 00:00:00 2001 From: Kat Date: Fri, 17 Jul 2026 10:44:24 -0400 Subject: [PATCH 3/9] Feat: Improve color picker button scaling & precise preview alpha background drawing --- .../color/picker/ColorPickerWidget.java | 9 ++- .../ingame/color/picker/PickerButton.java | 23 +++++- .../glowcase/client/util/GuiGraphicsUtil.java | 71 ++++++++++++++++--- 3 files changed, 85 insertions(+), 18 deletions(-) diff --git a/src/main/java/dev/hephaestus/glowcase/client/gui/widget/ingame/color/picker/ColorPickerWidget.java b/src/main/java/dev/hephaestus/glowcase/client/gui/widget/ingame/color/picker/ColorPickerWidget.java index e42b156d..54b57426 100644 --- a/src/main/java/dev/hephaestus/glowcase/client/gui/widget/ingame/color/picker/ColorPickerWidget.java +++ b/src/main/java/dev/hephaestus/glowcase/client/gui/widget/ingame/color/picker/ColorPickerWidget.java @@ -99,7 +99,7 @@ public ColorPickerWidget(ColorPickerIncludedScreen screen, int x, int y, int wid } // Preset & button width & height: 16 - // Presets per row: 10 (2 rows by default, 3 if alpha is shown) + // Presets per row: 10 (2 rows by default, 3 rows if alpha is shown) // Hue & Alpha slider heights: 10 // Preview & Sat/value picker: Whatever height is left // Preview width: 1/3 of picker padded width @@ -184,9 +184,8 @@ protected void extractContents(GuiGraphicsExtractor graphics, int mouseX, int mo } public void extractPreviewArea(PickerArea area, GuiGraphicsExtractor graphics) { - // TODO - Precise tile of the background for my perfectionism here // Alpha background texture (if needed) - if (this.showAlpha) graphics.blitSprite(RenderPipelines.GUI_TEXTURED, ALPHA_PREVIEW_TEXTURE, area.getX(), area.getY(), area.getWidth(), area.getHeight()); + if (this.showAlpha) GuiGraphicsUtil.drawPreciseTile(graphics, ALPHA_PREVIEW_TEXTURE, area.getX(), area.getY(), area.getX2(), area.getY2(), 8, 7); // Current color graphics.fill(area.getX(), area.getY(), area.getX2(), area.getY2(), this.getColor()); } @@ -231,8 +230,8 @@ public void extractPresetArea(PickerPreset preset, GuiGraphicsExtractor graphics } public void extractButtonArea(PickerButton button, GuiGraphicsExtractor graphics, int mouseX, int mouseY) { - // TODO - PLEASE precise texture this it'll annoy me so much - graphics.blitSprite(RenderPipelines.GUI_TEXTURED, button.getTexture(mouseX, mouseY), button.getX(), button.getY(), button.getWidth(), button.getHeight()); +// graphics.fill(button.getX(), button.getY(), button.getX2(), button.getY2(), ColorUtil.RED); + graphics.blitSprite(RenderPipelines.GUI_TEXTURED, button.getTexture(mouseX, mouseY), button.getX() - button.getPadX(), button.getY() - button.getPadY(), button.getWidth() + button.getPadScale(), button.getHeight() + button.getPadScale()); } public void extractThumb(GuiGraphicsExtractor graphics, int thumbX, int thumbY, int thumbWidth, int thumbHeight, int thumbColor) { diff --git a/src/main/java/dev/hephaestus/glowcase/client/gui/widget/ingame/color/picker/PickerButton.java b/src/main/java/dev/hephaestus/glowcase/client/gui/widget/ingame/color/picker/PickerButton.java index 24a76ff0..9b467aed 100644 --- a/src/main/java/dev/hephaestus/glowcase/client/gui/widget/ingame/color/picker/PickerButton.java +++ b/src/main/java/dev/hephaestus/glowcase/client/gui/widget/ingame/color/picker/PickerButton.java @@ -13,18 +13,23 @@ public class PickerButton extends PickerArea { private final Identifier texture; private final Identifier hoverTexture; private final Runnable clickListener; + // Padding on the texture rendering because the icons aren't (and physically can't be) centered on the pixel grid + private final int padX, padY, padScale; public static List createButtons(ColorPickerWidget colorPickerWidget) { return List.of( - new PickerButton(colorPickerWidget, CONFIRM_TEXTURE, CONFIRM_HIGHLIGHTED_TEXTURE, colorPickerWidget::confirm), - new PickerButton(colorPickerWidget, CANCEL_TEXTURE, CANCEL_HIGHLIGHTED_TEXTURE, colorPickerWidget::cancel) + new PickerButton(colorPickerWidget, CONFIRM_TEXTURE, CONFIRM_HIGHLIGHTED_TEXTURE, 1, 1, 2, colorPickerWidget::confirm), + new PickerButton(colorPickerWidget, CANCEL_TEXTURE, CANCEL_HIGHLIGHTED_TEXTURE, 2, 1, 3, colorPickerWidget::cancel) ); } - public PickerButton(ColorPickerWidget colorPicker, Identifier texture, Identifier hoverTexture, Runnable clickListener) { + public PickerButton(ColorPickerWidget colorPicker, Identifier texture, Identifier hoverTexture, int padX, int padY, int padScale, Runnable clickListener) { super(colorPicker, true, null, null); this.texture = texture; this.hoverTexture = hoverTexture; + this.padX = padX; + this.padY = padY; + this.padScale = padScale; this.clickListener = clickListener; } @@ -40,4 +45,16 @@ public boolean mouseClicked(double mouseX, double mouseY) { public Identifier getTexture(int mouseX, int mouseY) { return this.isMouseOver(mouseX, mouseY) ? this.hoverTexture : this.texture; } + + public int getPadX() { + return padX; + } + + public int getPadY() { + return padY; + } + + public int getPadScale() { + return padScale; + } } diff --git a/src/main/java/dev/hephaestus/glowcase/client/util/GuiGraphicsUtil.java b/src/main/java/dev/hephaestus/glowcase/client/util/GuiGraphicsUtil.java index 3ee54bd3..ecfd4ac9 100644 --- a/src/main/java/dev/hephaestus/glowcase/client/util/GuiGraphicsUtil.java +++ b/src/main/java/dev/hephaestus/glowcase/client/util/GuiGraphicsUtil.java @@ -1,8 +1,6 @@ package dev.hephaestus.glowcase.client.util; import com.mojang.blaze3d.pipeline.RenderPipeline; -import com.mojang.blaze3d.textures.GpuTexture; -import com.mojang.blaze3d.textures.GpuTextureView; import com.mojang.blaze3d.vertex.VertexConsumer; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiGraphicsExtractor; @@ -80,13 +78,66 @@ public static void extractHueGradient(GuiGraphicsExtractor graphics, int x0, int } } -// public static void drawPreciseTile(GuiGraphicsExtractor graphics, Identifier spriteId, int x0, int y0, int x1, int y1, float rows, float columns) { -// TextureAtlasSprite sprite = Minecraft.getInstance().getAtlasManager().getAtlasOrThrow(AtlasIds.GUI).getSprite(spriteId); -// AbstractTexture spriteTexture = Minecraft.getInstance().getTextureManager().getTexture(sprite.atlasLocation()); -// GpuTextureView texture = spriteTexture.getTextureView(); -// -// } -// -// public static void drawPreciseTexture(GuiGraphicsExtractor graphics, GpuTexture) + /** + * Tile a texture across an area with precise texture placement. Allows for better tiling of textures within an integer bounds than otherwise possible. + */ + public static void drawPreciseTile(GuiGraphicsExtractor graphics, Identifier spriteId, int x0, int y0, int x1, int y1, float rows, float columns) { + TextureAtlasSprite sprite = Minecraft.getInstance().getAtlasManager().getAtlasOrThrow(AtlasIds.GUI).getSprite(spriteId); + AbstractTexture spriteTexture = Minecraft.getInstance().getTextureManager().getTexture(sprite.atlasLocation()); + float width = x1 - x0; + float height = y1 - y0; + float tileWidth = width / columns; + float tileHeight = height / rows; + for (int iX = 0; iX < columns; iX++) { + float tileX = x0 + (tileWidth * iX); + for (int iY = 0; iY < rows; iY++) { + float tileY = y0 + (tileHeight * iY); + drawPreciseTexture( + graphics, spriteTexture, + tileX, tileY, tileX + tileWidth, tileY + tileHeight, + sprite.getU0(), sprite.getU1(), sprite.getV0(), sprite.getV1() + ); + } + } + } + + /** + * Draw a texture with precise placement beyond the normal integer grid of GUI rendering. + */ + public static void drawPreciseTexture(GuiGraphicsExtractor graphics, AbstractTexture texture, float x0, float y0, float x1, float y1, float u0, float u1, float v0, float v1) { + graphics.guiRenderState.addGuiElement( + new GuiElementRenderState() { + @Override + public void buildVertices(@NonNull VertexConsumer vertexConsumer) { + Matrix3x2fStack matrix = graphics.pose(); + int color = -1; + vertexConsumer.addVertexWith2DPose(matrix, x0, y0).setUv(u0, v0).setColor(color); + vertexConsumer.addVertexWith2DPose(matrix, x0, y1).setUv(u0, v1).setColor(color); + vertexConsumer.addVertexWith2DPose(matrix, x1, y1).setUv(u1, v1).setColor(color); + vertexConsumer.addVertexWith2DPose(matrix, x1, y0).setUv(u1, v0).setColor(color); + } + + @Override + public @NonNull RenderPipeline pipeline() { + return RenderPipelines.GUI_TEXTURED; + } + + @Override + public @NonNull TextureSetup textureSetup() { + return TextureSetup.singleTexture(texture.getTextureView(), texture.getSampler()); + } + + @Override + public @Nullable ScreenRectangle scissorArea() { + return null; + } + + @Override + public @NonNull ScreenRectangle bounds() { + return new ScreenRectangle((int) x0, (int) y0, (int) (x1 - x0), (int) (y1 - y0)).transformMaxBounds(graphics.pose()); + } + } + ); + } } From ef8955b7b7e8904f6c2209f7720fe2b7373c807d Mon Sep 17 00:00:00 2001 From: Kat Date: Fri, 17 Jul 2026 10:48:28 -0400 Subject: [PATCH 4/9] Feat: Better Color Picker cursor shenanigans --- .../color/picker/ColorPickerWidget.java | 28 +++++++++++++++---- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/src/main/java/dev/hephaestus/glowcase/client/gui/widget/ingame/color/picker/ColorPickerWidget.java b/src/main/java/dev/hephaestus/glowcase/client/gui/widget/ingame/color/picker/ColorPickerWidget.java index 54b57426..0319f634 100644 --- a/src/main/java/dev/hephaestus/glowcase/client/gui/widget/ingame/color/picker/ColorPickerWidget.java +++ b/src/main/java/dev/hephaestus/glowcase/client/gui/widget/ingame/color/picker/ColorPickerWidget.java @@ -1,5 +1,6 @@ package dev.hephaestus.glowcase.client.gui.widget.ingame.color.picker; +import com.mojang.blaze3d.platform.cursor.CursorTypes; import dev.hephaestus.glowcase.Glowcase; import dev.hephaestus.glowcase.client.gui.screen.ingame.ColorPickerIncludedScreen; import dev.hephaestus.glowcase.client.gui.widget.ingame.color.functional.ColorSetter; @@ -196,14 +197,20 @@ public void extractSatValueArea(PickerArea area, GuiGraphicsExtractor graphics, // Transparent to black, top to bottom graphics.fillGradient(area.getX(), area.getY(), area.getX2(), area.getY2(), ColorUtil.TRANSPARENT, ColorUtil.BLACK); // Outline - if (area.shouldOutline(mouseX, mouseY)) graphics.outline(area.getX(), area.getY(), area.getWidth(), area.getHeight(), ColorUtil.WHITE); + if (area.shouldOutline(mouseX, mouseY)) { + graphics.outline(area.getX(), area.getY(), area.getWidth(), area.getHeight(), ColorUtil.WHITE); + graphics.requestCursor(CursorTypes.POINTING_HAND); + } } public void extractHueArea(PickerArea area, GuiGraphicsExtractor graphics, int mouseX, int mouseY) { // Hue gradient, starting and ending on red GuiGraphicsUtil.extractHueGradient(graphics, area.getX(), area.getY(), area.getX2(), area.getY2()); // Outline - if (area.shouldOutline(mouseX, mouseY)) graphics.outline(area.getX(), area.getY(), area.getWidth(), area.getHeight(), ColorUtil.WHITE); + if (area.shouldOutline(mouseX, mouseY)) { + graphics.outline(area.getX(), area.getY(), area.getWidth(), area.getHeight(), ColorUtil.WHITE); + graphics.requestCursor(CursorTypes.POINTING_HAND); + } } public void extractAlphaArea(PickerArea area, GuiGraphicsExtractor graphics, int mouseX, int mouseY) { @@ -212,7 +219,10 @@ public void extractAlphaArea(PickerArea area, GuiGraphicsExtractor graphics, int // Transparent to current color, left to right GuiGraphicsUtil.extractHorizontalGradient(graphics, area.getX(), area.getY(), area.getX2(), area.getY2(), ColorUtil.TRANSPARENT, this.getColorNoAlpha()); // Outline - if (area.shouldOutline(mouseX, mouseY)) graphics.outline(area.getX(), area.getY(), area.getWidth(), area.getHeight(), ColorUtil.WHITE); + if (area.shouldOutline(mouseX, mouseY)) { + graphics.outline(area.getX(), area.getY(), area.getWidth(), area.getHeight(), ColorUtil.WHITE); + graphics.requestCursor(CursorTypes.POINTING_HAND); + } } public void extractPresetArea(PickerPreset preset, GuiGraphicsExtractor graphics, boolean alphaPreset, int mouseX, int mouseY) { @@ -226,12 +236,15 @@ public void extractPresetArea(PickerPreset preset, GuiGraphicsExtractor graphics graphics.text(Minecraft.getInstance().font, hex, preset.getX() + 1, preset.getY() + 7, ColorUtil.WHITE); } // Outline - if (preset.shouldOutline(mouseX, mouseY)) graphics.outline(preset.getX(), preset.getY(), preset.getWidth(), preset.getHeight(), ColorUtil.WHITE); + if (preset.shouldOutline(mouseX, mouseY)) { + graphics.outline(preset.getX(), preset.getY(), preset.getWidth(), preset.getHeight(), ColorUtil.WHITE); + graphics.requestCursor(CursorTypes.POINTING_HAND); + } } public void extractButtonArea(PickerButton button, GuiGraphicsExtractor graphics, int mouseX, int mouseY) { -// graphics.fill(button.getX(), button.getY(), button.getX2(), button.getY2(), ColorUtil.RED); graphics.blitSprite(RenderPipelines.GUI_TEXTURED, button.getTexture(mouseX, mouseY), button.getX() - button.getPadX(), button.getY() - button.getPadY(), button.getWidth() + button.getPadScale(), button.getHeight() + button.getPadScale()); + if (button.isMouseOver(mouseX, mouseY)) graphics.requestCursor(CursorTypes.POINTING_HAND); } public void extractThumb(GuiGraphicsExtractor graphics, int thumbX, int thumbY, int thumbWidth, int thumbHeight, int thumbColor) { @@ -252,6 +265,11 @@ public void extractThumb(GuiGraphicsExtractor graphics, int thumbX, int thumbY, graphics.outline(x, y, thumbWidth, thumbHeight, ColorUtil.WHITE); } + @Override + protected void handleCursor(GuiGraphicsExtractor graphics) { + // NO-OP + } + // endregion public void target(AbstractWidget widget, int initColor, boolean showAlpha, ColorSetter pickedColorListener) { From 8bb3c44b52b6a9b55ac49841afb4f9f1b157064b Mon Sep 17 00:00:00 2001 From: Kat Date: Fri, 17 Jul 2026 11:39:58 -0400 Subject: [PATCH 5/9] Feat: Add color pickers to Sprite, Outline, Popup, and Text Block Properties screens --- .../ingame/ColorPickerIncludedScreen.java | 31 ++++-- .../screen/ingame/OutlineBlockEditScreen.java | 55 ++++++++-- .../screen/ingame/PopupBlockEditScreen.java | 39 +++++-- .../screen/ingame/SpriteBlockEditScreen.java | 18 ++- .../screen/ingame/TextBlockEditScreen.java | 15 +-- .../screen/ingame/TextBlockOptionsScreen.java | 103 +++++++++++++----- .../widget/ingame/color/HexColorEditBox.java | 23 +--- .../color/picker/ColorPickerWidget.java | 9 +- 8 files changed, 207 insertions(+), 86 deletions(-) diff --git a/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/ColorPickerIncludedScreen.java b/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/ColorPickerIncludedScreen.java index 41f7e87e..cb20793d 100644 --- a/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/ColorPickerIncludedScreen.java +++ b/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/ColorPickerIncludedScreen.java @@ -3,8 +3,7 @@ import dev.hephaestus.glowcase.client.gui.widget.ingame.color.picker.ColorPickerWidget; import dev.hephaestus.glowcase.client.util.ColorUtil; import net.minecraft.ChatFormatting; -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.components.AbstractWidget; +import net.minecraft.client.gui.GuiGraphicsExtractor; import net.minecraft.client.gui.components.events.GuiEventListener; import net.minecraft.client.gui.screens.Screen; import net.minecraft.client.input.KeyEvent; @@ -13,11 +12,29 @@ /** * Main interface for any Screen wishing to implement a {@link ColorPickerWidget}.

- * Each ColorPickerIncludedScreen has *one* Color Picker widget which gets shared among all things using it. + * Each ColorPickerIncludedScreen has *one* Color Picker widget which gets shared among all things using it.
+ * Steps for adding a Color Picker to a screen: + *
    + *
  1. Implement this interface, and return a private ColorPickerWidget in {@link ColorPickerIncludedScreen#getColorPickerWidget()}.
  2. + *
  3. Initialize your ColorPickerWidget in {@link Screen#init()} via {@link ColorPickerWidget#builder(ColorPickerIncludedScreen)}. You do *not* need to add it as a renderableWidget.
  4. + *
  5. Include {@link ColorPickerIncludedScreen#extractColorPicker(GuiGraphicsExtractor, int, int, float)} at the very bottom of {@link Screen#extractRenderState(GuiGraphicsExtractor, int, int, float)} to ensure it renders atop of everything else.
  6. + *
  7. Include {@link ColorPickerIncludedScreen#mouseClickedColorPicker(MouseButtonEvent, boolean)} at the very top of {@link Screen#mouseClicked(MouseButtonEvent, boolean)}, return true if color picker was clicked, otherwise continue with method.
  8. + *
  9. Include {@link ColorPickerIncludedScreen#keyPressedColorPicker(KeyEvent)} at the very top of {@link Screen#keyPressed(KeyEvent)}, return true if color picker key pressed, otherwise continue with method.
  10. + *
  11. Booyah!
  12. + *
+ * @author Superkat32 */ public interface ColorPickerIncludedScreen { ColorPickerWidget getColorPickerWidget(); + default ColorPickerWidget createColorPickerWidget() { + return ColorPickerWidget.builder(this).build(); + } + + default void extractColorPicker(GuiGraphicsExtractor graphics, int mouseX, int mouseY, float delta) { + this.getColorPickerWidget().extractRenderState(graphics, mouseX, mouseY, delta); + } + default boolean mouseClickedColorPicker(MouseButtonEvent event, boolean doubleClick) { double mouseX = event.x(); double mouseY = event.y(); @@ -60,17 +77,13 @@ default boolean keyPressedColorPicker(KeyEvent event) { return false; } -// default void setColorPickerTarget(GuiEventListener element) { -// this.getColorPickerWidget().target(element); -// } - default void hideColorPickerWidget() { this.getColorPickerWidget().hide(); } // TODO - break this into FormattableScreen - void insertHexTag(String hex); - void insertFormattingTag(ChatFormatting formatting); + default void insertHexTag(String hex) {} + default void insertFormattingTag(ChatFormatting formatting) {} default void insertHexColor(int color) { String hex = ColorUtil.toHex(color); this.insertHexTag(hex); diff --git a/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/OutlineBlockEditScreen.java b/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/OutlineBlockEditScreen.java index 4ae93263..2f12f7a1 100644 --- a/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/OutlineBlockEditScreen.java +++ b/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/OutlineBlockEditScreen.java @@ -3,19 +3,23 @@ import com.google.common.primitives.Ints; import dev.hephaestus.glowcase.block.entity.OutlineBlockEntity; import dev.hephaestus.glowcase.client.gui.widget.ingame.GlowcaseEditBox; +import dev.hephaestus.glowcase.client.gui.widget.ingame.color.HexColorEditBox; +import dev.hephaestus.glowcase.client.gui.widget.ingame.color.picker.ColorPickerWidget; import dev.hephaestus.glowcase.packet.C2SEditOutlineBlock; import dev.hephaestus.glowcase.util.InputFilters; import dev.hephaestus.glowcase.util.TextUtils; +import net.minecraft.client.gui.GuiGraphicsExtractor; import net.minecraft.client.gui.components.StringWidget; +import net.minecraft.client.input.KeyEvent; +import net.minecraft.client.input.MouseButtonEvent; import net.minecraft.core.Vec3i; import net.minecraft.network.chat.Component; -import net.minecraft.network.chat.TextColor; import net.minecraft.network.protocol.common.custom.CustomPacketPayload; import org.jetbrains.annotations.Nullable; import java.util.concurrent.atomic.AtomicInteger; -public class OutlineBlockEditScreen extends BlockEditorScreen { +public class OutlineBlockEditScreen extends BlockEditorScreen implements ColorPickerIncludedScreen { private StringWidget offsetTextWidget; private StringWidget scaleTextWidget; private StringWidget colorTextWidget; @@ -27,9 +31,11 @@ public class OutlineBlockEditScreen extends BlockEditorScreen { - TextColor.parseColor(this.colorWidget.getValue()) - .ifSuccess(color -> this.blockEntity.color = color.getValue() | 0xFF000000); - }); + this.colorPickerWidget = this.createColorPickerWidget(); + + this.colorWidget = HexColorEditBox.builder(this.minecraft.font, width / 2 - 65, widgetY.getAndAdd(lineOffset), + () -> this.blockEntity.color, color -> this.blockEntity.color = color + ) + .setWidth(50) + .setColorPickerWidget(this.colorPickerWidget) + .build(); +// this.colorWidget = new GlowcaseEditBox(this.minecraft.font, width / 2 - 65, widgetY.getAndAdd(lineOffset), 50, 20, Component.empty()); +// this.colorWidget.setValue("#" + String.format("%1$06X", this.blockEntity.color & 0x00FFFFFF)); +// this.colorWidget.setResponder(string -> { +// TextColor.parseColor(this.colorWidget.getValue()) +// .ifSuccess(color -> this.blockEntity.color = color.getValue() | 0xFF000000); +// }); this.widthWidget = new GlowcaseEditBox(this.minecraft.font, width / 2 - 65, widgetY.getAndAdd(lineOffset), 50, 20, Component.empty()); this.widthWidget.setValue(String.valueOf(this.blockEntity.width)); @@ -147,8 +161,31 @@ public void init() { this.addRenderableWidget(this.widthWidget); } + @Override + public void extractRenderState(GuiGraphicsExtractor graphics, int mouseX, int mouseY, float delta) { + super.extractRenderState(graphics, mouseX, mouseY, delta); + this.extractColorPicker(graphics, mouseX, mouseY, delta); + } + + @Override + public boolean mouseClicked(MouseButtonEvent event, boolean doubleClick) { + if (this.mouseClickedColorPicker(event, doubleClick)) return true; + return super.mouseClicked(event, doubleClick); + } + + @Override + public boolean keyPressed(KeyEvent event) { + if (this.keyPressedColorPicker(event)) return true; + return super.keyPressed(event); + } + @Override public @Nullable CustomPacketPayload getUpdatePayload() { return C2SEditOutlineBlock.of(blockEntity); } + + @Override + public ColorPickerWidget getColorPickerWidget() { + return this.colorPickerWidget; + } } diff --git a/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/PopupBlockEditScreen.java b/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/PopupBlockEditScreen.java index 2b8c3f20..fd3273b9 100644 --- a/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/PopupBlockEditScreen.java +++ b/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/PopupBlockEditScreen.java @@ -3,6 +3,8 @@ import dev.hephaestus.glowcase.block.entity.HyperlinkBlockEntity; import dev.hephaestus.glowcase.block.entity.PopupBlockEntity; import dev.hephaestus.glowcase.block.entity.TextBlockEntity; +import dev.hephaestus.glowcase.client.gui.widget.ingame.color.HexColorEditBox; +import dev.hephaestus.glowcase.client.gui.widget.ingame.color.picker.ColorPickerWidget; import dev.hephaestus.glowcase.packet.C2SEditPopupBlock; import dev.hephaestus.glowcase.util.TextUtils; import net.minecraft.client.Minecraft; @@ -21,13 +23,15 @@ import org.lwjgl.glfw.GLFW; //TODO: multi-character selection at some point? it may be a bit complex but it'd be nice -public class PopupBlockEditScreen extends BlockEditorScreen { +public class PopupBlockEditScreen extends BlockEditorScreen implements ColorPickerIncludedScreen { private TextFieldHelper selectionManager; private int currentRow; private long ticksSinceOpened = 0; private EditBox titleEntryWidget; private Button changeAlignment; - private EditBox colorEntryWidget; + private HexColorEditBox colorEntryWidget; + + private ColorPickerWidget colorPickerWidget; public PopupBlockEditScreen(PopupBlockEntity blockEntity) { super(blockEntity); @@ -76,14 +80,21 @@ public void init() { )); }).bounds(120 + innerPadding, 20 + innerPadding, 160, 20).build(); - this.colorEntryWidget = new EditBox(this.minecraft.font, 280 + innerPadding * 2, 20 + innerPadding, 50, 20, Component.empty()); - this.colorEntryWidget.setValue("#" + Integer.toHexString(this.blockEntity.color & 0x00FFFFFF)); - this.colorEntryWidget.setResponder(string -> { - TextColor.parseColor(this.colorEntryWidget.getValue()).ifSuccess(color -> { - this.blockEntity.color = color == null ? 0xFFFFFFFF : color.getValue() | 0xFF000000; - this.blockEntity.renderDirty = true; - }); - }); + this.colorPickerWidget = createColorPickerWidget(); + this.colorEntryWidget = HexColorEditBox.builder(this.minecraft.font, 280 + innerPadding, 20 + innerPadding, + () -> this.blockEntity.color, color -> { this.blockEntity.color = color; this.blockEntity.renderDirty = true; } + ) + .setWidth(50) + .setColorPickerWidget(this.colorPickerWidget) + .build(); +// this.colorEntryWidget = new EditBox(this.minecraft.font, 280 + innerPadding * 2, 20 + innerPadding, 50, 20, Component.empty()); +// this.colorEntryWidget.setValue("#" + Integer.toHexString(this.blockEntity.color & 0x00FFFFFF)); +// this.colorEntryWidget.setResponder(string -> { +// TextColor.parseColor(this.colorEntryWidget.getValue()).ifSuccess(color -> { +// this.blockEntity.color = color == null ? 0xFFFFFFFF : color.getValue() | 0xFF000000; +// this.blockEntity.renderDirty = true; +// }); +// }); this.addRenderableWidget(this.titleEntryWidget); this.addRenderableWidget(this.changeAlignment); @@ -169,6 +180,7 @@ public void extractRenderState(GuiGraphicsExtractor graphics, int mouseX, int mo } graphics.pose().popMatrix(); + this.extractColorPicker(graphics, mouseX, mouseY, delta); } @Override @@ -186,6 +198,7 @@ public boolean charTyped(CharacterEvent event) { @Override public boolean keyPressed(KeyEvent event) { int keyCode = event.key(); + if (this.keyPressedColorPicker(event)) return true; if (this.titleEntryWidget.canConsumeInput()) { if (keyCode == GLFW.GLFW_KEY_ESCAPE) { this.onClose(); @@ -296,6 +309,7 @@ public boolean mouseClicked(MouseButtonEvent event, boolean doubleClick) { double mouseX = event.x(); double mouseY = event.y(); int topOffset = (int) (40 + 2 * this.width / 100F); + if (this.mouseClickedColorPicker(event, doubleClick)) return true; if (!this.titleEntryWidget.mouseClicked(event, doubleClick)) { this.titleEntryWidget.setFocused(false); } @@ -354,4 +368,9 @@ public boolean mouseClicked(MouseButtonEvent event, boolean doubleClick) { return super.mouseClicked(event, doubleClick); } } + + @Override + public ColorPickerWidget getColorPickerWidget() { + return this.colorPickerWidget; + } } diff --git a/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/SpriteBlockEditScreen.java b/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/SpriteBlockEditScreen.java index ff43a249..2019049e 100644 --- a/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/SpriteBlockEditScreen.java +++ b/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/SpriteBlockEditScreen.java @@ -5,6 +5,7 @@ import dev.hephaestus.glowcase.client.gui.widget.ingame.GlowcaseEditBox; import dev.hephaestus.glowcase.client.gui.widget.ingame.SuggestionListWidget; import dev.hephaestus.glowcase.client.gui.widget.ingame.color.HexColorEditBox; +import dev.hephaestus.glowcase.client.gui.widget.ingame.color.picker.ColorPickerWidget; import dev.hephaestus.glowcase.packet.C2SEditSpriteBlock; import net.fabricmc.loader.api.FabricLoader; import net.minecraft.client.gui.GuiGraphicsExtractor; @@ -25,7 +26,7 @@ import java.util.List; import java.util.function.Function; -public class SpriteBlockEditScreen extends BlockEditorScreen { +public class SpriteBlockEditScreen extends BlockEditorScreen implements ColorPickerIncludedScreen { private EditBox spriteWidget; private Button spriteWidgetHelpButton; private Button rotationWidget; @@ -35,6 +36,7 @@ public class SpriteBlockEditScreen extends BlockEditorScreen private List spriteHelpTooltipText; + private ColorPickerWidget colorPickerWidget; private SuggestionListWidget suggestionWidget; private List validSprites = new ArrayList<>(); @@ -74,10 +76,13 @@ public void init() { this.zOffsetToggle.setMessage(Component.literal(this.blockEntity.zOffset.name())); }).bounds(width / 2 - 90, height / 2 + 5, 180, 20).build(); + this.colorPickerWidget = this.createColorPickerWidget(); + this.colorEntryWidget = HexColorEditBox.builder(this.minecraft.font, width / 2 - 90, height / 2 + 35, () -> this.blockEntity.color, color -> this.blockEntity.color = color ) .setWidth(180) + .setColorPickerWidget(this.colorPickerWidget) .build(); // this.colorEntryWidget = new EditBox(this.minecraft.font, width / 2 - 90, height / 2 + 35, 180, 20, Component.empty()); @@ -96,6 +101,7 @@ public void init() { } catch (NumberFormatException ignored) {} }); +// this.addRenderableWidget(this.colorPickerWidget); this.addRenderableWidget(this.spriteWidget); this.addRenderableWidget(this.spriteWidgetHelpButton); this.addRenderableWidget(this.rotationWidget); @@ -151,6 +157,7 @@ public void extractRenderState(GuiGraphicsExtractor graphics, int mouseX, int mo }*/ // render the list over everything + this.extractColorPicker(graphics, mouseX, mouseY, delta); suggestionWidget.extractRenderState(graphics, mouseX, mouseY, delta); } @@ -158,6 +165,9 @@ public void extractRenderState(GuiGraphicsExtractor graphics, int mouseX, int mo public boolean mouseClicked(MouseButtonEvent event, boolean doubleClick) { double mouseX = event.x(); double mouseY = event.y(); + + if (mouseClickedColorPicker(event, doubleClick)) return true; + if (suggestionWidget.isMouseOver(mouseX, mouseY) && spriteWidget.isFocused()) { return suggestionWidget.mouseClicked(event, doubleClick); } else { @@ -192,6 +202,7 @@ public boolean keyPressed(KeyEvent event) { if (suggestionWidget.keyPressed(event)) { return true; } + if (keyPressedColorPicker(event)) return true; return super.keyPressed(event); } @@ -201,4 +212,9 @@ public CustomPacketPayload getUpdatePayload() { blockEntity.setChanged(); return C2SEditSpriteBlock.of(blockEntity); } + + @Override + public ColorPickerWidget getColorPickerWidget() { + return this.colorPickerWidget; + } } diff --git a/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/TextBlockEditScreen.java b/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/TextBlockEditScreen.java index d8fe7929..23f04f4e 100644 --- a/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/TextBlockEditScreen.java +++ b/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/TextBlockEditScreen.java @@ -71,7 +71,7 @@ public void init() { var scaleSlider = new TextScale.SliderWidget(textBlockEntity, middle - 203, innerPadding, 113, 20); addFormattingButtons(middle - 90 + 6, innerPadding, 0, 20, 2); - this.colorPickerWidget = ColorPickerWidget.builder(this).build(); + this.colorPickerWidget = this.createColorPickerWidget(); // this.colorEntryWidget = new HexColorEditBox(this.minecraft.font, middle + 54, innerPadding, 64, 20, // true, this.colorPickerWidget, () -> this.textBlockEntity.color, color -> this.textBlockEntity.color = color @@ -125,7 +125,7 @@ public void init() { // this.colorEntryWidget // ); - this.addRenderableWidget(colorPickerWidget); +// this.addRenderableWidget(colorPickerWidget); this.addRenderableWidget(this.colorEntryWidget); this.addRenderableWidget(scaleSlider); this.addRenderableWidget(moreOptionsButton); @@ -218,7 +218,8 @@ public void extractRenderState(GuiGraphicsExtractor graphics, int mouseX, int mo graphics.pose().popMatrix(); - colorPickerWidget.extractRenderState(graphics, mouseX, mouseY, delta); + this.extractColorPicker(graphics, mouseX, mouseY, delta); +// colorPickerWidget.extractRenderState(graphics, mouseX, mouseY, delta); } @Override @@ -236,9 +237,7 @@ public boolean charTyped(CharacterEvent event) { public boolean keyPressed(KeyEvent event) { var keyCode = event.key(); - if (this.keyPressedColorPicker(event)) { - return true; - } + if (this.keyPressedColorPicker(event)) return true; // if (this.colorPickerWidget.active) { // switch (keyCode) { @@ -413,9 +412,7 @@ public boolean mouseClicked(MouseButtonEvent event, boolean doubleClick) { break; } - if (mouseClickedColorPicker(event, doubleClick)) { - return true; - } + if (mouseClickedColorPicker(event, doubleClick)) return true; // if (colorPickerWidget.active && colorPickerWidget.visible) { // if (colorPickerWidget.isMouseOver(mouseX, mouseY)) { diff --git a/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/TextBlockOptionsScreen.java b/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/TextBlockOptionsScreen.java index 248b7276..eb9319a7 100644 --- a/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/TextBlockOptionsScreen.java +++ b/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/TextBlockOptionsScreen.java @@ -2,6 +2,8 @@ import dev.hephaestus.glowcase.block.entity.TextBlockEntity; import dev.hephaestus.glowcase.client.gui.screen.ingame.TextBlockEditScreen.TextScale; +import dev.hephaestus.glowcase.client.gui.widget.ingame.color.HexColorEditBox; +import dev.hephaestus.glowcase.client.gui.widget.ingame.color.picker.ColorPickerWidget; import dev.hephaestus.glowcase.client.util.ColorUtil; import dev.hephaestus.glowcase.packet.C2SEditTextBlock; import net.minecraft.client.Minecraft; @@ -16,6 +18,8 @@ import net.minecraft.client.gui.layouts.HeaderAndFooterLayout; import net.minecraft.client.gui.narration.NarratableEntry; import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.input.KeyEvent; +import net.minecraft.client.input.MouseButtonEvent; import net.minecraft.network.chat.CommonComponents; import net.minecraft.network.chat.Component; import net.minecraft.network.protocol.common.custom.CustomPacketPayload; @@ -23,9 +27,10 @@ import java.util.List; -public class TextBlockOptionsScreen extends BlockEditorScreen { +public class TextBlockOptionsScreen extends BlockEditorScreen implements ColorPickerIncludedScreen { private final Screen returnScreen; + private ColorPickerWidget colorPickerWidget; public final HeaderAndFooterLayout layout = new HeaderAndFooterLayout(this); public TextOptionList options; @@ -98,32 +103,55 @@ public void init() { ) ); + // Note: Color picker position is messed up on this screen, but it still works otherwise + this.colorPickerWidget = createColorPickerWidget(); this.options.addHeaders(Component.translatable("gui.glowcase.color"), Component.translatable("gui.glowcase.background_color")); - var colorEditBox = new EditBox( - this.font, - Button.DEFAULT_WIDTH, - Button.DEFAULT_HEIGHT, - Component.translatable("gui.glowcase.color") - ); - colorEditBox.setValue(ColorUtil.toAlphaHex(this.blockEntity.color)); - colorEditBox.setResponder(string -> ColorUtil.parse(string, blockEntity.color) - .ifSuccess(newColor -> { - blockEntity.color = newColor; - blockEntity.rebake(true); - })); - - var backgroundEditBox = new EditBox( - this.font, - Button.DEFAULT_WIDTH, - Button.DEFAULT_HEIGHT, - Component.translatable("gui.glowcase.background_color") - ); - backgroundEditBox.setValue(ColorUtil.toAlphaHex(this.blockEntity.backgroundColor)); - backgroundEditBox.setResponder(string -> ColorUtil.parse(string, blockEntity.backgroundColor) - .ifSuccess(newColor -> { - blockEntity.backgroundColor = newColor; - blockEntity.rebake(true); - })); + HexColorEditBox colorEditBox = HexColorEditBox.builder(this.minecraft.font, 0, 0, + () -> this.blockEntity.color, color -> { + this.blockEntity.color = color; + this.blockEntity.rebake(true); + } + ) + .setEditableAlpha(true) + .setWidth(Button.DEFAULT_WIDTH) + .setColorPickerWidget(this.colorPickerWidget) + .build(); + +// var colorEditBox = new EditBox( +// this.font, +// Button.DEFAULT_WIDTH, +// Button.DEFAULT_HEIGHT, +// Component.translatable("gui.glowcase.color") +// ); +// colorEditBox.setValue(ColorUtil.toAlphaHex(this.blockEntity.color)); +// colorEditBox.setResponder(string -> ColorUtil.parse(string, blockEntity.color) +// .ifSuccess(newColor -> { +// blockEntity.color = newColor; +// blockEntity.rebake(true); +// })); + + HexColorEditBox backgroundEditBox = HexColorEditBox.builder(this.minecraft.font, 0, 0, + () -> this.blockEntity.backgroundColor, color -> { + this.blockEntity.backgroundColor = color; + this.blockEntity.rebake(true); + } + ) + .setWidth(Button.DEFAULT_WIDTH) + .setEditableAlpha(true) + .setColorPickerWidget(this.colorPickerWidget) + .build(); +// var backgroundEditBox = new EditBox( +// this.font, +// Button.DEFAULT_WIDTH, +// Button.DEFAULT_HEIGHT, +// Component.translatable("gui.glowcase.background_color") +// ); +// backgroundEditBox.setValue(ColorUtil.toAlphaHex(this.blockEntity.backgroundColor)); +// backgroundEditBox.setResponder(string -> ColorUtil.parse(string, blockEntity.backgroundColor) +// .ifSuccess(newColor -> { +// blockEntity.backgroundColor = newColor; +// blockEntity.rebake(true); +// })); this.options.add(colorEditBox, backgroundEditBox); @@ -159,6 +187,29 @@ public void onClose() { this.minecraft.setScreen(this.returnScreen); } + @Override + public void extractRenderState(GuiGraphicsExtractor graphics, int mouseX, int mouseY, float delta) { + super.extractRenderState(graphics, mouseX, mouseY, delta); + this.extractColorPicker(graphics, mouseX, mouseY, delta); + } + + @Override + public boolean mouseClicked(MouseButtonEvent event, boolean doubleClick) { + if (this.mouseClickedColorPicker(event, doubleClick)) return true; + return super.mouseClicked(event, doubleClick); + } + + @Override + public boolean keyPressed(KeyEvent event) { + if (this.keyPressedColorPicker(event)) return true; + return super.keyPressed(event); + } + + @Override + public ColorPickerWidget getColorPickerWidget() { + return this.colorPickerWidget; + } + @NullMarked public static class TextOptionList extends ContainerObjectSelectionList { public TextOptionList(Minecraft minecraft, int width, int height, int y) { diff --git a/src/main/java/dev/hephaestus/glowcase/client/gui/widget/ingame/color/HexColorEditBox.java b/src/main/java/dev/hephaestus/glowcase/client/gui/widget/ingame/color/HexColorEditBox.java index bd6cd436..a7ccf651 100644 --- a/src/main/java/dev/hephaestus/glowcase/client/gui/widget/ingame/color/HexColorEditBox.java +++ b/src/main/java/dev/hephaestus/glowcase/client/gui/widget/ingame/color/HexColorEditBox.java @@ -12,7 +12,7 @@ import org.jetbrains.annotations.Nullable; /** - * An EditBox Widget built for HEX colors, with automatic color (as an integer) getter & setter, and built-in {@link ColorPickerWidget} support.

+ * An EditBox Widget built for HEX colors, with automatic color (as an integer) getter & setter, and built-in {@link ColorPickerWidget} support. * @author Superkat32 */ public class HexColorEditBox extends GlowcaseEditBox { @@ -20,7 +20,6 @@ public class HexColorEditBox extends GlowcaseEditBox { public final ColorPickerWidget colorPickerWidget; public final ColorGetter colorGetter; public final ColorSetter colorSetter; - public int fallbackColor; public int color; public boolean editableAlpha; @@ -30,14 +29,13 @@ public static HexColorEditBox.Builder builder(Font textRenderer, int x, int y, C public HexColorEditBox( Font textRenderer, int x, int y, int width, int height, - boolean editableAlpha, int fallbackColor, @Nullable ColorPickerWidget colorPickerWidget, + boolean editableAlpha, @Nullable ColorPickerWidget colorPickerWidget, ColorGetter colorGetter, ColorSetter colorSetter ) { super(textRenderer, x, y, width, height, Component.empty()); this.colorPickerWidget = colorPickerWidget; this.colorGetter = colorGetter; this.colorSetter = colorSetter; - this.fallbackColor = fallbackColor; this.color = colorGetter.get(); this.editableAlpha = editableAlpha; @@ -46,18 +44,13 @@ public HexColorEditBox( }); this.setTextFromColor(); - -// if (this.colorPickerWidget != null) { -// this.colorPickerWidget.target(this); -// this.colorPickerWidget.setup(this.color, true, this::setColor); -// } } @Override public void onClick(MouseButtonEvent event, boolean doubleClick) { super.onClick(event, doubleClick); if (this.colorPickerWidget != null) { - this.colorPickerWidget.target(this, this.color, true, this::setColor); + this.colorPickerWidget.target(this, this.color, this.editableAlpha, this::setColor); } } @@ -102,7 +95,6 @@ public static class Builder { private int width = DEFAULT_WIDTH; private int height = 20; private boolean editableAlpha = false; - private int fallbackColor; private ColorPickerWidget colorPickerWidget = null; public Builder(Font textRenderer, int x, int y, ColorGetter colorGetter, ColorSetter colorSetter) { @@ -111,8 +103,6 @@ public Builder(Font textRenderer, int x, int y, ColorGetter colorGetter, ColorSe this.textRenderer = textRenderer; this.x = x; this.y = y; - - this.fallbackColor = colorGetter.get(); } public Builder setWidth(int width) { @@ -131,11 +121,6 @@ public Builder setEditableAlpha(boolean editableAlpha) { return this; } - public Builder setFallbackColor(int fallbackColor) { - this.fallbackColor = fallbackColor; - return this; - } - public Builder setColorPickerWidget(ColorPickerWidget colorPickerWidget) { this.colorPickerWidget = colorPickerWidget; return this; @@ -144,7 +129,7 @@ public Builder setColorPickerWidget(ColorPickerWidget colorPickerWidget) { public HexColorEditBox build() { return new HexColorEditBox( this.textRenderer, this.x, this.y, this.width, this.height, - this.editableAlpha, this.fallbackColor, this.colorPickerWidget, + this.editableAlpha, this.colorPickerWidget, this.colorGetter, this.colorSetter ); } diff --git a/src/main/java/dev/hephaestus/glowcase/client/gui/widget/ingame/color/picker/ColorPickerWidget.java b/src/main/java/dev/hephaestus/glowcase/client/gui/widget/ingame/color/picker/ColorPickerWidget.java index 0319f634..a7d17a80 100644 --- a/src/main/java/dev/hephaestus/glowcase/client/gui/widget/ingame/color/picker/ColorPickerWidget.java +++ b/src/main/java/dev/hephaestus/glowcase/client/gui/widget/ingame/color/picker/ColorPickerWidget.java @@ -13,6 +13,7 @@ import net.minecraft.client.gui.components.AbstractWidget; import net.minecraft.client.gui.components.events.GuiEventListener; import net.minecraft.client.gui.narration.NarrationElementOutput; +import net.minecraft.client.gui.screens.Screen; import net.minecraft.client.input.InputWithModifiers; import net.minecraft.client.input.MouseButtonEvent; import net.minecraft.client.renderer.RenderPipelines; @@ -75,7 +76,7 @@ public class ColorPickerWidget extends AbstractButton { public PickerArea currentClickedArea = null; // Used for allowing mouse drags beyond an area's boundaries public float hue, saturation, value, alpha; - public float prevHue, prevSaturation, prevValue, prevAlpha; + public float prevHue, prevSaturation, prevValue, prevAlpha; // Used for cancelling, *not* interpolation public static ColorPickerWidget.Builder builder(ColorPickerIncludedScreen screen) { return new Builder(screen); @@ -285,14 +286,16 @@ public void target(AbstractWidget widget, int initColor, boolean showAlpha, Colo * @param pickedColorListener What to do with the picked color, as an integer. */ public void target(AbstractWidget widget, int initColor, boolean showAlpha, boolean rightAligned, ColorSetter pickedColorListener) { + Screen screen = Minecraft.getInstance().screen; this.visible = true; this.active = true; this.targetElement = widget; // Ensure at least 2 pixels of padding between screen edges - int x = Math.min(Minecraft.getInstance().screen.width - this.getWidth() - 2, widget.getX()); + int x = Math.min(screen.width - this.getWidth() - 2, widget.getX()); if (rightAligned) x = Math.max(2, widget.getX() + widget.getWidth() - this.getWidth() + 2); - int y = widget.getY() + widget.getHeight(); + int y = widget.getY() + widget.getHeight(); // Beneath widget + if (y + this.getHeight() > screen.height - 2) y = widget.getY() - this.getHeight(); // Above widget this.setX(x); this.setY(y); From b6973092bbe45d887f4a1345a490f397fda87f03 Mon Sep 17 00:00:00 2001 From: Kat Date: Fri, 17 Jul 2026 12:10:52 -0400 Subject: [PATCH 6/9] Chore: Sweep sweep --- .../gui/screen/ingame/NoteEditScreen.java | 37 +- .../screen/ingame/OutlineBlockEditScreen.java | 6 - .../screen/ingame/PopupBlockEditScreen.java | 8 - .../screen/ingame/SpriteBlockEditScreen.java | 11 +- .../screen/ingame/TextBlockEditScreen.java | 101 --- .../screen/ingame/TextBlockOptionsScreen.java | 25 - .../gui/widget/ingame/ColorPresetWidget.java | 84 --- .../color/picker/ColorPickerWidget.java | 573 ------------------ .../ingame/color/picker/PickerPreset.java | 7 - 9 files changed, 7 insertions(+), 845 deletions(-) delete mode 100644 src/main/java/dev/hephaestus/glowcase/client/gui/widget/ingame/ColorPresetWidget.java diff --git a/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/NoteEditScreen.java b/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/NoteEditScreen.java index 09313845..f4614d78 100644 --- a/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/NoteEditScreen.java +++ b/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/NoteEditScreen.java @@ -67,7 +67,7 @@ public class NoteEditScreen extends TextEditorScreen { private boolean finalizing = false; private List signing_text; -// private ColorPickerWidget colorPickerWidget; + private ColorPickerWidget colorPickerWidget; private Button doneButton; private Button signButton; private Button changeAlignment; @@ -187,10 +187,7 @@ protected void init() { }).bounds(width / 2 + BG_WIDTH / 2 - (BG_WIDTH / 2 - 3), height / 2 + BG_HEIGHT / 2 + offset, BG_WIDTH / 2 - 3, 20).build(); -// this.colorPickerWidget = ColorPickerWidget.builder(this, 216, 10).size(182, 104).build(); -// this.colorPickerWidget.toggle(false); //start deactivated - -// this.addRenderableWidget(colorPickerWidget); + this.colorPickerWidget = this.createColorPickerWidget(); addRenderableWidget(changeAlignment); addRenderableWidget(doneButton); @@ -329,6 +326,7 @@ public void extractRenderState(GuiGraphicsExtractor graphics, int mouseX, int mo } graphics.disableScissor(); + this.extractColorPicker(graphics, mouseX, mouseY, delta); } @Override @@ -347,13 +345,7 @@ public boolean keyPressed(KeyEvent event) { boolean result; int keyCode = event.key(); -// if (this.colorPickerWidget.active && (keyCode == GLFW.GLFW_KEY_ENTER || keyCode == GLFW.GLFW_KEY_ESCAPE)) { - if (false) { -// if (keyCode == GLFW.GLFW_KEY_ENTER) { -// this.colorPickerWidget.confirmColor(); -// } else { -// this.colorPickerWidget.cancel(); -// } + if (keyPressedColorPicker(event)) { result = true; } else { setFocused(null); @@ -445,18 +437,7 @@ public boolean charTyped(CharacterEvent event) { public boolean mouseClicked(MouseButtonEvent event, boolean doubleClick) { double mouseX = event.x(); double mouseY = event.y(); -// if (colorPickerWidget.active && colorPickerWidget.visible) { -// if (colorPickerWidget.isMouseOver(mouseX, mouseY)) { -// colorPickerWidget.mouseClicked(event, doubleClick); -// this.setFocused(colorPickerWidget); -// this.setDragging(true); -// return true; -// } else { -//// if (!this.colorPickerWidget.targetElement.isMouseOver(mouseX, mouseY)) { -//// toggleColorPicker(false); -//// } -// } -// } + if (this.mouseClickedColorPicker(event, doubleClick)) return true; boolean withinX = (mouseX >= width / 2f - BG_WIDTH / 2f && mouseX <= width / 2f + BG_WIDTH / 2f); boolean withinY = (mouseY >= height / 2f - BG_HEIGHT / 2f && mouseY <= height / 2f + BG_HEIGHT / 2f); @@ -599,15 +580,9 @@ public CustomPacketPayload getUpdatePayload() { @Override public ColorPickerWidget getColorPickerWidget() { -// return colorPickerWidget; - return null; + return this.colorPickerWidget; } -// @Override -// public void toggleColorPickerWidget(boolean active) { -//// colorPickerWidget.toggle(active); -// } - @Override TextFieldHelper getSelectionManager() { return selectionManager; diff --git a/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/OutlineBlockEditScreen.java b/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/OutlineBlockEditScreen.java index 2f12f7a1..38b65a81 100644 --- a/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/OutlineBlockEditScreen.java +++ b/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/OutlineBlockEditScreen.java @@ -135,12 +135,6 @@ public void init() { .setWidth(50) .setColorPickerWidget(this.colorPickerWidget) .build(); -// this.colorWidget = new GlowcaseEditBox(this.minecraft.font, width / 2 - 65, widgetY.getAndAdd(lineOffset), 50, 20, Component.empty()); -// this.colorWidget.setValue("#" + String.format("%1$06X", this.blockEntity.color & 0x00FFFFFF)); -// this.colorWidget.setResponder(string -> { -// TextColor.parseColor(this.colorWidget.getValue()) -// .ifSuccess(color -> this.blockEntity.color = color.getValue() | 0xFF000000); -// }); this.widthWidget = new GlowcaseEditBox(this.minecraft.font, width / 2 - 65, widgetY.getAndAdd(lineOffset), 50, 20, Component.empty()); this.widthWidget.setValue(String.valueOf(this.blockEntity.width)); diff --git a/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/PopupBlockEditScreen.java b/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/PopupBlockEditScreen.java index fd3273b9..384f73ee 100644 --- a/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/PopupBlockEditScreen.java +++ b/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/PopupBlockEditScreen.java @@ -87,14 +87,6 @@ public void init() { .setWidth(50) .setColorPickerWidget(this.colorPickerWidget) .build(); -// this.colorEntryWidget = new EditBox(this.minecraft.font, 280 + innerPadding * 2, 20 + innerPadding, 50, 20, Component.empty()); -// this.colorEntryWidget.setValue("#" + Integer.toHexString(this.blockEntity.color & 0x00FFFFFF)); -// this.colorEntryWidget.setResponder(string -> { -// TextColor.parseColor(this.colorEntryWidget.getValue()).ifSuccess(color -> { -// this.blockEntity.color = color == null ? 0xFFFFFFFF : color.getValue() | 0xFF000000; -// this.blockEntity.renderDirty = true; -// }); -// }); this.addRenderableWidget(this.titleEntryWidget); this.addRenderableWidget(this.changeAlignment); diff --git a/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/SpriteBlockEditScreen.java b/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/SpriteBlockEditScreen.java index 2019049e..75d7a919 100644 --- a/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/SpriteBlockEditScreen.java +++ b/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/SpriteBlockEditScreen.java @@ -85,14 +85,6 @@ public void init() { .setColorPickerWidget(this.colorPickerWidget) .build(); -// this.colorEntryWidget = new EditBox(this.minecraft.font, width / 2 - 90, height / 2 + 35, 180, 20, Component.empty()); -// this.colorEntryWidget.setValue("#" + String.format("%1$06X", this.blockEntity.color & 0x00FFFFFF)); -// this.colorEntryWidget.setResponder(string -> { -// TextColor.parseColor(this.colorEntryWidget.getValue()).ifSuccess(color -> { -// this.blockEntity.color = color == null ? 0xFFFFFFFF : color.getValue() | 0xFF000000; -// }); -// }); - this.scaleEntryWidget = new EditBox(this.minecraft.font, width / 2 - 90, height / 2 + 65, 180, 20, Component.empty()); this.scaleEntryWidget.setValue(String.valueOf(this.blockEntity.scale)); this.scaleEntryWidget.setResponder(string -> { @@ -101,7 +93,6 @@ public void init() { } catch (NumberFormatException ignored) {} }); -// this.addRenderableWidget(this.colorPickerWidget); this.addRenderableWidget(this.spriteWidget); this.addRenderableWidget(this.spriteWidgetHelpButton); this.addRenderableWidget(this.rotationWidget); @@ -156,8 +147,8 @@ public void extractRenderState(GuiGraphicsExtractor graphics, int mouseX, int mo setTooltip(this.spriteHelpTooltipText); }*/ - // render the list over everything this.extractColorPicker(graphics, mouseX, mouseY, delta); + // render the list over everything suggestionWidget.extractRenderState(graphics, mouseX, mouseY, delta); } diff --git a/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/TextBlockEditScreen.java b/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/TextBlockEditScreen.java index 23f04f4e..929fba36 100644 --- a/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/TextBlockEditScreen.java +++ b/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/TextBlockEditScreen.java @@ -38,15 +38,12 @@ public class TextBlockEditScreen extends TextEditorScreen implements BlockEditor private final TextBlockEntity textBlockEntity; private List textWidgets; -// private List colorListeners; private TextFieldHelper selectionManager; private HexColorEditBox colorEntryWidget; private int currentRow; private long ticksSinceOpened = 0; private ColorPickerWidget colorPickerWidget; -// private ColorPickerWidget colorPickerWidget; -// private Color colorEntryPreColorPicker; // used for color picker cancel button public TextBlockEditScreen(TextBlockEntity textBlockEntity) { this.textBlockEntity = textBlockEntity; @@ -73,9 +70,6 @@ public void init() { this.colorPickerWidget = this.createColorPickerWidget(); -// this.colorEntryWidget = new HexColorEditBox(this.minecraft.font, middle + 54, innerPadding, 64, 20, -// true, this.colorPickerWidget, () -> this.textBlockEntity.color, color -> this.textBlockEntity.color = color -// ); this.colorEntryWidget = HexColorEditBox.builder(this.minecraft.font, middle + 54, innerPadding, () -> this.textBlockEntity.color, color -> { this.textBlockEntity.color = color; @@ -87,27 +81,6 @@ public void init() { .build(); this.colorEntryWidget.setTooltip(Tooltip.create(Component.translatable("gui.glowcase.color"))); - -// this.colorEntryWidget = new EditBox(this.minecraft.font, middle + 54, innerPadding, 64, 20, Component.empty()); -// this.colorEntryWidget.setTooltip(Tooltip.create(Component.translatable("gui.glowcase.color"))); -// this.colorEntryWidget.setValue(ColorUtil.toAlphaHex(this.textBlockEntity.color)); -// this.colorEntryWidget.setResponder(string -> { -// ColorUtil.parse(string, this.textBlockEntity.color).ifSuccess(newColor -> { -// final int color = (Math.max(newColor >>> 24, 0x1A) << 24) | (newColor & ColorUtil.RGB_MASK); -// -// this.textBlockEntity.color = color; -// // make sure it doesn't update from the color picker updating the text -// if (this.colorEntryWidget.isFocused()) { -// this.colorPickerWidget.setColor(new Color(color)); -// } -// this.textBlockEntity.rebake(true); -// }); -// }); - - -// this.colorPickerWidget = ColorPickerWidget.builder(this, 216, 10).size(182, 104).build(); -// this.colorPickerWidget.toggle(false); //start deactivated - var moreOptionsButton = Button.builder( Component.translatable("gui.glowcase.more"), button -> { @@ -121,11 +94,6 @@ public void init() { this.colorEntryWidget ); -// this.colorListeners = List.of( -// this.colorEntryWidget -// ); - -// this.addRenderableWidget(colorPickerWidget); this.addRenderableWidget(this.colorEntryWidget); this.addRenderableWidget(scaleSlider); this.addRenderableWidget(moreOptionsButton); @@ -219,7 +187,6 @@ public void extractRenderState(GuiGraphicsExtractor graphics, int mouseX, int mo graphics.pose().popMatrix(); this.extractColorPicker(graphics, mouseX, mouseY, delta); -// colorPickerWidget.extractRenderState(graphics, mouseX, mouseY, delta); } @Override @@ -239,31 +206,11 @@ public boolean keyPressed(KeyEvent event) { if (this.keyPressedColorPicker(event)) return true; -// if (this.colorPickerWidget.active) { -// switch (keyCode) { -// case GLFW.GLFW_KEY_ENTER, GLFW.GLFW_KEY_KP_ENTER -> this.colorPickerWidget.confirmColor(); -// case GLFW.GLFW_KEY_ESCAPE -> this.colorPickerWidget.cancel(); -// default -> { -// final GuiEventListener listener = this.colorPickerWidget.targetElement; -// if (listener != null) { -// this.setFocused(listener); -// return listener.keyPressed(event); -// } -// } -// } -// -//// this.toggleColorPickerWidget(false); -// this.setFocused(null); -// -// return true; -// } - if (this.getFocused() != null) { if (this.getFocused().keyPressed(event)) { return true; } -// this.toggleColorPickerWidget(false); this.setFocused(null); if (keyCode == GLFW.GLFW_KEY_ESCAPE) { @@ -367,31 +314,6 @@ private void deleteLine() { this.textBlockEntity.rebake(true); } - private void colorListenerClicked(EditBox textWidget) { -// this.colorPickerWidget.setPosition(Math.min(textWidget.getX(), width - colorPickerWidget.getWidth()), textWidget.getY() + textWidget.getHeight()); -// this.colorPickerWidget.setTargetElement(textWidget); -// this.colorPickerWidget.setOnAccept(picker -> { -// textWidget.setValue(ColorUtil.toAlphaHex(picker.getCurrentColor().getRGB())); -// }); -// this.colorPickerWidget.setOnCancel(picker -> { -// picker.setColor(this.colorEntryPreColorPicker); -// textWidget.setValue(ColorUtil.toAlphaHex(this.colorEntryPreColorPicker.getRGB())); -// }); -// this.colorPickerWidget.setChangeListener(color -> { -// final int newColor = ColorUtil.transferAlpha(this.colorEntryPreColorPicker.getRGB(), color.getRGB()); -// textWidget.setValue(ColorUtil.toAlphaHex(newColor)); -// }); -// this.colorPickerWidget.setPresetListener((color, formatting) -> { -// this.colorPickerWidget.setColor(color); -// }); -// ColorUtil.parse(textWidget.getValue(), ColorUtil.WHITE).ifSuccess(color -> { -// final Color pickerColor = new Color(color); -// this.colorEntryPreColorPicker = pickerColor; -// this.colorPickerWidget.setColor(pickerColor); -// }).ifError(textColorError -> this.colorEntryPreColorPicker = this.colorPickerWidget.getCurrentColor()); -// toggleColorPickerWidget(true); - } - @Override public boolean mouseClicked(MouseButtonEvent event, boolean doubleClick) { double mouseX = event.x(); @@ -403,29 +325,11 @@ public boolean mouseClicked(MouseButtonEvent event, boolean doubleClick) { continue; } this.setFocused(text); -// if (this.colorListeners.contains(text)) { -// this.colorListenerClicked(text); -// } -// if (this.colorPickerWidget.targetElement != text) { -// text.setFocused(false); -// } break; } if (mouseClickedColorPicker(event, doubleClick)) return true; -// if (colorPickerWidget.active && colorPickerWidget.visible) { -// if (colorPickerWidget.isMouseOver(mouseX, mouseY)) { -// colorPickerWidget.mouseClicked(event, doubleClick); -// this.setFocused(colorPickerWidget); -// this.setDragging(true); -// return true; -// } else { -// if (!this.colorPickerWidget.targetElement.isMouseOver(mouseX, mouseY)) { -// toggleColorPickerWidget(false); -// } -// } -// } if (mouseY > topOffset) { this.currentRow = Mth.clamp((int) (mouseY - topOffset) / 12, 0, this.textBlockEntity.lines.size() - 1); this.setFocused(null); @@ -484,11 +388,6 @@ public ColorPickerWidget getColorPickerWidget() { return this.colorPickerWidget; } -// @Override -// public void toggleColorPickerWidget(boolean active) { -// this.colorPickerWidget.toggle(active); -// } - @Override TextFieldHelper getSelectionManager() { return this.selectionManager; diff --git a/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/TextBlockOptionsScreen.java b/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/TextBlockOptionsScreen.java index eb9319a7..de09e9ef 100644 --- a/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/TextBlockOptionsScreen.java +++ b/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/TextBlockOptionsScreen.java @@ -117,19 +117,6 @@ public void init() { .setColorPickerWidget(this.colorPickerWidget) .build(); -// var colorEditBox = new EditBox( -// this.font, -// Button.DEFAULT_WIDTH, -// Button.DEFAULT_HEIGHT, -// Component.translatable("gui.glowcase.color") -// ); -// colorEditBox.setValue(ColorUtil.toAlphaHex(this.blockEntity.color)); -// colorEditBox.setResponder(string -> ColorUtil.parse(string, blockEntity.color) -// .ifSuccess(newColor -> { -// blockEntity.color = newColor; -// blockEntity.rebake(true); -// })); - HexColorEditBox backgroundEditBox = HexColorEditBox.builder(this.minecraft.font, 0, 0, () -> this.blockEntity.backgroundColor, color -> { this.blockEntity.backgroundColor = color; @@ -140,18 +127,6 @@ public void init() { .setEditableAlpha(true) .setColorPickerWidget(this.colorPickerWidget) .build(); -// var backgroundEditBox = new EditBox( -// this.font, -// Button.DEFAULT_WIDTH, -// Button.DEFAULT_HEIGHT, -// Component.translatable("gui.glowcase.background_color") -// ); -// backgroundEditBox.setValue(ColorUtil.toAlphaHex(this.blockEntity.backgroundColor)); -// backgroundEditBox.setResponder(string -> ColorUtil.parse(string, blockEntity.backgroundColor) -// .ifSuccess(newColor -> { -// blockEntity.backgroundColor = newColor; -// blockEntity.rebake(true); -// })); this.options.add(colorEditBox, backgroundEditBox); diff --git a/src/main/java/dev/hephaestus/glowcase/client/gui/widget/ingame/ColorPresetWidget.java b/src/main/java/dev/hephaestus/glowcase/client/gui/widget/ingame/ColorPresetWidget.java deleted file mode 100644 index d7b96691..00000000 --- a/src/main/java/dev/hephaestus/glowcase/client/gui/widget/ingame/ColorPresetWidget.java +++ /dev/null @@ -1,84 +0,0 @@ -package dev.hephaestus.glowcase.client.gui.widget.ingame; - -import dev.hephaestus.glowcase.client.gui.widget.ingame.color.picker.ColorPickerWidget; -import net.minecraft.ChatFormatting; -import net.minecraft.client.gui.GuiGraphicsExtractor; -import net.minecraft.client.gui.components.AbstractButton; -import net.minecraft.client.gui.narration.NarrationElementOutput; -import net.minecraft.client.input.InputWithModifiers; -import net.minecraft.network.chat.Component; -import org.jetbrains.annotations.Nullable; - -import java.awt.*; - -public class ColorPresetWidget extends AbstractButton { - public final ColorPickerWidget colorPickerWidget; - public final Color color; - @Nullable - public ChatFormatting formatting = null; - public int z = 0; - - public ColorPresetWidget(ColorPickerWidget colorPicker, int x, int y, int width, int height, Color color) { - super(x, y, width, height, Component.nullToEmpty("")); - this.colorPickerWidget = colorPicker; - this.color = color; - } - - public void setPosition(int x, int y, int z, int size) { - this.setX(x); - this.setY(y); - this.setSize(size, size); - this.z = z; - } - - public static ColorPresetWidget fromFormatting(ColorPickerWidget colorPicker, ChatFormatting formatting) { - if (formatting.isColor()) { - //noinspection DataFlowIssue - ColorPresetWidget presetWidget = new ColorPresetWidget(colorPicker, 0, 0, 0, 0, new Color(formatting.getColor())); - presetWidget.formatting = formatting; - return presetWidget; - } - return new ColorPresetWidget(colorPicker, 0, 0, 0, 0, Color.white); //fallback - } - - public static ColorPresetWidget fromColor(ColorPickerWidget colorPicker, Color color) { - return new ColorPresetWidget(colorPicker, 0, 0, 0, 0, color); - } - - @Override - protected void extractContents(GuiGraphicsExtractor graphics, int mouseX, int mouseY, float delta) { - graphics.fill(this.getX(), this.getY(), this.getX() + this.getWidth(), this.getY() + this.getHeight(), this.color.getRGB()); - if (isMouseOver(mouseX, mouseY)) { - drawOutline(graphics, this.getX() - 1, this.getY() - 1, this.getWidth() + 2, this.getHeight() + 2, this.z + 1); - } - } - - private void drawOutline(GuiGraphicsExtractor graphics, int x, int y, int width, int height, int z) { - int color = Color.white.getRGB(); - graphics.fill(x, y, x + width, y + 1, color); - graphics.fill(x, y, x + 1, y + height, color); - graphics.fill(x + width, y, x + width - 1, y + height, color); - graphics.fill(x, y + height, x + width, y + height - 1, color); - } - - @Override - public void onPress(InputWithModifiers input) { -// BiConsumer presetListener = this.colorPickerWidget.getPresetListener(); -// if (presetListener != null) { -// presetListener.accept(this.color, this.formatting != null && this.formatting.isColor() ? this.formatting : null); -// } else { -// if (this.formatting != null && formatting.isColor()) { -// this.colorPickerWidget.color = this.color; -// this.colorPickerWidget.toggle(false); -// } else { -// this.colorPickerWidget.setColor(this.color); -// } -// } - - } - - @Override - protected void updateWidgetNarration(NarrationElementOutput builder) { - - } -} diff --git a/src/main/java/dev/hephaestus/glowcase/client/gui/widget/ingame/color/picker/ColorPickerWidget.java b/src/main/java/dev/hephaestus/glowcase/client/gui/widget/ingame/color/picker/ColorPickerWidget.java index a7d17a80..04cf4bc7 100644 --- a/src/main/java/dev/hephaestus/glowcase/client/gui/widget/ingame/color/picker/ColorPickerWidget.java +++ b/src/main/java/dev/hephaestus/glowcase/client/gui/widget/ingame/color/picker/ColorPickerWidget.java @@ -34,8 +34,6 @@ * @author Superkat32 */ public class ColorPickerWidget extends AbstractButton { - // Okay, let's do this one last time. My name is Color-Picker Parker, and I was bitten by a radioactive Gradle Elephant, and for the last like 5 minutes, I've been the one and only Glowcase Color Picker... it's like 2am right now - // To keep things simple (and keep me sane), sizes are fully locked and hardcoded // Width calculated by: ((presetScale + padding) * presetsPerLine) + padding -> ((16 + 2) * 10) + 2 // Height calculated by: Whatever my heart desired at the moment -> 116 and 146, apparently @@ -489,575 +487,4 @@ public ColorPickerWidget build() { return new ColorPickerWidget(screen, 0, 0, DEFAULT_WIDTH, DEFAULT_HEIGHT, Component.nullToEmpty("")); } } - - -// public final ColorPickerIncludedScreen screen; -// public GuiEventListener targetElement; -// public Color color = Color.red; -// public boolean includePresets = true; -// public ArrayList presetWidgets = Lists.newArrayList(); -// public boolean confirmOrCancelButtonDown = false; -// public IconButtonWidget confirmButton; -// public IconButtonWidget cancelButton; -// private Consumer changeListener; -// private BiConsumer presetListener; -// private Consumer onAccept; -// private Consumer onCancel; -// -// private boolean mouseDown = false; -// private int presetY, presetSize, presetPadding, presetHeight; -// private boolean presetDown = false; -// private int previewX, previewY, previewWidth, previewHeight; -// private int hueX, hueY, hueWidth, hueHeight; -// private boolean hueDown = false; -// private int satLightX, satLightY, satLightWidth, satLightHeight; -// private boolean satLightDown = false; -// public int hueThumbX; -// public int satLightThumbX, satLightThumbY; -// -// private float[] HSL; -// private float hue; -// private float saturation; -// private float light; -// -// public static ColorPickerWidget.Builder builder(ColorPickerIncludedScreen screen, int x, int y) { -// return new ColorPickerWidget.Builder(screen, x, y); -// } -// -// public ColorPickerWidget(ColorPickerIncludedScreen screen, int x, int y, int width, int height, Component message) { -// super(x, y, width, height, message); -// this.screen = screen; -// -// this.confirmButton = IconButtonWidget.builder(CONFIRM_TEXTURE, action -> this.confirmColor()) -// .hoverIcon(CONFIRM_HIGHLIGHTED_TEXTURE).build(); -// -// this.cancelButton = IconButtonWidget.builder(CANCEL_TEXTURE, action -> this.cancel()) -// .hoverIcon(CANCEL_HIGHLIGHTED_TEXTURE).build(); -// -// updatePositions(); -// updateHSL(); -// updateThumbPositions(); -// } -// -// public void setTargetElement(GuiEventListener element) { -// this.targetElement = element; -// } -// -// public void setIncludePresets(boolean shouldInclude) { -// this.includePresets = shouldInclude; -// } -// -// public void setPresets(boolean includeDefaultPresets, List addedPresets) { -// if (includeDefaultPresets) { -// addDefaultPresets(); -// } -// if (!addedPresets.isEmpty()) { -// for (Color preset : addedPresets) { -// this.presetWidgets.add(ColorPresetWidget.fromColor(this, preset)); -// } -// } -// } -// -// public void confirmColor() { -// if (this.onAccept != null) { -// this.onAccept.accept(this); -// } -// -// this.toggle(false); -// } -// -// public void cancel() { -// if (this.onCancel != null) { -// this.onCancel.accept(this); -// } -// -// this.toggle(false); -// } -// -// public void toggle(boolean active) { -// this.active = active; -// this.visible = active; -// if (this.active) { -// this.updatePositions(); -// this.updateHSL(); -// this.updateThumbPositions(); -// } -// } -// -// public void insertColor(Color color) { -// String hex = getHexCode(color); -// this.screen.insertHexTag(hex); -// } -// -// public void insertFormatting(ChatFormatting formatting) { -// this.screen.insertFormattingTag(formatting); -// } -// -// public void setColor(Color color) { -// this.color = color; -// this.updateHSL(); -// this.updateThumbPositions(); -// } -// -// @Override -// protected void extractContents(GuiGraphicsExtractor graphics, int mouseX, int mouseY, float delta) { -// if (!visible) return; -// updateHSL(); -// -// //graphics.setShaderColor(1f, 1f, 1f, this.alpha); -// /*RenderSystem.enableBlend(); -// RenderSystem.enableDepthTest();*/ -// Matrix3x2fStack matrices = graphics.pose(); -// //graphics.applyBlur(); -// -// graphics.nextStratum(); -// matrices.pushMatrix(); -// -// int x = this.getX(); -// int y = this.getY(); -// int z = 1; -// int width = this.getWidth(); -// int height = this.getHeight(); -// -// //background -// graphics.blit(RenderPipelines.GUI_TEXTURED, Identifier.withDefaultNamespace("textures/gui/inworld_menu_list_background.png"), x, y, 0, 0, width, height, 32, 32); -// if (this.isHoveredOrFocused()) { -// //outline -// drawOutline(graphics, x, y, width, height, Color.white); -// } -// -// //color picker stuff -// updatePositions(); -// this.confirmButton.setPosition(x + width - presetSize - presetPadding, y + height - presetSize - 2, z + 1, presetSize, presetSize + 2); -// this.cancelButton.setPosition(x + width - presetSize * 2 - presetPadding * 2 - 1, y + height - presetSize - 2, z + 1, presetSize, presetSize + 2); -// -// drawColorPreview(graphics, previewX, previewY, previewWidth, previewHeight); -// drawSatLight(graphics, satLightX, satLightY, satLightWidth, satLightHeight); -// drawHueBar(graphics, hueX, hueY, hueWidth, hueHeight, z + 1); -// if (this.includePresets) { -// //sorta dynamic but also really specific to keep it all aligned -// //I'm not going to worry about it a lot though because I do not see the custom preset thing being used a lot if at all -// drawPresets(graphics, mouseX, mouseY, delta, previewX, presetY, y + height - presetY, z + 1, presetSize, width / (presetSize + presetPadding), presetPadding); -// } -// -// this.confirmButton.extractRenderState(graphics, mouseX, mouseY, delta); -// this.cancelButton.extractRenderState(graphics, mouseX, mouseY, delta); -// -// -// matrices.popMatrix(); -// -// //graphics.setShaderColor(1f, 1f, 1f, 1f); -// } -// -// public void updatePositions() { -// int x = this.getX(); -// int y = this.getY(); -// int width = this.getWidth(); -// int height = this.getHeight(); -// -// presetSize = (int) (height / 6.5); -// presetPadding = 2; -// presetHeight = presetSize * 2 + presetPadding * 2; -// -// previewX = x + 2; -// previewY = y + 2; -// previewWidth = width / 3; -// previewHeight = height - 16 - (includePresets ? presetHeight : 0); -// satLightX = previewX + previewWidth + 2; -// satLightY = y + 2; -// satLightWidth = width - previewWidth - 6; -// satLightHeight = previewHeight; -// hueX = x + 2; -// hueY = previewY + previewHeight + 2; -// hueWidth = width - 4; -// hueHeight = height - previewHeight - 6 - (includePresets ? presetHeight : 0); -// presetY = hueY + hueHeight + presetPadding; -// } -// -// private void drawColorPreview(GuiGraphicsExtractor graphics, int x, int y, int width, int height) { -// graphics.fill(x, y, x + width, y + height, this.color.getRGB()); -// } -// -// private void drawHueBar(GuiGraphicsExtractor graphics, int x, int y, int width, int height, int z) { -// //rainbow gradient -// int[] colors = new int[]{ -// Color.red.getRGB(), Color.yellow.getRGB(), Color.green.getRGB(), -// Color.cyan.getRGB(), Color.blue.getRGB(), Color.magenta.getRGB(), -// Color.red.getRGB() -// }; -// -// int maxColors = colors.length - 1; -// for (int color = 0; color < maxColors; color++) { -// sidewaysGradient( -// graphics, -// x + (width / maxColors * (color)), y, -// width / maxColors, height, -// colors[color], colors[color + 1] -// ); -// } -// -// //thumb -// graphics.fill(hueThumbX - 3, y - 1, hueThumbX + 3, y + height + 1, getRgbFromHueThumb()); -// drawOutline(graphics, hueThumbX - 3, y - 1, 6, height + 2, Color.white); -// } -// -// private void drawSatLight(GuiGraphicsExtractor graphics, int x, int y, int width, int height) { -// //white to current color's hue, left to right -// sidewaysGradient(graphics, x, y, width, height, Color.white.getRGB(), getRgbFromHueThumb()); -// -// //transparent to black, top to bottom -// graphics.fillGradient(x, y, x + width, y + height, 0x00000000, Color.black.getRGB()); -// -// //thumb -// graphics.fill(satLightThumbX - 4, satLightThumbY - 4, satLightThumbX + 4, satLightThumbY + 4, this.color.getRGB()); -// drawOutline(graphics, satLightThumbX - 4, satLightThumbY - 4, 8, 8, Color.white); -// } -// -// private void drawOutline(GuiGraphicsExtractor graphics, int x, int y, int width, int height, Color outlineColor) { -// int color = outlineColor.getRGB(); -// graphics.fill(x, y, x + width, y + 1, color); -// graphics.fill(x, y, x + 1, y + height, color); -// graphics.fill(x + width, y, x + width - 1, y + height, color); -// graphics.fill(x, y + height, x + width, y + height - 1, color); -// } -// -// private void sidewaysGradient(GuiGraphicsExtractor graphics, int x, int y, int width, int height, int startColor, int endColor) { -// graphics.guiRenderState.addGuiElement(new GuiElementRenderState() { -// -// @Override -// public ScreenRectangle bounds() { -// return new ScreenRectangle(x, y, width, height).transformMaxBounds(graphics.pose()); -// } -// -// @Override -// public void buildVertices(VertexConsumer vertices) { -// Matrix3x2fStack matrix = graphics.pose(); -// vertices.addVertexWith2DPose(matrix, x, y).setColor(startColor); -// vertices.addVertexWith2DPose(matrix, x, y + height).setColor(startColor); -// vertices.addVertexWith2DPose(matrix, x + width, y + height).setColor(endColor); -// vertices.addVertexWith2DPose(matrix, x + width, y).setColor(endColor); -// } -// -// @Override -// public RenderPipeline pipeline() { -// return RenderPipelines.GUI; -// } -// -// @Override -// public TextureSetup textureSetup() { -// return TextureSetup.noTexture(); -// } -// -// @Override -// public @Nullable ScreenRectangle scissorArea() { -// return null; -// } -// }); -// } -// -// private void drawPresets(GuiGraphicsExtractor graphics, int mouseX, int mouseY, float delta, int x, int y, int height, int z, int presetSize, int presetsPerLine, int presetPadding) { -// int presetX = x; -// int presetY = y; -// int renderedPresets = 0; -// for (ColorPresetWidget preset : this.presetWidgets) { -// preset.setPosition(presetX, presetY, z, presetSize); -// preset.extractRenderState(graphics, mouseX, mouseY, delta); -// presetX += presetSize + presetPadding; -// renderedPresets++; -// if (renderedPresets % presetsPerLine == 0) { -// presetY += presetSize + presetPadding; -// if (presetY > y + height) { //prevent overflow -// return; -// } -// presetX = x; -// } -// } -// } -// -// //done manually to keep list order instead of looping through Formatting.values() -// public void addDefaultPresets() { -// ColorPresetWidget darkRed = ColorPresetWidget.fromFormatting(this, ChatFormatting.DARK_RED); -// ColorPresetWidget red = ColorPresetWidget.fromFormatting(this, ChatFormatting.RED); -// ColorPresetWidget gold = ColorPresetWidget.fromFormatting(this, ChatFormatting.GOLD); -// ColorPresetWidget yellow = ColorPresetWidget.fromFormatting(this, ChatFormatting.YELLOW); -// ColorPresetWidget green = ColorPresetWidget.fromFormatting(this, ChatFormatting.GREEN); -// ColorPresetWidget darkGreen = ColorPresetWidget.fromFormatting(this, ChatFormatting.DARK_GREEN); -// ColorPresetWidget aqua = ColorPresetWidget.fromFormatting(this, ChatFormatting.AQUA); -// ColorPresetWidget darkAqua = ColorPresetWidget.fromFormatting(this, ChatFormatting.DARK_AQUA); -// ColorPresetWidget blue = ColorPresetWidget.fromFormatting(this, ChatFormatting.BLUE); -// ColorPresetWidget darkBlue = ColorPresetWidget.fromFormatting(this, ChatFormatting.DARK_BLUE); -// ColorPresetWidget lightPurple = ColorPresetWidget.fromFormatting(this, ChatFormatting.LIGHT_PURPLE); -// ColorPresetWidget darkPurple = ColorPresetWidget.fromFormatting(this, ChatFormatting.DARK_PURPLE); -// ColorPresetWidget white = ColorPresetWidget.fromFormatting(this, ChatFormatting.WHITE); -// ColorPresetWidget grey = ColorPresetWidget.fromFormatting(this, ChatFormatting.GRAY); -// ColorPresetWidget darkGrey = ColorPresetWidget.fromFormatting(this, ChatFormatting.DARK_GRAY); -// ColorPresetWidget black = ColorPresetWidget.fromFormatting(this, ChatFormatting.BLACK); -// this.presetWidgets.addAll(List.of(darkRed, red, gold, yellow, green, darkGreen, aqua, darkAqua, -// blue, darkBlue, lightPurple, darkPurple, white, grey, darkGrey, black)); -// } -// -// @Override -// public void onClick(MouseButtonEvent event, boolean doubleClick) { -// this.mouseDown = true; -// this.satLightDown = false; -// this.hueDown = false; -// this.presetDown = false; -// this.confirmOrCancelButtonDown = false; -// setColorFromMouse(event, doubleClick); -// } -// -// public void setColorFromMouse(MouseButtonEvent event, boolean doubleClick) { -// int colorAlpha = color.getAlpha(); -// -// double mouseX = event.x(); -// double mouseY = event.y(); -// if (clickedSatLight(mouseX, mouseY)) { -// setSatLightFromMouse(mouseX, mouseY); -// } else if (clickedHue(mouseX, mouseY)) { -// setHueFromMouse(mouseX); -// } else if (this.confirmButton.isMouseOver(mouseX, mouseY)) { -// if (satLightDown || hueDown || presetDown || confirmOrCancelButtonDown) return; -// this.confirmButton.onClick(event, doubleClick); -// confirmOrCancelButtonDown = true; -// } else if (this.cancelButton.isMouseOver(mouseX, mouseY)) { -// if (satLightDown || hueDown || presetDown || confirmOrCancelButtonDown) return; -// this.cancelButton.onClick(event, doubleClick); -// confirmOrCancelButtonDown = true; -// } else { -// //clickedPreset also sets the preset to avoid an extra calculation -// checkAndSetPreset(event, doubleClick); -// } -// -// if (this.changeListener != null) { -// this.changeListener.accept(this.color); -// } -// } -// -// public boolean clickedSatLight(double mouseX, double mouseY) { -// if (hueDown || presetDown || confirmOrCancelButtonDown) return false; -// -// if (mouseX >= satLightX -// && mouseX <= satLightX + satLightWidth -// && mouseY >= satLightY -// && mouseY <= satLightY + satLightHeight) { -// satLightDown = true; -// } -// -// if (satLightDown) { -// satLightThumbX = (int) Math.clamp(mouseX, satLightX, satLightX + satLightWidth); -// satLightThumbY = (int) Math.clamp(mouseY, satLightY, satLightY + satLightHeight); -// } -// return satLightDown; -// } -// -// public boolean clickedHue(double mouseX, double mouseY) { -// if (satLightDown || presetDown || confirmOrCancelButtonDown) return false; -// -// if (mouseY >= hueY && mouseY <= hueY + hueHeight -// && mouseX >= hueX && mouseX <= hueX + hueWidth) { -// hueDown = true; -// } -// -// if (hueDown) { -// hueThumbX = (int) Math.clamp(mouseX, hueX, hueX + hueWidth); -// } -// return hueDown; -// } -// -// public boolean checkAndSetPreset(MouseButtonEvent event, boolean doubleClick) { -// if (satLightDown || hueDown || presetDown || confirmOrCancelButtonDown) return false; -// -// //just checks for each preset here, and also sets here so it doesn't have to check again -// for (ColorPresetWidget preset : this.presetWidgets) { -// if (preset.isMouseOver(event.x(), event.y())) { -// preset.onClick(event, doubleClick); -// //even though the preset closes the color picker, -// //this is added to prevent spamming tags when holding down the mouse button -// presetDown = true; -// } -// } -// return presetDown; -// } -// -// @Override -// protected void onDrag(MouseButtonEvent event, double dx, double dy) { -// if (mouseDown || isMouseOver(event.x(), event.y())) { -// setColorFromMouse(event, false); -// } -// } -// -// @Override -// public void onRelease(MouseButtonEvent event) { -// this.mouseDown = false; -// } -// -// @Override -// public boolean isMouseOver(double mouseX, double mouseY) { -// return super.isMouseOver(mouseX, mouseY); -// } -// -// @Override -// public void onPress(InputWithModifiers input) { -// } -// -// -// public void setSatLightFromMouse(double mouseX, double mouseY) { -// if (mouseX < satLightX) { -// this.saturation = 0f; -// } else if (mouseX > satLightX + satLightWidth) { -// this.saturation = 1f; -// } else { -// float newSat = (float) (mouseX - satLightX) / satLightWidth; -// this.saturation = Math.clamp(newSat, 0f, 1f); -// } -// -// if (mouseY < satLightY) { -// this.light = 1f; -// } else if (mouseY > satLightY + satLightHeight) { -// this.light = 0f; -// } else { -// float newLight = (float) (mouseY - satLightY) / satLightHeight; -// this.light = Math.clamp(1f - newLight, 0f, 1f); -// } -// -// setColorFromHSL(); -// } -// -// public void setHueFromMouse(double mouseX) { -// if (mouseX < hueX) { -// this.hue = 0f; -// } else if (mouseX > hueX + hueWidth) { -// this.hue = 1f; -// } else { -// float newHue = (float) (mouseX - hueX) / hueWidth; -// this.hue = Math.clamp(newHue, 0f, 1f); -// } -// -// setColorFromHSL(); -// } -// -// public void updateThumbPositions() { -// this.satLightThumbX = getSatLightThumbX(); -// this.satLightThumbY = getSatLightThumbY(); -// this.hueThumbX = getHueThumbX(); -// } -// -// private int getSatLightThumbX() { -// int min = satLightX; -// int max = satLightX + satLightWidth; -// int value = (int) (min + (satLightWidth * this.saturation)); -// return Math.clamp(value, min, max); -// } -// -// private int getSatLightThumbY() { -// int min = satLightY; -// int max = satLightY + satLightHeight; -// int value = (int) (min + (satLightHeight * (1.0f - this.light))); -// return Math.clamp(value, min, max); -// } -// -// private int getHueThumbX() { -// int min = hueX; -// int max = hueX + hueWidth; -// int value = (int) (min + hueWidth * this.hue); -// return Math.clamp(value, min, max); -// } -// -// public Color getCurrentColor() { -// return this.color; -// } -// -// public void setColorFromHSL() { -// float trueHue = (float) (hueThumbX - hueX) / hueWidth; -// this.color = Color.getHSBColor(trueHue, this.saturation, this.light); -// } -// -// public int getRgbFromHueThumb() { -// float trueHue = (float) (hueThumbX - hueX) / hueWidth; -// return Color.HSBtoRGB(trueHue, 1, 1); -// } -// -// public void updateHSL() { -// this.HSL = getHSL(); -// this.hue = HSL[0]; -// this.saturation = HSL[1]; -// this.light = HSL[2]; -// } -// -// protected float[] getHSL() { -// return Color.RGBtoHSB(this.color.getRed(), this.color.getGreen(), this.color.getBlue(), null); -// } -// -// @Override -// public void updateWidgetNarration(NarrationElementOutput builder) { -// this.defaultButtonNarrationText(builder); -// } -// -// public void setChangeListener(Consumer changeListener) { -// this.changeListener = changeListener; -// } -// -// public void setPresetListener(BiConsumer presetListener) { -// this.presetListener = presetListener; -// } -// -// public void setOnAccept(Consumer onAccept) { -// this.onAccept = onAccept; -// } -// -// public void setOnCancel(Consumer onCancel) { -// this.onCancel = onCancel; -// } -// -// public BiConsumer getPresetListener() { -// return presetListener; -// } -// -// public static String getHexCode(Color color) { -// return "#" + String.format("%1$06X", color.getRGB() & 0x00FFFFFF); -// } -// -// @Environment(EnvType.CLIENT) -// public static class Builder { -// private final ColorPickerIncludedScreen screen; -// private final int x; -// private final int y; -// private int width = 150; -// private int height = 200; -// private boolean includePresets = true; -// private boolean includeDefaultPresets = true; -// private final List presets = Lists.newArrayList(); -// -// public Builder(ColorPickerIncludedScreen screen, int x, int y) { -// this.screen = screen; -// this.x = x; -// this.y = y; -// } -// -// public ColorPickerWidget.Builder size(int width, int height) { -// this.width = width; -// this.height = height; -// return this; -// } -// -// public ColorPickerWidget.Builder includePresets(boolean shouldInclude) { -// this.includePresets = shouldInclude; -// return this; -// } -// -// public ColorPickerWidget.Builder withPreset(boolean includeDefault, Color... presets) { -// this.includeDefaultPresets = includeDefault; -// this.presets.addAll(Arrays.asList(presets)); -// return this; -// } -// -// public ColorPickerWidget build() { -// ColorPickerWidget colorPickerWidget = new ColorPickerWidget(this.screen, this.x, this.y, this.width, this.height, Component.nullToEmpty("")); -// colorPickerWidget.setIncludePresets(this.includePresets); -// if (this.includePresets) { -// colorPickerWidget.setPresets(this.includeDefaultPresets, this.presets); -// } -// return colorPickerWidget; -// } -// } } diff --git a/src/main/java/dev/hephaestus/glowcase/client/gui/widget/ingame/color/picker/PickerPreset.java b/src/main/java/dev/hephaestus/glowcase/client/gui/widget/ingame/color/picker/PickerPreset.java index cd679fa5..e76312aa 100644 --- a/src/main/java/dev/hephaestus/glowcase/client/gui/widget/ingame/color/picker/PickerPreset.java +++ b/src/main/java/dev/hephaestus/glowcase/client/gui/widget/ingame/color/picker/PickerPreset.java @@ -69,13 +69,6 @@ public int getPresetColor() { return presetFormatting; } -// public int getFormattingColorOrDefault() { -// if (this.presetFormatting != null && this.presetFormatting.isColor() && this.presetFormatting.getColor() != null) { -// return ARGB.color(1f, this.presetFormatting.getColor()); -// } -// return this.getPresetColor(); -// } - public boolean isAlphaPreset() { return isAlphaPreset; } From e5878b000532d78b93cfed95ad30857de39cd126 Mon Sep 17 00:00:00 2001 From: Kat Date: Fri, 17 Jul 2026 12:16:06 -0400 Subject: [PATCH 7/9] Chore: Extra cleanup --- .../gui/screen/ingame/ColorPickerIncludedScreen.java | 1 - .../widget/ingame/color/picker/ColorPickerWidget.java | 10 ++++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/ColorPickerIncludedScreen.java b/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/ColorPickerIncludedScreen.java index cb20793d..e2ef616b 100644 --- a/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/ColorPickerIncludedScreen.java +++ b/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/ColorPickerIncludedScreen.java @@ -81,7 +81,6 @@ default void hideColorPickerWidget() { this.getColorPickerWidget().hide(); } - // TODO - break this into FormattableScreen default void insertHexTag(String hex) {} default void insertFormattingTag(ChatFormatting formatting) {} default void insertHexColor(int color) { diff --git a/src/main/java/dev/hephaestus/glowcase/client/gui/widget/ingame/color/picker/ColorPickerWidget.java b/src/main/java/dev/hephaestus/glowcase/client/gui/widget/ingame/color/picker/ColorPickerWidget.java index 04cf4bc7..e686a0a7 100644 --- a/src/main/java/dev/hephaestus/glowcase/client/gui/widget/ingame/color/picker/ColorPickerWidget.java +++ b/src/main/java/dev/hephaestus/glowcase/client/gui/widget/ingame/color/picker/ColorPickerWidget.java @@ -468,13 +468,15 @@ public int getHueColor() { return ColorUtil.HSBtoRGB(this.hue, 1f, 1f); } - // region Unused @Override - public void onPress(@NonNull InputWithModifiers input) {} + public void onPress(@NonNull InputWithModifiers input) { + // NO-OP + } @Override - protected void updateWidgetNarration(@NonNull NarrationElementOutput output) {} - // endregion + protected void updateWidgetNarration(@NonNull NarrationElementOutput output) { + // NO-OP + } public static class Builder { private final ColorPickerIncludedScreen screen; From 18bf8f3de4b65c7e128872fa79311b4c2309a51d Mon Sep 17 00:00:00 2001 From: Kat Date: Fri, 17 Jul 2026 19:46:46 -0400 Subject: [PATCH 8/9] Feat: Add background color into main screen for Text Block --- .../screen/ingame/TextBlockEditScreen.java | 47 +++++++++++++----- .../screen/ingame/TextBlockOptionsScreen.java | 2 +- .../resources/assets/glowcase/lang/en_us.json | 9 ++-- .../textures/gui/sprites/properties.png | Bin 0 -> 140 bytes 4 files changed, 41 insertions(+), 17 deletions(-) create mode 100644 src/main/resources/assets/glowcase/textures/gui/sprites/properties.png diff --git a/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/TextBlockEditScreen.java b/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/TextBlockEditScreen.java index 929fba36..ecfd4964 100644 --- a/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/TextBlockEditScreen.java +++ b/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/TextBlockEditScreen.java @@ -1,6 +1,8 @@ package dev.hephaestus.glowcase.client.gui.screen.ingame; +import dev.hephaestus.glowcase.Glowcase; import dev.hephaestus.glowcase.block.entity.TextBlockEntity; +import dev.hephaestus.glowcase.client.gui.widget.ingame.IconButtonWidget; import dev.hephaestus.glowcase.client.gui.widget.ingame.color.HexColorEditBox; import dev.hephaestus.glowcase.client.gui.widget.ingame.color.picker.ColorPickerWidget; import dev.hephaestus.glowcase.client.gui.widget.ingame.GlowcaseEditBox; @@ -13,7 +15,9 @@ import net.minecraft.client.gui.Font; import net.minecraft.client.gui.GuiGraphicsExtractor; import net.minecraft.client.gui.components.AbstractSliderButton; +import net.minecraft.client.gui.components.AbstractWidget; import net.minecraft.client.gui.components.Button; +import net.minecraft.client.gui.components.CycleButton; import net.minecraft.client.gui.components.EditBox; import net.minecraft.client.gui.components.Tooltip; import net.minecraft.client.gui.components.events.GuiEventListener; @@ -23,11 +27,13 @@ import net.minecraft.client.input.MouseButtonEvent; import net.minecraft.network.chat.Component; import net.minecraft.network.protocol.common.custom.CustomPacketPayload; +import net.minecraft.resources.Identifier; import net.minecraft.util.Mth; import org.jetbrains.annotations.Nullable; import org.lwjgl.glfw.GLFW; import java.awt.*; +import java.time.Duration; import java.util.List; import java.util.function.Consumer; @@ -41,6 +47,8 @@ public class TextBlockEditScreen extends TextEditorScreen implements BlockEditor private TextFieldHelper selectionManager; private HexColorEditBox colorEntryWidget; + private HexColorEditBox backgroundColorEntryWidget; + private int currentRow; private long ticksSinceOpened = 0; private ColorPickerWidget colorPickerWidget; @@ -65,12 +73,12 @@ public void init() { int middle = width / 2; - var scaleSlider = new TextScale.SliderWidget(textBlockEntity, middle - 203, innerPadding, 113, 20); - addFormattingButtons(middle - 90 + 6, innerPadding, 0, 20, 2); + var scaleSlider = new TextScale.SliderWidget(textBlockEntity, middle - 203 - 5, innerPadding, 113, 20); + addFormattingButtons(middle - 90 + 6 - 5, innerPadding, 0, 20, 2); this.colorPickerWidget = this.createColorPickerWidget(); - this.colorEntryWidget = HexColorEditBox.builder(this.minecraft.font, middle + 54, innerPadding, + this.colorEntryWidget = HexColorEditBox.builder(this.minecraft.font, middle + 54 - 5, innerPadding, () -> this.textBlockEntity.color, color -> { this.textBlockEntity.color = color; this.textBlockEntity.rebake(true); @@ -79,22 +87,34 @@ public void init() { .setEditableAlpha(true) .setColorPickerWidget(this.colorPickerWidget) .build(); - this.colorEntryWidget.setTooltip(Tooltip.create(Component.translatable("gui.glowcase.color"))); - - var moreOptionsButton = Button.builder( - Component.translatable("gui.glowcase.more"), - button -> { - var optionsScreen = new TextBlockOptionsScreen(this, textBlockEntity); - Minecraft.getInstance().setScreen(optionsScreen); - }) - .bounds(middle + 124, innerPadding, 80, 20) + this.colorEntryWidget.setTooltip(Tooltip.create(Component.translatable("gui.glowcase.color_argb"))); + + this.backgroundColorEntryWidget = HexColorEditBox.builder(this.minecraft.font, middle + 54 + 64 + 6 - 5, innerPadding, + () -> this.textBlockEntity.backgroundColor, color -> { + this.textBlockEntity.backgroundColor = color; + this.textBlockEntity.rebake(true); + } + ) + .setEditableAlpha(true) + .setColorPickerWidget(this.colorPickerWidget) + .build(); + this.backgroundColorEntryWidget.setTooltip(Tooltip.create(Component.translatable("gui.glowcase.background_color_argb"))); + + Button moreOptionsButton = IconButtonWidget.builder(Glowcase.id("properties"), button -> { + TextBlockOptionsScreen optionsScreen = new TextBlockOptionsScreen(this, textBlockEntity); + Minecraft.getInstance().setScreen(optionsScreen); + }) + .dimensions(middle + 124 + 64 + 6 - 5, innerPadding, 20, 20, 16, 16) .build(); + moreOptionsButton.setTooltip(Tooltip.create(Component.translatable("gui.glowcase.extra_properties"))); this.textWidgets = List.of( - this.colorEntryWidget + this.colorEntryWidget, + this.backgroundColorEntryWidget ); this.addRenderableWidget(this.colorEntryWidget); + this.addRenderableWidget(this.backgroundColorEntryWidget); this.addRenderableWidget(scaleSlider); this.addRenderableWidget(moreOptionsButton); } @@ -129,6 +149,7 @@ private void checkRow() { } } + // FIXME - Text shadow to false is not represented in editor @Override public void extractRenderState(GuiGraphicsExtractor graphics, int mouseX, int mouseY, float delta) { super.extractRenderState(graphics, mouseX, mouseY, delta); diff --git a/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/TextBlockOptionsScreen.java b/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/TextBlockOptionsScreen.java index de09e9ef..fcde8f57 100644 --- a/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/TextBlockOptionsScreen.java +++ b/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/TextBlockOptionsScreen.java @@ -105,7 +105,7 @@ public void init() { // Note: Color picker position is messed up on this screen, but it still works otherwise this.colorPickerWidget = createColorPickerWidget(); - this.options.addHeaders(Component.translatable("gui.glowcase.color"), Component.translatable("gui.glowcase.background_color")); + this.options.addHeaders(Component.translatable("gui.glowcase.color_argb"), Component.translatable("gui.glowcase.background_color_argb")); HexColorEditBox colorEditBox = HexColorEditBox.builder(this.minecraft.font, 0, 0, () -> this.blockEntity.color, color -> { this.blockEntity.color = color; diff --git a/src/main/resources/assets/glowcase/lang/en_us.json b/src/main/resources/assets/glowcase/lang/en_us.json index 37870e38..007fc95a 100644 --- a/src/main/resources/assets/glowcase/lang/en_us.json +++ b/src/main/resources/assets/glowcase/lang/en_us.json @@ -101,8 +101,10 @@ "gui.glowcase.volume": "Volume", "gui.glowcase.pitch": "Pitch", "gui.glowcase.yaw": "Yaw", - "gui.glowcase.color": "Color (ARGB)", - "gui.glowcase.background_color": "Background Color (ARGB)", + "gui.glowcase.color_argb": "Color (ARGB)", + "gui.glowcase.color": "Color (RGB)", + "gui.glowcase.background_color_argb": "Background Color (ARGB)", + "gui.glowcase.background_color": "Background Color (RGB)", "gui.glowcase.repeat_delay": "Repeat Delay", "gui.glowcase.distance": "Distance", "gui.glowcase.sound_category": "%s", @@ -179,5 +181,6 @@ "gui.glowcase.render_distance_value.infinite": "Render Distance: Infinite", "gui.glowcase.text_alignment": "Text Alignment", "gui.glowcase.text_shadow": "Text Shadow", - "gui.glowcase.more": "More..." + "gui.glowcase.more": "More...", + "gui.glowcase.extra_properties": "Extra Properties" } diff --git a/src/main/resources/assets/glowcase/textures/gui/sprites/properties.png b/src/main/resources/assets/glowcase/textures/gui/sprites/properties.png new file mode 100644 index 0000000000000000000000000000000000000000..46df3000880fc4ab9340586792da7dda87fd981a GIT binary patch literal 140 zcmeAS@N?(olHy`uVBq!ia0vp^0wBx*Bp9q_EZ7UAm`Z~Df*BafCZDwc@?1S#978H@ z)%G3aJmA1{*kt;*``)!8#Z#KOm^Sh#?g^1;@_Mvo>eWv>de5ym{q?5Wj1OWNNA);O m{{1U>oV{gI>IAO|&Drw7&CP4izvI{mvc}WZ&t;ucLK6UYJTm0~ literal 0 HcmV?d00001 From 7edc7f97f99e556ada161b84db435e26fb30c653 Mon Sep 17 00:00:00 2001 From: Kat Date: Fri, 17 Jul 2026 19:48:41 -0400 Subject: [PATCH 9/9] Chore: Optimize imports for various classes updated in the Color Picker rewrite --- .../client/gui/screen/ingame/PopupBlockEditScreen.java | 1 - .../client/gui/screen/ingame/SpriteBlockEditScreen.java | 1 - .../client/gui/screen/ingame/TextBlockEditScreen.java | 8 +------- .../client/gui/screen/ingame/TextBlockOptionsScreen.java | 2 -- .../gui/widget/ingame/color/picker/ColorPickerWidget.java | 2 -- 5 files changed, 1 insertion(+), 13 deletions(-) diff --git a/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/PopupBlockEditScreen.java b/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/PopupBlockEditScreen.java index 384f73ee..b9d7b844 100644 --- a/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/PopupBlockEditScreen.java +++ b/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/PopupBlockEditScreen.java @@ -16,7 +16,6 @@ import net.minecraft.client.input.KeyEvent; import net.minecraft.client.input.MouseButtonEvent; import net.minecraft.network.chat.Component; -import net.minecraft.network.chat.TextColor; import net.minecraft.network.protocol.common.custom.CustomPacketPayload; import net.minecraft.util.Mth; import org.jetbrains.annotations.Nullable; diff --git a/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/SpriteBlockEditScreen.java b/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/SpriteBlockEditScreen.java index 75d7a919..325978d2 100644 --- a/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/SpriteBlockEditScreen.java +++ b/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/SpriteBlockEditScreen.java @@ -16,7 +16,6 @@ import net.minecraft.client.input.MouseButtonEvent; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.network.chat.Component; -import net.minecraft.network.chat.TextColor; import net.minecraft.network.protocol.common.custom.CustomPacketPayload; import net.minecraft.resources.Identifier; import net.minecraft.server.packs.resources.ResourceManager; diff --git a/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/TextBlockEditScreen.java b/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/TextBlockEditScreen.java index ecfd4964..e00dca71 100644 --- a/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/TextBlockEditScreen.java +++ b/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/TextBlockEditScreen.java @@ -2,11 +2,10 @@ import dev.hephaestus.glowcase.Glowcase; import dev.hephaestus.glowcase.block.entity.TextBlockEntity; +import dev.hephaestus.glowcase.client.gui.widget.ingame.GlowcaseEditBox; import dev.hephaestus.glowcase.client.gui.widget.ingame.IconButtonWidget; import dev.hephaestus.glowcase.client.gui.widget.ingame.color.HexColorEditBox; import dev.hephaestus.glowcase.client.gui.widget.ingame.color.picker.ColorPickerWidget; -import dev.hephaestus.glowcase.client.gui.widget.ingame.GlowcaseEditBox; -import dev.hephaestus.glowcase.client.util.ColorUtil; import dev.hephaestus.glowcase.packet.C2SEditTextBlock; import dev.hephaestus.glowcase.util.InputFilters; import dev.hephaestus.glowcase.util.ParseUtil; @@ -15,9 +14,7 @@ import net.minecraft.client.gui.Font; import net.minecraft.client.gui.GuiGraphicsExtractor; import net.minecraft.client.gui.components.AbstractSliderButton; -import net.minecraft.client.gui.components.AbstractWidget; import net.minecraft.client.gui.components.Button; -import net.minecraft.client.gui.components.CycleButton; import net.minecraft.client.gui.components.EditBox; import net.minecraft.client.gui.components.Tooltip; import net.minecraft.client.gui.components.events.GuiEventListener; @@ -27,13 +24,10 @@ import net.minecraft.client.input.MouseButtonEvent; import net.minecraft.network.chat.Component; import net.minecraft.network.protocol.common.custom.CustomPacketPayload; -import net.minecraft.resources.Identifier; import net.minecraft.util.Mth; import org.jetbrains.annotations.Nullable; import org.lwjgl.glfw.GLFW; -import java.awt.*; -import java.time.Duration; import java.util.List; import java.util.function.Consumer; diff --git a/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/TextBlockOptionsScreen.java b/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/TextBlockOptionsScreen.java index fcde8f57..bdf87961 100644 --- a/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/TextBlockOptionsScreen.java +++ b/src/main/java/dev/hephaestus/glowcase/client/gui/screen/ingame/TextBlockOptionsScreen.java @@ -4,7 +4,6 @@ import dev.hephaestus.glowcase.client.gui.screen.ingame.TextBlockEditScreen.TextScale; import dev.hephaestus.glowcase.client.gui.widget.ingame.color.HexColorEditBox; import dev.hephaestus.glowcase.client.gui.widget.ingame.color.picker.ColorPickerWidget; -import dev.hephaestus.glowcase.client.util.ColorUtil; import dev.hephaestus.glowcase.packet.C2SEditTextBlock; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiGraphicsExtractor; @@ -12,7 +11,6 @@ import net.minecraft.client.gui.components.Button; import net.minecraft.client.gui.components.ContainerObjectSelectionList; import net.minecraft.client.gui.components.CycleButton; -import net.minecraft.client.gui.components.EditBox; import net.minecraft.client.gui.components.StringWidget; import net.minecraft.client.gui.components.events.GuiEventListener; import net.minecraft.client.gui.layouts.HeaderAndFooterLayout; diff --git a/src/main/java/dev/hephaestus/glowcase/client/gui/widget/ingame/color/picker/ColorPickerWidget.java b/src/main/java/dev/hephaestus/glowcase/client/gui/widget/ingame/color/picker/ColorPickerWidget.java index e686a0a7..183adaa3 100644 --- a/src/main/java/dev/hephaestus/glowcase/client/gui/widget/ingame/color/picker/ColorPickerWidget.java +++ b/src/main/java/dev/hephaestus/glowcase/client/gui/widget/ingame/color/picker/ColorPickerWidget.java @@ -20,11 +20,9 @@ import net.minecraft.network.chat.Component; import net.minecraft.resources.Identifier; import net.minecraft.util.ARGB; -import net.minecraft.util.CommonColors; import org.jetbrains.annotations.Nullable; import org.jspecify.annotations.NonNull; -import java.util.Iterator; import java.util.List; import java.util.function.Consumer;