Skip to content

Commit 7b4c95e

Browse files
committed
ColorPicker: Add okhsl HS and HL rectangular picker shapes
1 parent 26df043 commit 7b4c95e

File tree

7 files changed

+383
-37
lines changed

7 files changed

+383
-37
lines changed

doc/classes/ColorPicker.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,12 @@
144144
<constant name="SHAPE_NONE" value="4" enum="PickerShapeType">
145145
The color space shape and the shape select button are hidden. Can't be selected from the shapes popup.
146146
</constant>
147+
<constant name="SHAPE_OK_HS_RECTANGLE" value="5" enum="PickerShapeType">
148+
OKHSL Color Model rectangle with constant lightness.
149+
</constant>
150+
<constant name="SHAPE_OK_HL_RECTANGLE" value="6" enum="PickerShapeType">
151+
OKHSL Color Model rectangle with constant saturation.
152+
</constant>
147153
</constants>
148154
<theme_items>
149155
<theme_item name="focused_not_editing_cursor_color" data_type="color" type="Color" default="Color(1, 1, 1, 0.275)">

editor/editor_settings.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -569,7 +569,7 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
569569
_initial_set("interface/inspector/resources_to_open_in_new_inspector", open_in_new_inspector_defaults);
570570

571571
EDITOR_SETTING_BASIC(Variant::INT, PROPERTY_HINT_ENUM, "interface/inspector/default_color_picker_mode", (int32_t)ColorPicker::MODE_RGB, "RGB,HSV,RAW,OKHSL")
572-
EDITOR_SETTING_BASIC(Variant::INT, PROPERTY_HINT_ENUM, "interface/inspector/default_color_picker_shape", (int32_t)ColorPicker::SHAPE_OKHSL_CIRCLE, "HSV Rectangle,HSV Rectangle Wheel,VHS Circle,OKHSL Circle")
572+
EDITOR_SETTING_BASIC(Variant::INT, PROPERTY_HINT_ENUM, "interface/inspector/default_color_picker_shape", (int32_t)ColorPicker::SHAPE_OKHSL_CIRCLE, "HSV Rectangle,HSV Rectangle Wheel,VHS Circle,OKHSL Circle,OK HS Rectangle:5,OK HL Rectangle") // `SHAPE_NONE` is 4.
573573
EDITOR_SETTING_BASIC(Variant::BOOL, PROPERTY_HINT_NONE, "interface/inspector/color_picker_show_intensity", true, "");
574574

575575
// Theme

editor/plugins/script_text_editor.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
#include "editor/gui/editor_toaster.h"
4444
#include "editor/plugins/editor_context_menu_plugin.h"
4545
#include "editor/themes/editor_scale.h"
46+
#include "scene/gui/grid_container.h"
4647
#include "scene/gui/menu_button.h"
4748
#include "scene/gui/rich_text_label.h"
4849
#include "scene/gui/slider.h"
@@ -2845,7 +2846,7 @@ ScriptTextEditor::ScriptTextEditor() {
28452846
inline_color_options->set_text_overrun_behavior(TextServer::OVERRUN_TRIM_ELLIPSIS);
28462847
inline_color_options->set_fit_to_longest_item(false);
28472848
inline_color_options->connect("item_selected", callable_mp(this, &ScriptTextEditor::_update_color_text).unbind(1));
2848-
inline_color_picker->get_slider(ColorPicker::SLIDER_COUNT)->get_parent()->add_sibling(inline_color_options);
2849+
inline_color_picker->get_slider_container()->add_sibling(inline_color_options);
28492850

28502851
connection_info_dialog = memnew(ConnectionInfoDialog);
28512852

scene/gui/color_picker.cpp

Lines changed: 60 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -139,10 +139,10 @@ void ColorPicker::_notification(int p_what) {
139139
}
140140

141141
if (current_shape != SHAPE_NONE) {
142-
btn_shape->set_button_icon(shape_popup->get_item_icon(current_shape));
142+
btn_shape->set_button_icon(shape_popup->get_item_icon(get_current_shape_index()));
143143
}
144144

145-
for (int i = 0; i < SLIDER_COUNT; i++) {
145+
for (int i = 0; i < MODE_SLIDER_COUNT; i++) {
146146
labels[i]->set_custom_minimum_size(Size2(theme_cache.label_width, 0));
147147
sliders[i]->add_theme_constant_override(SNAME("center_grabber"), theme_cache.center_slider_grabbers);
148148
}
@@ -185,7 +185,7 @@ void ColorPicker::_notification(int p_what) {
185185
case NOTIFICATION_FOCUS_ENTER:
186186
case NOTIFICATION_FOCUS_EXIT: {
187187
if (current_shape != SHAPE_NONE) {
188-
shapes[current_shape]->cursor_editing = false;
188+
shapes[get_current_shape_index()]->cursor_editing = false;
189189
}
190190
} break;
191191

@@ -198,7 +198,7 @@ void ColorPicker::_notification(int p_what) {
198198
input->is_action_just_released("ui_down")) {
199199
gamepad_event_delay_ms = DEFAULT_GAMEPAD_EVENT_DELAY_MS;
200200
if (current_shape == SHAPE_NONE) {
201-
shapes[current_shape]->echo_multiplier = 1;
201+
shapes[get_current_shape_index()]->echo_multiplier = 1;
202202
}
203203
accept_event();
204204
set_process_internal(false);
@@ -217,7 +217,7 @@ void ColorPicker::_notification(int p_what) {
217217
input->is_action_pressed("ui_right") - input->is_action_pressed("ui_left"),
218218
input->is_action_pressed("ui_down") - input->is_action_pressed("ui_up"));
219219

220-
shapes[current_shape]->update_cursor(color_change_vector, true);
220+
shapes[get_current_shape_index()]->update_cursor(color_change_vector, true);
221221
accept_event();
222222
}
223223
return;
@@ -309,7 +309,7 @@ void fragment() {
309309

310310
circle_ok_color_shader.instantiate();
311311
circle_ok_color_shader->set_code(OK_COLOR_SHADER + R"(
312-
// ColorPicker ok color hsv circle shader.
312+
// ColorPicker ok color hsl circle shader.
313313
314314
uniform float ok_hsl_l = 1.0;
315315
@@ -330,20 +330,48 @@ void fragment() {
330330
float b4 = float(sqrt(x * x + y * y) < 0.5);
331331
COLOR = vec4(col, (b + b2 + b3 + b4) / 4.00);
332332
})");
333+
334+
rectangle_ok_color_hs_shader.instantiate();
335+
rectangle_ok_color_hs_shader->set_code(OK_COLOR_SHADER + R"(
336+
// ColorPicker ok color hs rectangle shader.
337+
338+
uniform float ok_hsl_l = 0.0;
339+
340+
void fragment() {
341+
float h = UV.x;
342+
float s = 1.0 - UV.y;
343+
vec3 col = okhsl_to_srgb(vec3(h, s, ok_hsl_l));
344+
COLOR = vec4(col, 1.0);
345+
})");
346+
347+
rectangle_ok_color_hl_shader.instantiate();
348+
rectangle_ok_color_hl_shader->set_code(OK_COLOR_SHADER + R"(
349+
// ColorPicker ok color hl rectangle shader.
350+
351+
uniform float ok_hsl_s = 0.0;
352+
353+
void fragment() {
354+
float h = UV.x;
355+
float l = 1.0 - UV.y;
356+
vec3 col = okhsl_to_srgb(vec3(h, ok_hsl_s, l));
357+
COLOR = vec4(col, 1.0);
358+
})");
333359
}
334360

335361
void ColorPicker::finish_shaders() {
336362
wheel_shader.unref();
337363
circle_shader.unref();
338364
circle_ok_color_shader.unref();
365+
rectangle_ok_color_hs_shader.unref();
366+
rectangle_ok_color_hl_shader.unref();
339367
}
340368

341369
void ColorPicker::set_focus_on_line_edit() {
342370
callable_mp((Control *)c_text, &Control::grab_focus).call_deferred();
343371
}
344372

345373
void ColorPicker::set_focus_on_picker_shape() {
346-
shapes[current_shape]->grab_focus();
374+
shapes[get_current_shape_index()]->grab_focus();
347375
}
348376

349377
void ColorPicker::_update_controls() {
@@ -384,7 +412,7 @@ void ColorPicker::_update_controls() {
384412

385413
int i = 0;
386414
for (ColorPickerShape *shape : shapes) {
387-
bool is_active = current_shape == i;
415+
bool is_active = get_current_shape_index() == i;
388416
i++;
389417

390418
if (!shape->is_initialized) {
@@ -552,14 +580,14 @@ void ColorPicker::create_slider(GridContainer *gc, int idx) {
552580
slider->connect("drag_started", callable_mp(this, &ColorPicker::_slider_drag_started));
553581
slider->connect(SceneStringName(value_changed), callable_mp(this, &ColorPicker::_slider_value_changed).unbind(1));
554582
slider->connect("drag_ended", callable_mp(this, &ColorPicker::_slider_drag_ended).unbind(1));
555-
if (idx < SLIDER_COUNT) {
583+
if (idx < MODE_SLIDER_COUNT) {
556584
slider->connect(SceneStringName(draw), callable_mp(this, &ColorPicker::_slider_draw).bind(idx));
557585
} else if (idx == SLIDER_ALPHA) {
558586
slider->connect(SceneStringName(draw), callable_mp(this, &ColorPicker::_alpha_slider_draw));
559587
}
560588
slider->connect(SceneStringName(gui_input), callable_mp(this, &ColorPicker::_slider_or_spin_input));
561589

562-
if (idx < SLIDER_COUNT) {
590+
if (idx < MODE_SLIDER_COUNT) {
563591
sliders[idx] = slider;
564592
values[idx] = val;
565593
labels[idx] = lbl;
@@ -618,10 +646,8 @@ void ColorPicker::set_palette_saved_callback(const Callable &p_palette_saved) {
618646
#endif
619647

620648
HSlider *ColorPicker::get_slider(int p_idx) {
621-
if (p_idx < SLIDER_COUNT) {
622-
return sliders[p_idx];
623-
}
624-
return alpha_slider;
649+
ERR_FAIL_INDEX_V(p_idx, MODE_MAX, nullptr);
650+
return sliders[p_idx];
625651
}
626652

627653
Vector<float> ColorPicker::get_active_slider_values() {
@@ -649,7 +675,7 @@ void ColorPicker::_copy_normalized_to_hsv_okhsl() {
649675
}
650676

651677
void ColorPicker::_copy_hsv_okhsl_to_normalized() {
652-
if (current_shape != SHAPE_NONE && shapes[current_shape]->is_ok_hsl()) {
678+
if (current_shape != SHAPE_NONE && shapes[get_current_shape_index()]->is_ok_hsl()) {
653679
color_normalized.set_ok_hsl(ok_hsl_h, ok_hsl_s, ok_hsl_l, color_normalized.a);
654680
} else {
655681
color_normalized.set_hsv(h, s, v, color_normalized.a);
@@ -712,7 +738,7 @@ void ColorPicker::_reset_sliders_theme() {
712738
style_box_flat->set_content_margin(SIDE_TOP, 16 * theme_cache.base_scale);
713739
style_box_flat->set_bg_color(Color(0.2, 0.23, 0.31).lerp(Color(0, 0, 0, 1), 0.3).clamp());
714740

715-
for (int i = 0; i < SLIDER_COUNT; i++) {
741+
for (int i = 0; i < MODE_SLIDER_COUNT; i++) {
716742
sliders[i]->begin_bulk_theme_override();
717743
sliders[i]->add_theme_icon_override(SNAME("grabber"), theme_cache.bar_arrow);
718744
sliders[i]->add_theme_icon_override(SNAME("grabber_highlight"), theme_cache.bar_arrow);
@@ -815,7 +841,7 @@ void ColorPicker::_update_color(bool p_update_sliders) {
815841
_update_text_value();
816842

817843
if (current_shape != SHAPE_NONE) {
818-
for (Control *control : shapes[current_shape]->controls) {
844+
for (Control *control : shapes[get_current_shape_index()]->controls) {
819845
control->queue_redraw();
820846
}
821847
}
@@ -931,11 +957,11 @@ void ColorPicker::set_picker_shape(PickerShapeType p_shape) {
931957
return;
932958
}
933959
if (current_shape != SHAPE_NONE) {
934-
shape_popup->set_item_checked(current_shape, false);
960+
shape_popup->set_item_checked(get_current_shape_index(), false);
935961
}
936962
if (p_shape != SHAPE_NONE) {
937-
shape_popup->set_item_checked(p_shape, true);
938-
btn_shape->set_button_icon(shape_popup->get_item_icon(p_shape));
963+
shape_popup->set_item_checked(shape_to_index(p_shape), true);
964+
btn_shape->set_button_icon(shape_popup->get_item_icon(shape_to_index(p_shape)));
939965
}
940966

941967
current_shape = p_shape;
@@ -1018,6 +1044,11 @@ void ColorPicker::_quick_open_palette_file_selected(const String &p_path) {
10181044
file_dialog->set_file_mode(FileDialog::FILE_MODE_OPEN_FILE);
10191045
_palette_file_selected(p_path);
10201046
}
1047+
1048+
GridContainer *ColorPicker::get_slider_container() {
1049+
return slider_gc;
1050+
}
1051+
10211052
#endif // ifdef TOOLS_ENABLED
10221053

10231054
void ColorPicker::_palette_file_selected(const String &p_path) {
@@ -1344,7 +1375,7 @@ void ColorPicker::set_colorize_sliders(bool p_colorize_sliders) {
13441375
if (colorize_sliders) {
13451376
Ref<StyleBoxEmpty> style_box_empty(memnew(StyleBoxEmpty));
13461377

1347-
for (int i = 0; i < SLIDER_COUNT; i++) {
1378+
for (int i = 0; i < MODE_SLIDER_COUNT; i++) {
13481379
sliders[i]->add_theme_style_override("slider", style_box_empty);
13491380
}
13501381

@@ -1354,7 +1385,7 @@ void ColorPicker::set_colorize_sliders(bool p_colorize_sliders) {
13541385
style_box_flat->set_content_margin(SIDE_TOP, 16 * theme_cache.base_scale);
13551386
style_box_flat->set_bg_color(Color(0.2, 0.23, 0.31).lerp(Color(0, 0, 0, 1), 0.3).clamp());
13561387

1357-
for (int i = 0; i < SLIDER_COUNT; i++) {
1388+
for (int i = 0; i < MODE_SLIDER_COUNT; i++) {
13581389
sliders[i]->add_theme_style_override("slider", style_box_flat);
13591390
}
13601391

@@ -2051,7 +2082,7 @@ void ColorPicker::_bind_methods() {
20512082
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "edit_intensity"), "set_edit_intensity", "is_editing_intensity");
20522083
ADD_PROPERTY(PropertyInfo(Variant::INT, "color_mode", PROPERTY_HINT_ENUM, "RGB,HSV,LINEAR,OKHSL"), "set_color_mode", "get_color_mode");
20532084
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "deferred_mode"), "set_deferred_mode", "is_deferred_mode");
2054-
ADD_PROPERTY(PropertyInfo(Variant::INT, "picker_shape", PROPERTY_HINT_ENUM, "HSV Rectangle,HSV Rectangle Wheel,VHS Circle,OKHSL Circle,None"), "set_picker_shape", "get_picker_shape");
2085+
ADD_PROPERTY(PropertyInfo(Variant::INT, "picker_shape", PROPERTY_HINT_ENUM, "HSV Rectangle,HSV Rectangle Wheel,VHS Circle,OKHSL Circle,OK HS Rectangle:5,OK HL Rectangle,None:4"), "set_picker_shape", "get_picker_shape");
20552086
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "can_add_swatches"), "set_can_add_swatches", "are_swatches_enabled");
20562087
ADD_GROUP("Customization", "");
20572088
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sampler_visible"), "set_sampler_visible", "is_sampler_visible");
@@ -2077,6 +2108,8 @@ void ColorPicker::_bind_methods() {
20772108
BIND_ENUM_CONSTANT(SHAPE_VHS_CIRCLE);
20782109
BIND_ENUM_CONSTANT(SHAPE_OKHSL_CIRCLE);
20792110
BIND_ENUM_CONSTANT(SHAPE_NONE);
2111+
BIND_ENUM_CONSTANT(SHAPE_OK_HS_RECTANGLE);
2112+
BIND_ENUM_CONSTANT(SHAPE_OK_HL_RECTANGLE);
20802113

20812114
BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_CONSTANT, ColorPicker, content_margin, "margin");
20822115
BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, ColorPicker, label_width);
@@ -2158,16 +2191,18 @@ ColorPicker::ColorPicker() {
21582191
add_shape(memnew(ColorPickerShapeWheel(this)));
21592192
add_shape(memnew(ColorPickerShapeVHSCircle(this)));
21602193
add_shape(memnew(ColorPickerShapeOKHSLCircle(this)));
2194+
add_shape(memnew(ColorPickerShapeOKHSRectangle(this)));
2195+
add_shape(memnew(ColorPickerShapeOKHLRectangle(this)));
21612196

21622197
shape_popup = btn_shape->get_popup();
21632198
{
21642199
int i = 0;
21652200
for (const ColorPickerShape *shape : shapes) {
2166-
shape_popup->add_radio_check_item(shape->get_name(), i);
2201+
shape_popup->add_radio_check_item(shape->get_name(), index_to_shape(i));
21672202
i++;
21682203
}
21692204
}
2170-
shape_popup->set_item_checked(current_shape, true);
2205+
shape_popup->set_item_checked(get_current_shape_index(), true);
21712206
shape_popup->connect(SceneStringName(id_pressed), callable_mp(this, &ColorPicker::set_picker_shape));
21722207
shape_popup->connect("about_to_popup", callable_mp(this, &ColorPicker::_block_input_on_popup_show));
21732208
shape_popup->connect(SNAME("popup_hide"), callable_mp(this, &ColorPicker::_enable_input_on_popup_hide));

scene/gui/color_picker.h

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,8 @@ class ColorPicker : public VBoxContainer {
8888
friend class ColorPickerShapeCircle;
8989
friend class ColorPickerShapeVHSCircle;
9090
friend class ColorPickerShapeOKHSLCircle;
91+
friend class ColorPickerShapeOKHSRectangle;
92+
friend class ColorPickerShapeOKHLRectangle;
9193

9294
friend class ColorModeRGB;
9395
friend class ColorModeHSV;
@@ -113,19 +115,49 @@ class ColorPicker : public VBoxContainer {
113115
SHAPE_VHS_CIRCLE,
114116
SHAPE_OKHSL_CIRCLE,
115117
SHAPE_NONE,
118+
SHAPE_OK_HS_RECTANGLE,
119+
SHAPE_OK_HL_RECTANGLE,
116120

117121
SHAPE_MAX
118122
};
119123

120-
static const int SLIDER_COUNT = 3;
124+
private:
125+
// Ideally, `SHAPE_NONE` should be -1 so that we don't need to convert shape type to index.
126+
// In order to avoid breaking compatibility, we have to use these methods for conversion.
127+
inline int get_current_shape_index() {
128+
return shape_to_index(current_shape);
129+
}
130+
131+
static inline int shape_to_index(PickerShapeType p_shape) {
132+
if (p_shape == SHAPE_NONE) {
133+
return -1;
134+
}
135+
if (p_shape > SHAPE_NONE) {
136+
return p_shape - 1;
137+
}
138+
return p_shape;
139+
}
140+
141+
static inline PickerShapeType index_to_shape(int p_index) {
142+
if (p_index == -1) {
143+
return SHAPE_NONE;
144+
}
145+
if (p_index >= SHAPE_NONE) {
146+
return (PickerShapeType)(p_index + 1);
147+
}
148+
return (PickerShapeType)p_index;
149+
}
150+
151+
public:
152+
static const int MODE_SLIDER_COUNT = 3;
153+
121154
enum SLIDER_EXTRA {
122-
SLIDER_INTENSITY = 3,
155+
SLIDER_INTENSITY = MODE_SLIDER_COUNT,
123156
SLIDER_ALPHA,
124157

125158
SLIDER_MAX
126159
};
127160

128-
private:
129161
enum class MenuOption {
130162
MENU_SAVE,
131163
MENU_SAVE_AS,
@@ -134,17 +166,20 @@ class ColorPicker : public VBoxContainer {
134166
MENU_CLEAR,
135167
};
136168

169+
private:
137170
static inline Ref<Shader> wheel_shader;
138171
static inline Ref<Shader> circle_shader;
139172
static inline Ref<Shader> circle_ok_color_shader;
173+
static inline Ref<Shader> rectangle_ok_color_hs_shader;
174+
static inline Ref<Shader> rectangle_ok_color_hl_shader;
140175
static inline List<Color> preset_cache;
141176
static inline List<Color> recent_preset_cache;
142177

143178
#ifdef TOOLS_ENABLED
144179
Object *editor_settings = nullptr;
145180
#endif
146181

147-
int current_slider_count = SLIDER_COUNT;
182+
int current_slider_count = MODE_SLIDER_COUNT;
148183

149184
const float DEFAULT_GAMEPAD_EVENT_DELAY_MS = 1.0 / 2;
150185
const float GAMEPAD_EVENT_REPEAT_RATE_MS = 1.0 / 30;
@@ -394,6 +429,7 @@ class ColorPicker : public VBoxContainer {
394429
void _quick_open_palette_file_selected(const String &p_path);
395430
#endif
396431

432+
GridContainer *get_slider_container();
397433
HSlider *get_slider(int idx);
398434
Vector<float> get_active_slider_values();
399435

0 commit comments

Comments
 (0)