color picker

This commit is contained in:
2025-05-12 10:28:37 -05:00
parent f9baa0fe5f
commit 6eb3fc8092
6 changed files with 321 additions and 108 deletions
@@ -44,7 +44,7 @@ public class ElementRenderer {
int adjustedMouseX = (int) mouseX - element.x;
int adjustedMouseY = (int) mouseY - element.y;
if (Utils.isHovering(adjustedMouseX, adjustedMouseY, element.width, element.height, element.scale)) {
if (element.opacity > 0 && Utils.isHovering(adjustedMouseX, adjustedMouseY, element.width, element.height, element.scale)) {
element.focused = true;
element.click((int) (adjustedMouseX * element.scale), (int) (adjustedMouseY * element.scale));
}
@@ -71,7 +71,7 @@ public class ElementRenderer {
public static void keyPressed(List<Element> elements, int keyCode, int scanCode, int modifiers) {
for (Element element : new ArrayList<>(elements)) {
if (element.focused) {
if (element.focused && element.opacity > 0) {
element.keyPressed(keyCode, scanCode, modifiers);
char typedChar = Utils.getCharFromKey(keyCode, modifiers);
@@ -0,0 +1,167 @@
package org.saturnclient.ui2.components.dialog;
import java.awt.Color;
import org.saturnclient.saturnclient.SaturnClient;
import org.saturnclient.saturnclient.config.Property;
import org.saturnclient.ui2.SaturnScreen;
import net.minecraft.client.gui.DrawContext;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.text.Text;
public class ColorDialog extends Screen {
private Property<Integer> prop;
private SaturnScreen parent;
private static final int PICKER_WIDTH = 200;
private static final int PICKER_HEIGHT = 200;
private static final int SLIDER_WIDTH = 200;
private static final int SLIDER_HEIGHT = 10;
private int selectedX = 0;
private int selectedY = 0;
private float opacity = 1.0f;
private boolean dragging = false;
public ColorDialog(Property<Integer> prop , SaturnScreen parent) {
super(Text.literal("Color Dialog"));
this.prop = prop;
this.parent = parent;
int alpha = (prop.value >> 24) & 0xFF;
if (alpha == 0) alpha = 255; // fallback if no alpha specified
this.opacity = alpha / 255.0f;
}
@Override
public void close() {
SaturnClient.client.setScreen(parent);
}
@Override
public void render(DrawContext context, int mouseX, int mouseY, float delta) {
renderBackground(context, mouseX, mouseY, delta);
int xStart = (width - PICKER_WIDTH) / 2;
int yStart = (height - PICKER_HEIGHT) / 2;
// Draw the HSV hue/saturation square (brightness fixed at 1)
for (int x = 0; x < PICKER_WIDTH; x++) {
for (int y = 0; y < PICKER_HEIGHT; y++) {
float hue = x / (float) PICKER_WIDTH;
float saturation = y / (float) PICKER_HEIGHT;
int color = Color.HSBtoRGB(hue, saturation, 1.0f);
context.fill(xStart + x, yStart + y, xStart + x + 1, yStart + y + 1, 0xFF000000 | color);
}
}
int x = (xStart + selectedX) - 4;
int y = (yStart + selectedY) - 4;
context.fill(x, y, x+8, y+8, 0xFF000000 | prop.value);
context.drawBorder(x, y, 8, 8, 0xFFffffff);
renderSlider(context, mouseX, mouseY, delta);
}
public void renderSlider(DrawContext context, int mouseX, int mouseY, float delta) {
int xStart = (width - SLIDER_WIDTH) / 2;
int yStart = (height - SLIDER_HEIGHT - PICKER_HEIGHT) / 2 - 10;
// Draw slider background (left = transparent, right = white)
for (int x = 0; x < SLIDER_WIDTH; x++) {
float localOpacity = x / (float) SLIDER_WIDTH;
int alpha = (int)(localOpacity * 255) & 0xFF;
int color = (alpha << 24) | (prop.value & 0xFFFFFF);
context.fill(xStart + x, yStart, xStart + x + 1, yStart + SLIDER_HEIGHT, color);
}
// Draw current value as a marker (thin black line)
int knobX = xStart + (int)(opacity * SLIDER_WIDTH);
context.fill(knobX - 1, yStart - 2, knobX + 1, yStart + SLIDER_HEIGHT + 2, 0xFF000000);
// Draw opacity text
// context.drawText(textRenderer, String.format("Opacity: %.2f", opacity), xStart, yStart - 15, 0xFFFFFF, false);
}
@Override
public boolean mouseClicked(double mouseX, double mouseY, int button) {
int xStart = (width - PICKER_WIDTH) / 2;
int yStart = (height - PICKER_HEIGHT) / 2;
int relX = (int) mouseX - xStart;
int relY = (int) mouseY - yStart;
if (relX >= 0 && relX < PICKER_WIDTH && relY >= 0 && relY < PICKER_HEIGHT) {
float hue = relX / (float) PICKER_WIDTH;
float saturation = relY / (float) PICKER_HEIGHT;
prop.value = Color.HSBtoRGB(hue, saturation, 1.0f);
int alpha = (int)(opacity * 255) & 0xFF;
prop.value = (alpha << 24) | (prop.value & 0xFFFFFF);
selectedX = relX;
selectedY = relY;
return true;
} else if (isInSlider(mouseX, mouseY)) {
updateOpacity(mouseX);
dragging = true;
return true;
}
return super.mouseClicked(mouseX, mouseY, button);
}
@Override
public boolean mouseReleased(double mouseX, double mouseY, int button) {
dragging = false;
return super.mouseReleased(mouseX, mouseY, button);
}
@Override
public boolean mouseDragged(double mouseX, double mouseY, int button, double deltaX, double deltaY) {
if (dragging) {
updateOpacity(mouseX);
return true;
} else {
int xStart = (width - PICKER_WIDTH) / 2;
int yStart = (height - PICKER_HEIGHT) / 2;
int relX = (int) mouseX - xStart;
int relY = (int) mouseY - yStart;
if (relX >= 0 && relX < PICKER_WIDTH && relY >= 0 && relY < PICKER_HEIGHT) {
float hue = relX / (float) PICKER_WIDTH;
float saturation = relY / (float) PICKER_HEIGHT;
prop.value = Color.HSBtoRGB(hue, saturation, 1.0f);
int alpha = (int)(opacity * 255) & 0xFF;
prop.value = (alpha << 24) | (prop.value & 0xFFFFFF);
selectedX = relX;
selectedY = relY;
return true;
}
}
return super.mouseDragged(mouseX, mouseY, button, deltaX, deltaY);
}
private boolean isInSlider(double mouseX, double mouseY) {
int xStart = (width - SLIDER_WIDTH) / 2;
int yStart = (height - SLIDER_HEIGHT - PICKER_HEIGHT) / 2 - 10;
return mouseX >= xStart && mouseX <= xStart + SLIDER_WIDTH &&
mouseY >= yStart && mouseY <= yStart + SLIDER_HEIGHT;
}
private void updateOpacity(double mouseX) {
int xStart = (width - SLIDER_WIDTH) / 2;
float newOpacity = (float)((mouseX - xStart) / SLIDER_WIDTH);
opacity = Math.max(0.0f, Math.min(1.0f, newOpacity));
int alpha = (int)(opacity * 255) & 0xFF;
prop.value = (alpha << 24) | (prop.value & 0xFFFFFF);
}
}
@@ -1,22 +1,11 @@
package org.saturnclient.ui2.components.inputs;
import org.lwjgl.glfw.GLFW;
import org.saturnclient.saturnclient.SaturnClient;
import org.saturnclient.saturnclient.config.ConfigManager;
import org.saturnclient.saturnclient.config.Property;
import org.saturnclient.ui.SaturnUi;
import org.saturnclient.ui2.Element;
import org.saturnclient.ui2.ElementContext;
import org.saturnclient.ui2.RenderScope;
import org.saturnclient.ui2.resources.Fonts;
import net.minecraft.client.font.TextRenderer;
public class FloatInput extends Element {
String text = "";
public class FloatInput extends Input {
public Property<Float> prop;
public int cursorPosition = 0;
private TextRenderer textRenderer = SaturnClient.client.textRenderer;
public FloatInput(Property<Float> prop) {
this.width = 120;
@@ -25,27 +14,6 @@ public class FloatInput extends Element {
this.text = String.valueOf(prop.value);
}
@Override
public void click(int mouseX, int mouseY) {
int scrollOffset = getScrollOffset();
String visibleText = text.substring(scrollOffset);
int newCursorPos = scrollOffset;
int textWidth = 0;
for (int i = 0; i < visibleText.length(); i++) {
textWidth = textRenderer.getWidth(visibleText.substring(0, i + 1));
if (textWidth > mouseX) {
break;
}
newCursorPos++;
}
cursorPosition = newCursorPos;
}
@Override
public void charTyped(char chr) {
if ((Character.isDigit(chr) || chr == '.') && text.length() < 10) {
@@ -65,83 +33,21 @@ public class FloatInput extends Element {
}
@Override
public void keyPressed(int keyCode, int scanCode, int modifiers) {
if (keyCode == GLFW.GLFW_KEY_BACKSPACE) {
if (cursorPosition > 0) {
text = text.substring(0, cursorPosition - 1) +
text.substring(cursorPosition);
cursorPosition--;
if (text.length() == 0) {
text = "0";
cursorPosition = 1;
}
prop.value = Float.parseFloat(text);
ConfigManager.save();
}
} else if (keyCode == GLFW.GLFW_KEY_LEFT) {
if (cursorPosition > 0) {
cursorPosition--;
}
} else if (keyCode == GLFW.GLFW_KEY_RIGHT) {
if (cursorPosition < text.length()) {
cursorPosition++;
}
public void backspace() {
if (text.length() == 0) {
text = "0";
cursorPosition = 1;
}
prop.value = Float.parseFloat(text);
ConfigManager.save();
}
@Override
public void render(RenderScope renderScope, ElementContext ctx) {
public void checkReset() {
if (prop.isReset) {
this.text = String.valueOf(prop.value);
this.cursorPosition = 0;
prop.isReset = false;
}
renderScope.drawRoundedRectangle(0, 0, width, height, 10, 0xFF000000);
int scrollOffset = getScrollOffset();
String visibleText = getVisibleText(scrollOffset);
int textColor = focused ? 0xFFFFFF : 0xAAAAAA;
renderScope.drawText(visibleText, 2, 2, false, textColor);
if (focused) {
int cursorX = 2 +
textRenderer.getWidth(
SaturnUi.text(
visibleText.substring(0, cursorPosition - scrollOffset)));
renderScope.drawRect(cursorX, 2, 1, height - 1, 0xFFFFFFFF);
}
}
private int getScrollOffset() {
if (text.isEmpty()) {
return 0;
}
int offset = 0;
int maxWidth = width - 4; // Available width for text
while (offset < cursorPosition) { // Ensure cursor remains visible
String visibleText = text.substring(offset, cursorPosition);
if (textRenderer.getWidth(SaturnUi.text(visibleText)) > maxWidth) {
offset++;
} else {
break;
}
}
return offset;
}
private String getVisibleText(int scrollOffset) {
String visibleText = text.substring(scrollOffset);
// Ensure text does not overflow past the available width
for (int i = 1; i <= visibleText.length(); i++) {
if (textRenderer.getWidth(
SaturnUi.text(visibleText.substring(0, i))) > width - 4) {
return visibleText.substring(0, i - 1); // Trim overflow
}
}
return visibleText;
}
}
@@ -0,0 +1,33 @@
package org.saturnclient.ui2.components.inputs;
import org.saturnclient.saturnclient.SaturnClient;
import org.saturnclient.saturnclient.config.Property;
import org.saturnclient.ui2.Element;
import org.saturnclient.ui2.ElementContext;
import org.saturnclient.ui2.RenderScope;
import org.saturnclient.ui2.SaturnScreen;
import org.saturnclient.ui2.components.dialog.ColorDialog;
import org.saturnclient.ui2.resources.Fonts;
public class HexInput extends Element {
public Property<Integer> prop;
public SaturnScreen screen;
public HexInput(Property<Integer> prop, SaturnScreen screen) {
this.width = 50;
this.prop = prop;
this.height = Fonts.getHeight() + 8;
this.scale = 0.8f;
this.screen = screen;
}
@Override
public void click(int mouseX, int mouseY) {
SaturnClient.client.setScreen(new ColorDialog(prop, screen));
}
@Override
public void render(RenderScope renderScope, ElementContext ctx) {
renderScope.drawRoundedRectangle(0, 0, width, height, 10, prop.value);
}
}
@@ -0,0 +1,111 @@
package org.saturnclient.ui2.components.inputs;
import org.lwjgl.glfw.GLFW;
import org.saturnclient.saturnclient.SaturnClient;
import org.saturnclient.ui.SaturnUi;
import org.saturnclient.ui2.Element;
import org.saturnclient.ui2.ElementContext;
import org.saturnclient.ui2.RenderScope;
public abstract class Input extends Element {
String text = "";
public int cursorPosition = 0;
public abstract void checkReset();
public abstract void backspace();
public boolean validateBackspace() {
return true;
}
@Override
public void keyPressed(int keyCode, int scanCode, int modifiers) {
if (keyCode == GLFW.GLFW_KEY_BACKSPACE) {
if (cursorPosition > 0 && validateBackspace()) {
text = text.substring(0, cursorPosition - 1) +
text.substring(cursorPosition);
cursorPosition--;
backspace();
}
} else if (keyCode == GLFW.GLFW_KEY_LEFT) {
if (cursorPosition > 0) {
cursorPosition--;
}
} else if (keyCode == GLFW.GLFW_KEY_RIGHT) {
if (cursorPosition < text.length()) {
cursorPosition++;
}
}
}
@Override
public void click(int mouseX, int mouseY) {
int scrollOffset = getScrollOffset();
String visibleText = text.substring(scrollOffset);
int newCursorPos = scrollOffset;
int textWidth = 0;
for (int i = 0; i < visibleText.length(); i++) {
textWidth = SaturnClient.client.textRenderer.getWidth(visibleText.substring(0, i + 1));
if (textWidth > mouseX) {
break;
}
newCursorPos++;
}
cursorPosition = newCursorPos;
}
@Override
public void render(RenderScope renderScope, ElementContext ctx) {
checkReset();
renderScope.drawRoundedRectangle(0, 0, width, height, 10, 0xFF000000);
int scrollOffset = getScrollOffset();
String visibleText = getVisibleText(scrollOffset);
int textColor = focused ? 0xFFFFFF : 0xAAAAAA;
renderScope.drawText(visibleText, 2, 2, false, textColor);
if (focused) {
int cursorX = 2 +
SaturnClient.client.textRenderer.getWidth(
SaturnUi.text(
visibleText.substring(0, cursorPosition - scrollOffset)));
renderScope.drawRect(cursorX, 2, 1, height - 1, 0xFFFFFFFF);
}
}
protected int getScrollOffset() {
if (text.isEmpty()) {
return 0;
}
int offset = 0;
int maxWidth = width - 4; // Available width for text
while (offset < cursorPosition) { // Ensure cursor remains visible
String visibleText = text.substring(offset, cursorPosition);
if (SaturnClient.client.textRenderer.getWidth(SaturnUi.text(visibleText)) > maxWidth) {
offset++;
} else {
break;
}
}
return offset;
}
protected String getVisibleText(int scrollOffset) {
String visibleText = text.substring(scrollOffset);
// Ensure text does not overflow past the available width
for (int i = 1; i <= visibleText.length(); i++) {
if (SaturnClient.client.textRenderer.getWidth(
SaturnUi.text(visibleText.substring(0, i))) > width - 4) {
return visibleText.substring(0, i - 1); // Trim overflow
}
}
return visibleText;
}
}
@@ -2,13 +2,11 @@ package org.saturnclient.ui2.screens;
import org.saturnclient.saturnclient.SaturnClient;
import org.saturnclient.saturnclient.SaturnClientConfig;
import org.saturnclient.saturnclient.config.Property;
import org.saturnclient.saturnclient.menus.HudEditor;
import org.saturnclient.ui.Textures;
import org.saturnclient.ui2.SaturnScreen;
import org.saturnclient.ui2.anim.Fade;
import org.saturnclient.ui2.anim.SlideY;
import org.saturnclient.ui2.components.inputs.FloatInput;
import org.saturnclient.ui2.elements.Button;
import org.saturnclient.ui2.elements.ImageTexture;
import org.saturnclient.ui2.elements.TextureButton;
@@ -27,8 +25,6 @@ public class TitleMenu extends SaturnScreen {
public void ui() {
backgroundBlur = 0;
draw(new FloatInput(new Property<Float>(1.0f)));
draw(new ImageTexture(Textures.LOGO_TEXT).dimensions(98, 10).centerOffset(width, height, 0, -36).animation(new Fade(700)));
draw(new ImageTexture(SaturnClientConfig.getLogo()).dimensions(98, 98).centerOffset(width, height, 0, -82).animation(new SlideY(700, -40)));