Skip to content

Commit 6bb3c19

Browse files
committed
improvements to color picker
1 parent 7df3412 commit 6bb3c19

2 files changed

Lines changed: 168 additions & 25 deletions

File tree

src/main/java/com/cleanroommc/modularui/utils/Color.java

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import com.google.gson.JsonObject;
1212
import com.google.gson.JsonParseException;
1313

14+
import java.util.Locale;
1415
import java.util.function.ToIntFunction;
1516

1617
/**
@@ -747,6 +748,66 @@ public static void resetGlColor() {
747748
setGlColorOpaque(WHITE.main);
748749
}
749750

751+
/**
752+
* Returns a six digit hex string representation of a color component with upper case letters. Alpha is ignored.
753+
*
754+
* @param rgb rgb color
755+
* @return hex string representation
756+
*/
757+
public static String rgbToFullHexString(int rgb) {
758+
return toFullHexString(getRed(rgb), getGreen(rgb), getBlue(rgb));
759+
}
760+
761+
/**
762+
* Returns an eight digit hex string representation of a color component with upper case letters.
763+
*
764+
* @param argb argb color
765+
* @return hex string representation
766+
*/
767+
public static String argbToFullHexString(int argb) {
768+
return toFullHexString(getRed(argb), getGreen(argb), getBlue(argb), getAlpha(argb));
769+
}
770+
771+
/**
772+
* Returns a six digit hex string representation of a color component with upper case letters.
773+
*
774+
* @param r red
775+
* @param g green
776+
* @param b blue
777+
* @return hex string representation
778+
*/
779+
public static String toFullHexString(int r, int g, int b) {
780+
return componentToFullHexString(r) + componentToFullHexString(g) + componentToFullHexString(b);
781+
}
782+
783+
/**
784+
* Returns an eight digit hex string representation of a color component with upper case letters.
785+
*
786+
* @param r red
787+
* @param g green
788+
* @param b blue
789+
* @param a alpha
790+
* @return hex string representation
791+
*/
792+
public static String toFullHexString(int r, int g, int b, int a) {
793+
return componentToFullHexString(a) + toFullHexString(r, g, b);
794+
}
795+
796+
/**
797+
* Returns a double-digit hex string representation of a color component with upper case letters.
798+
*
799+
* @param component red, green, blue or alpha
800+
* @return hex string representation
801+
*/
802+
public static String componentToFullHexString(int component) {
803+
component &= 0xFF;
804+
if (component == 0) return "00";
805+
if (component == 255) return "FF";
806+
String s = Integer.toHexString(component).toUpperCase(Locale.ENGLISH);
807+
if (s.length() == 1) s = "0" + s;
808+
return s;
809+
}
810+
750811
/**
751812
* Parses a ARGB color of a json element.
752813
*

src/main/java/com/cleanroommc/modularui/widgets/ColorPickerDialog.java

Lines changed: 107 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.cleanroommc.modularui.widgets;
22

3+
import com.cleanroommc.modularui.ModularUI;
34
import com.cleanroommc.modularui.api.GuiAxis;
45
import com.cleanroommc.modularui.api.drawable.IDrawable;
56
import com.cleanroommc.modularui.api.drawable.IKey;
@@ -15,14 +16,22 @@
1516
import com.cleanroommc.modularui.widgets.layout.Row;
1617
import com.cleanroommc.modularui.widgets.textfield.TextFieldWidget;
1718

19+
import java.util.Locale;
1820
import java.util.function.Consumer;
1921

2022
public class ColorPickerDialog extends Dialog<Integer> {
2123

2224
private static final IDrawable handleBackground = new Rectangle().setColor(Color.WHITE.main);
2325

2426
private int color;
25-
private final int alpha;
27+
private int red;
28+
private int green;
29+
private int blue;
30+
private double hue;
31+
private double saturation;
32+
private double value;
33+
34+
private int alpha;
2635
private final boolean controlAlpha;
2736

2837
private final Rectangle preview = new Rectangle();
@@ -39,17 +48,10 @@ public ColorPickerDialog(Consumer<Integer> resultConsumer, int startColor, boole
3948

4049
public ColorPickerDialog(String name, Consumer<Integer> resultConsumer, int startColor, boolean controlAlpha) {
4150
super(name, resultConsumer);
42-
this.alpha = Color.getAlpha(startColor);
43-
updateColor(startColor);
4451
this.controlAlpha = controlAlpha;
52+
this.alpha = Color.getAlpha(startColor);
53+
updateAll(startColor);
4554
size(140, controlAlpha ? 106 : 94).background(GuiTextures.MC_BACKGROUND);
46-
IWidget alphaSlider = controlAlpha ? new Row()
47-
.widthRel(1f).height(12)
48-
.child(IKey.str("A: ").asWidget().heightRel(1f))
49-
.child(createSlider(this.sliderBackgroundA)
50-
.bounds(0, 255)
51-
.value(new DoubleValue.Dynamic(() -> Color.getAlpha(this.color), val -> updateColor(Color.withAlpha(this.color, (int) val))))) : null;
52-
5355
PagedWidget.Controller controller = new PagedWidget.Controller();
5456
child(new Column()
5557
.left(5).right(5).top(5).bottom(5)
@@ -71,22 +73,23 @@ public ColorPickerDialog(String name, Consumer<Integer> resultConsumer, int star
7173
.setValidator(this::validateRawColor)
7274
.value(new StringValue.Dynamic(() -> {
7375
if (controlAlpha) {
74-
return "#" + Integer.toHexString(this.color);
76+
return "#" + Color.toFullHexString(this.red, this.green, this.blue, this.alpha);
7577
}
76-
return "#" + Integer.toHexString(Color.withAlpha(this.color, 0));
78+
return "#" + Color.toFullHexString(this.red, this.green, this.blue);
7779
}, val -> {
7880
try {
79-
updateColor(Integer.decode(val));
81+
updateAll((int) (long) Long.decode(val));
8082
} catch (NumberFormatException ignored) {
83+
ModularUI.LOGGER.error("Illegal color string '{}'", val);
8184
}
8285
})))
8386
.child(this.preview.asWidget().background(GuiTextures.CHECKBOARD).size(10, 10).margin(1)))
8487
.child(new PagedWidget<>()
8588
.left(5).right(5)
8689
.expanded()
8790
.controller(controller)
88-
.addPage(createRGBPage(alphaSlider))
89-
.addPage(createHSVPage(alphaSlider)))
91+
.addPage(createRGBPage(createAlphaSlider("rgb")))
92+
.addPage(createHSVPage(createAlphaSlider("hsv"))))
9093
.child(new Row()
9194
.left(10).right(10).height(14)
9295
.mainAxisAlignment(Alignment.MainAxis.SPACE_BETWEEN)
@@ -113,20 +116,23 @@ private IWidget createRGBPage(IWidget alphaSlider) {
113116
.widthRel(1f).height(12)
114117
.child(IKey.str("R: ").asWidget().heightRel(1f))
115118
.child(createSlider(this.sliderBackgroundR)
119+
.debugName("red")
116120
.bounds(0, 255)
117-
.value(new DoubleValue.Dynamic(() -> Color.getRed(this.color), val -> updateColor(Color.withRed(this.color, (int) val))))))
121+
.value(new DoubleValue.Dynamic(() -> this.red, this::updateRed))))
118122
.child(new Row()
119123
.widthRel(1f).height(12)
120124
.child(IKey.str("G: ").asWidget().heightRel(1f))
121125
.child(createSlider(this.sliderBackgroundG)
126+
.debugName("green")
122127
.bounds(0, 255)
123-
.value(new DoubleValue.Dynamic(() -> Color.getGreen(this.color), val -> updateColor(Color.withGreen(this.color, (int) val))))))
128+
.value(new DoubleValue.Dynamic(() -> this.green, this::updateGreen))))
124129
.child(new Row()
125130
.widthRel(1f).height(12)
126131
.child(IKey.str("B: ").asWidget().heightRel(1f))
127132
.child(createSlider(this.sliderBackgroundB)
133+
.debugName("blue")
128134
.bounds(0, 255)
129-
.value(new DoubleValue.Dynamic(() -> Color.getBlue(this.color), val -> updateColor(Color.withBlue(this.color, (int) val))))))
135+
.value(new DoubleValue.Dynamic(() -> this.blue, this::updateBlue))))
130136
.childIf(alphaSlider != null, alphaSlider);
131137
}
132138

@@ -137,20 +143,23 @@ private IWidget createHSVPage(IWidget alphaSlider) {
137143
.widthRel(1f).height(12)
138144
.child(IKey.str("H: ").asWidget().heightRel(1f))
139145
.child(createSlider(new HueBar(GuiAxis.X))
146+
.debugName("hue")
140147
.bounds(0, 360)
141-
.value(new DoubleValue.Dynamic(() -> Color.getHue(this.color), val -> updateColor(Color.withHSVHue(this.color, (float) val))))))
148+
.value(new DoubleValue.Dynamic(() -> this.hue, this::updateHue))))
142149
.child(new Row()
143150
.widthRel(1f).height(12)
144151
.child(IKey.str("S: ").asWidget().heightRel(1f))
145152
.child(createSlider(this.sliderBackgroundS)
153+
.debugName("saturation")
146154
.bounds(0, 1)
147-
.value(new DoubleValue.Dynamic(() -> Color.getHSVSaturation(this.color), val -> updateColor(Color.withHSVSaturation(this.color, (float) val))))))
155+
.value(new DoubleValue.Dynamic(() -> this.saturation, this::updateSaturation))))
148156
.child(new Row()
149157
.widthRel(1f).height(12)
150158
.child(IKey.str("V: ").asWidget().heightRel(1f))
151159
.child(createSlider(this.sliderBackgroundV)
160+
.debugName("value")
152161
.bounds(0, 1)
153-
.value(new DoubleValue.Dynamic(() -> Color.getValue(this.color), val -> updateColor(Color.withValue(this.color, (float) val))))))
162+
.value(new DoubleValue.Dynamic(() -> this.value, this::updateValue))))
154163
.childIf(alphaSlider != null, alphaSlider);
155164
}
156165

@@ -163,6 +172,16 @@ private static SliderWidget createSlider(IDrawable background) {
163172
.sliderSize(2, 8);
164173
}
165174

175+
private IWidget createAlphaSlider(String s) {
176+
return controlAlpha ? new Row()
177+
.widthRel(1f).height(12)
178+
.child(IKey.str("A: ").asWidget().heightRel(1f))
179+
.child(createSlider(this.sliderBackgroundA)
180+
.debugName("alpha " + s)
181+
.bounds(0, 255)
182+
.value(new DoubleValue.Dynamic(() -> this.alpha, this::updateAlpha))) : null;
183+
}
184+
166185
private String validateRawColor(String raw) {
167186
if (!raw.startsWith("#")) {
168187
if (raw.startsWith("0x") || raw.startsWith("0X")) {
@@ -173,11 +192,74 @@ private String validateRawColor(String raw) {
173192
return raw;
174193
}
175194

176-
public void updateColor(int color) {
177-
this.color = color;
195+
private void updateRed(double v) {
196+
this.red = (int) v;
197+
updateFromRGB();
198+
}
199+
200+
private void updateGreen(double v) {
201+
this.green = (int) v;
202+
updateFromRGB();
203+
}
204+
205+
private void updateBlue(double v) {
206+
this.blue = (int) v;
207+
updateFromRGB();
208+
}
209+
210+
private void updateHue(double v) {
211+
this.hue = v;
212+
updateFromHSV();
213+
}
214+
215+
private void updateSaturation(double v) {
216+
this.saturation = v;
217+
updateFromHSV();
218+
}
219+
220+
private void updateValue(double v) {
221+
this.value = v;
222+
updateFromHSV();
223+
}
224+
225+
private void updateAlpha(double v) {
226+
if (!this.controlAlpha) return;
227+
this.alpha = (int) v;
228+
this.color = Color.withAlpha(this.color, this.alpha);
229+
}
230+
231+
private void updateFromRGB() {
232+
this.color = Color.argb(this.red, this.green, this.blue, this.alpha);
233+
this.saturation = Color.getHSVSaturation(this.color);
234+
this.value = Color.getValue(this.color);
235+
this.hue = Color.getHue(this.color);
236+
updateColor(this.color);
237+
}
238+
239+
private void updateFromHSV() {
240+
this.color = Color.ofHSV((float) this.hue, (float) this.saturation, (float) this.value, this.alpha);
241+
this.red = Color.getRed(this.color);
242+
this.green = Color.getGreen(this.color);
243+
this.blue = Color.getBlue(this.color);
244+
updateColor(this.color);
245+
}
246+
247+
public void updateAll(int color) {
178248
if (!this.controlAlpha) {
179-
this.color = Color.withAlpha(this.color, this.alpha);
249+
color = Color.withAlpha(color, this.alpha);
180250
}
251+
this.color = color;
252+
this.alpha = Color.getAlpha(color);
253+
this.red = Color.getRed(color);
254+
this.green = Color.getGreen(color);
255+
this.blue = Color.getBlue(color);
256+
this.hue = Color.getHue(color);
257+
this.saturation = Color.getHSVSaturation(color);
258+
this.value = Color.getValue(color);
259+
updateColor(color);
260+
}
261+
262+
public void updateColor(int color) {
181263
color = Color.withAlpha(color, 255);
182264
int rs = Color.withRed(color, 0), re = Color.withRed(color, 255);
183265
int gs = Color.withGreen(color, 0), ge = Color.withGreen(color, 255);
@@ -189,6 +271,6 @@ public void updateColor(int color) {
189271
this.sliderBackgroundA.setHorizontalGradient(as, ae);
190272
this.sliderBackgroundS.setHorizontalGradient(Color.withHSVSaturation(color, 0f), Color.withHSVSaturation(color, 1f));
191273
this.sliderBackgroundV.setHorizontalGradient(Color.withValue(color, 0f), Color.withValue(color, 1f));
192-
this.preview.setColor(this.color);
274+
this.preview.setColor(color);
193275
}
194276
}

0 commit comments

Comments
 (0)