diff --git a/doc/classes/ColorPicker.xml b/doc/classes/ColorPicker.xml
index 07e17b066c..1ca6703c92 100644
--- a/doc/classes/ColorPicker.xml
+++ b/doc/classes/ColorPicker.xml
@@ -144,6 +144,12 @@
The color space shape and the shape select button are hidden. Can't be selected from the shapes popup.
+
+ OKHSL Color Model rectangle with constant lightness.
+
+
+ OKHSL Color Model rectangle with constant saturation.
+
diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp
index 7a97dc5902..fb009eb497 100644
--- a/editor/editor_settings.cpp
+++ b/editor/editor_settings.cpp
@@ -569,7 +569,7 @@ void EditorSettings::_load_defaults(Ref p_extra_config) {
_initial_set("interface/inspector/resources_to_open_in_new_inspector", open_in_new_inspector_defaults);
EDITOR_SETTING_BASIC(Variant::INT, PROPERTY_HINT_ENUM, "interface/inspector/default_color_picker_mode", (int32_t)ColorPicker::MODE_RGB, "RGB,HSV,RAW,OKHSL")
- 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")
+ 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.
EDITOR_SETTING_BASIC(Variant::BOOL, PROPERTY_HINT_NONE, "interface/inspector/color_picker_show_intensity", true, "");
// Theme
diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp
index 559c4ce73b..9c6a05d536 100644
--- a/editor/plugins/script_text_editor.cpp
+++ b/editor/plugins/script_text_editor.cpp
@@ -43,6 +43,7 @@
#include "editor/gui/editor_toaster.h"
#include "editor/plugins/editor_context_menu_plugin.h"
#include "editor/themes/editor_scale.h"
+#include "scene/gui/grid_container.h"
#include "scene/gui/menu_button.h"
#include "scene/gui/rich_text_label.h"
#include "scene/gui/slider.h"
@@ -2845,7 +2846,7 @@ ScriptTextEditor::ScriptTextEditor() {
inline_color_options->set_text_overrun_behavior(TextServer::OVERRUN_TRIM_ELLIPSIS);
inline_color_options->set_fit_to_longest_item(false);
inline_color_options->connect("item_selected", callable_mp(this, &ScriptTextEditor::_update_color_text).unbind(1));
- inline_color_picker->get_slider(ColorPicker::SLIDER_COUNT)->get_parent()->add_sibling(inline_color_options);
+ inline_color_picker->get_slider_container()->add_sibling(inline_color_options);
connection_info_dialog = memnew(ConnectionInfoDialog);
diff --git a/scene/gui/color_picker.cpp b/scene/gui/color_picker.cpp
index 0096d4d0fe..bbd543b8e8 100644
--- a/scene/gui/color_picker.cpp
+++ b/scene/gui/color_picker.cpp
@@ -139,10 +139,10 @@ void ColorPicker::_notification(int p_what) {
}
if (current_shape != SHAPE_NONE) {
- btn_shape->set_button_icon(shape_popup->get_item_icon(current_shape));
+ btn_shape->set_button_icon(shape_popup->get_item_icon(get_current_shape_index()));
}
- for (int i = 0; i < SLIDER_COUNT; i++) {
+ for (int i = 0; i < MODE_SLIDER_COUNT; i++) {
labels[i]->set_custom_minimum_size(Size2(theme_cache.label_width, 0));
sliders[i]->add_theme_constant_override(SNAME("center_grabber"), theme_cache.center_slider_grabbers);
}
@@ -185,7 +185,7 @@ void ColorPicker::_notification(int p_what) {
case NOTIFICATION_FOCUS_ENTER:
case NOTIFICATION_FOCUS_EXIT: {
if (current_shape != SHAPE_NONE) {
- shapes[current_shape]->cursor_editing = false;
+ shapes[get_current_shape_index()]->cursor_editing = false;
}
} break;
@@ -198,7 +198,7 @@ void ColorPicker::_notification(int p_what) {
input->is_action_just_released("ui_down")) {
gamepad_event_delay_ms = DEFAULT_GAMEPAD_EVENT_DELAY_MS;
if (current_shape == SHAPE_NONE) {
- shapes[current_shape]->echo_multiplier = 1;
+ shapes[get_current_shape_index()]->echo_multiplier = 1;
}
accept_event();
set_process_internal(false);
@@ -217,7 +217,7 @@ void ColorPicker::_notification(int p_what) {
input->is_action_pressed("ui_right") - input->is_action_pressed("ui_left"),
input->is_action_pressed("ui_down") - input->is_action_pressed("ui_up"));
- shapes[current_shape]->update_cursor(color_change_vector, true);
+ shapes[get_current_shape_index()]->update_cursor(color_change_vector, true);
accept_event();
}
return;
@@ -309,7 +309,7 @@ void fragment() {
circle_ok_color_shader.instantiate();
circle_ok_color_shader->set_code(OK_COLOR_SHADER + R"(
-// ColorPicker ok color hsv circle shader.
+// ColorPicker ok color hsl circle shader.
uniform float ok_hsl_l = 1.0;
@@ -330,12 +330,40 @@ void fragment() {
float b4 = float(sqrt(x * x + y * y) < 0.5);
COLOR = vec4(col, (b + b2 + b3 + b4) / 4.00);
})");
+
+ rectangle_ok_color_hs_shader.instantiate();
+ rectangle_ok_color_hs_shader->set_code(OK_COLOR_SHADER + R"(
+// ColorPicker ok color hs rectangle shader.
+
+uniform float ok_hsl_l = 0.0;
+
+void fragment() {
+ float h = UV.x;
+ float s = 1.0 - UV.y;
+ vec3 col = okhsl_to_srgb(vec3(h, s, ok_hsl_l));
+ COLOR = vec4(col, 1.0);
+})");
+
+ rectangle_ok_color_hl_shader.instantiate();
+ rectangle_ok_color_hl_shader->set_code(OK_COLOR_SHADER + R"(
+// ColorPicker ok color hl rectangle shader.
+
+uniform float ok_hsl_s = 0.0;
+
+void fragment() {
+ float h = UV.x;
+ float l = 1.0 - UV.y;
+ vec3 col = okhsl_to_srgb(vec3(h, ok_hsl_s, l));
+ COLOR = vec4(col, 1.0);
+})");
}
void ColorPicker::finish_shaders() {
wheel_shader.unref();
circle_shader.unref();
circle_ok_color_shader.unref();
+ rectangle_ok_color_hs_shader.unref();
+ rectangle_ok_color_hl_shader.unref();
}
void ColorPicker::set_focus_on_line_edit() {
@@ -343,7 +371,7 @@ void ColorPicker::set_focus_on_line_edit() {
}
void ColorPicker::set_focus_on_picker_shape() {
- shapes[current_shape]->grab_focus();
+ shapes[get_current_shape_index()]->grab_focus();
}
void ColorPicker::_update_controls() {
@@ -384,7 +412,7 @@ void ColorPicker::_update_controls() {
int i = 0;
for (ColorPickerShape *shape : shapes) {
- bool is_active = current_shape == i;
+ bool is_active = get_current_shape_index() == i;
i++;
if (!shape->is_initialized) {
@@ -552,14 +580,14 @@ void ColorPicker::create_slider(GridContainer *gc, int idx) {
slider->connect("drag_started", callable_mp(this, &ColorPicker::_slider_drag_started));
slider->connect(SceneStringName(value_changed), callable_mp(this, &ColorPicker::_slider_value_changed).unbind(1));
slider->connect("drag_ended", callable_mp(this, &ColorPicker::_slider_drag_ended).unbind(1));
- if (idx < SLIDER_COUNT) {
+ if (idx < MODE_SLIDER_COUNT) {
slider->connect(SceneStringName(draw), callable_mp(this, &ColorPicker::_slider_draw).bind(idx));
} else if (idx == SLIDER_ALPHA) {
slider->connect(SceneStringName(draw), callable_mp(this, &ColorPicker::_alpha_slider_draw));
}
slider->connect(SceneStringName(gui_input), callable_mp(this, &ColorPicker::_slider_or_spin_input));
- if (idx < SLIDER_COUNT) {
+ if (idx < MODE_SLIDER_COUNT) {
sliders[idx] = slider;
values[idx] = val;
labels[idx] = lbl;
@@ -618,10 +646,8 @@ void ColorPicker::set_palette_saved_callback(const Callable &p_palette_saved) {
#endif
HSlider *ColorPicker::get_slider(int p_idx) {
- if (p_idx < SLIDER_COUNT) {
- return sliders[p_idx];
- }
- return alpha_slider;
+ ERR_FAIL_INDEX_V(p_idx, MODE_MAX, nullptr);
+ return sliders[p_idx];
}
Vector ColorPicker::get_active_slider_values() {
@@ -649,7 +675,7 @@ void ColorPicker::_copy_normalized_to_hsv_okhsl() {
}
void ColorPicker::_copy_hsv_okhsl_to_normalized() {
- if (current_shape != SHAPE_NONE && shapes[current_shape]->is_ok_hsl()) {
+ if (current_shape != SHAPE_NONE && shapes[get_current_shape_index()]->is_ok_hsl()) {
color_normalized.set_ok_hsl(ok_hsl_h, ok_hsl_s, ok_hsl_l, color_normalized.a);
} else {
color_normalized.set_hsv(h, s, v, color_normalized.a);
@@ -712,7 +738,7 @@ void ColorPicker::_reset_sliders_theme() {
style_box_flat->set_content_margin(SIDE_TOP, 16 * theme_cache.base_scale);
style_box_flat->set_bg_color(Color(0.2, 0.23, 0.31).lerp(Color(0, 0, 0, 1), 0.3).clamp());
- for (int i = 0; i < SLIDER_COUNT; i++) {
+ for (int i = 0; i < MODE_SLIDER_COUNT; i++) {
sliders[i]->begin_bulk_theme_override();
sliders[i]->add_theme_icon_override(SNAME("grabber"), theme_cache.bar_arrow);
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) {
_update_text_value();
if (current_shape != SHAPE_NONE) {
- for (Control *control : shapes[current_shape]->controls) {
+ for (Control *control : shapes[get_current_shape_index()]->controls) {
control->queue_redraw();
}
}
@@ -931,11 +957,11 @@ void ColorPicker::set_picker_shape(PickerShapeType p_shape) {
return;
}
if (current_shape != SHAPE_NONE) {
- shape_popup->set_item_checked(current_shape, false);
+ shape_popup->set_item_checked(get_current_shape_index(), false);
}
if (p_shape != SHAPE_NONE) {
- shape_popup->set_item_checked(p_shape, true);
- btn_shape->set_button_icon(shape_popup->get_item_icon(p_shape));
+ shape_popup->set_item_checked(shape_to_index(p_shape), true);
+ btn_shape->set_button_icon(shape_popup->get_item_icon(shape_to_index(p_shape)));
}
current_shape = p_shape;
@@ -1018,6 +1044,11 @@ void ColorPicker::_quick_open_palette_file_selected(const String &p_path) {
file_dialog->set_file_mode(FileDialog::FILE_MODE_OPEN_FILE);
_palette_file_selected(p_path);
}
+
+GridContainer *ColorPicker::get_slider_container() {
+ return slider_gc;
+}
+
#endif // ifdef TOOLS_ENABLED
void ColorPicker::_palette_file_selected(const String &p_path) {
@@ -1344,7 +1375,7 @@ void ColorPicker::set_colorize_sliders(bool p_colorize_sliders) {
if (colorize_sliders) {
Ref style_box_empty(memnew(StyleBoxEmpty));
- for (int i = 0; i < SLIDER_COUNT; i++) {
+ for (int i = 0; i < MODE_SLIDER_COUNT; i++) {
sliders[i]->add_theme_style_override("slider", style_box_empty);
}
@@ -1354,7 +1385,7 @@ void ColorPicker::set_colorize_sliders(bool p_colorize_sliders) {
style_box_flat->set_content_margin(SIDE_TOP, 16 * theme_cache.base_scale);
style_box_flat->set_bg_color(Color(0.2, 0.23, 0.31).lerp(Color(0, 0, 0, 1), 0.3).clamp());
- for (int i = 0; i < SLIDER_COUNT; i++) {
+ for (int i = 0; i < MODE_SLIDER_COUNT; i++) {
sliders[i]->add_theme_style_override("slider", style_box_flat);
}
@@ -2051,7 +2082,7 @@ void ColorPicker::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "edit_intensity"), "set_edit_intensity", "is_editing_intensity");
ADD_PROPERTY(PropertyInfo(Variant::INT, "color_mode", PROPERTY_HINT_ENUM, "RGB,HSV,LINEAR,OKHSL"), "set_color_mode", "get_color_mode");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "deferred_mode"), "set_deferred_mode", "is_deferred_mode");
- 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");
+ 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");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "can_add_swatches"), "set_can_add_swatches", "are_swatches_enabled");
ADD_GROUP("Customization", "");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sampler_visible"), "set_sampler_visible", "is_sampler_visible");
@@ -2077,6 +2108,8 @@ void ColorPicker::_bind_methods() {
BIND_ENUM_CONSTANT(SHAPE_VHS_CIRCLE);
BIND_ENUM_CONSTANT(SHAPE_OKHSL_CIRCLE);
BIND_ENUM_CONSTANT(SHAPE_NONE);
+ BIND_ENUM_CONSTANT(SHAPE_OK_HS_RECTANGLE);
+ BIND_ENUM_CONSTANT(SHAPE_OK_HL_RECTANGLE);
BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_CONSTANT, ColorPicker, content_margin, "margin");
BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, ColorPicker, label_width);
@@ -2158,16 +2191,18 @@ ColorPicker::ColorPicker() {
add_shape(memnew(ColorPickerShapeWheel(this)));
add_shape(memnew(ColorPickerShapeVHSCircle(this)));
add_shape(memnew(ColorPickerShapeOKHSLCircle(this)));
+ add_shape(memnew(ColorPickerShapeOKHSRectangle(this)));
+ add_shape(memnew(ColorPickerShapeOKHLRectangle(this)));
shape_popup = btn_shape->get_popup();
{
int i = 0;
for (const ColorPickerShape *shape : shapes) {
- shape_popup->add_radio_check_item(shape->get_name(), i);
+ shape_popup->add_radio_check_item(shape->get_name(), index_to_shape(i));
i++;
}
}
- shape_popup->set_item_checked(current_shape, true);
+ shape_popup->set_item_checked(get_current_shape_index(), true);
shape_popup->connect(SceneStringName(id_pressed), callable_mp(this, &ColorPicker::set_picker_shape));
shape_popup->connect("about_to_popup", callable_mp(this, &ColorPicker::_block_input_on_popup_show));
shape_popup->connect(SNAME("popup_hide"), callable_mp(this, &ColorPicker::_enable_input_on_popup_hide));
diff --git a/scene/gui/color_picker.h b/scene/gui/color_picker.h
index 9a1f212abe..26045f73db 100644
--- a/scene/gui/color_picker.h
+++ b/scene/gui/color_picker.h
@@ -88,6 +88,8 @@ class ColorPicker : public VBoxContainer {
friend class ColorPickerShapeCircle;
friend class ColorPickerShapeVHSCircle;
friend class ColorPickerShapeOKHSLCircle;
+ friend class ColorPickerShapeOKHSRectangle;
+ friend class ColorPickerShapeOKHLRectangle;
friend class ColorModeRGB;
friend class ColorModeHSV;
@@ -113,19 +115,49 @@ public:
SHAPE_VHS_CIRCLE,
SHAPE_OKHSL_CIRCLE,
SHAPE_NONE,
+ SHAPE_OK_HS_RECTANGLE,
+ SHAPE_OK_HL_RECTANGLE,
SHAPE_MAX
};
- static const int SLIDER_COUNT = 3;
+private:
+ // Ideally, `SHAPE_NONE` should be -1 so that we don't need to convert shape type to index.
+ // In order to avoid breaking compatibility, we have to use these methods for conversion.
+ inline int get_current_shape_index() {
+ return shape_to_index(current_shape);
+ }
+
+ static inline int shape_to_index(PickerShapeType p_shape) {
+ if (p_shape == SHAPE_NONE) {
+ return -1;
+ }
+ if (p_shape > SHAPE_NONE) {
+ return p_shape - 1;
+ }
+ return p_shape;
+ }
+
+ static inline PickerShapeType index_to_shape(int p_index) {
+ if (p_index == -1) {
+ return SHAPE_NONE;
+ }
+ if (p_index >= SHAPE_NONE) {
+ return (PickerShapeType)(p_index + 1);
+ }
+ return (PickerShapeType)p_index;
+ }
+
+public:
+ static const int MODE_SLIDER_COUNT = 3;
+
enum SLIDER_EXTRA {
- SLIDER_INTENSITY = 3,
+ SLIDER_INTENSITY = MODE_SLIDER_COUNT,
SLIDER_ALPHA,
SLIDER_MAX
};
-private:
enum class MenuOption {
MENU_SAVE,
MENU_SAVE_AS,
@@ -134,9 +166,12 @@ private:
MENU_CLEAR,
};
+private:
static inline Ref wheel_shader;
static inline Ref circle_shader;
static inline Ref circle_ok_color_shader;
+ static inline Ref rectangle_ok_color_hs_shader;
+ static inline Ref rectangle_ok_color_hl_shader;
static inline List preset_cache;
static inline List recent_preset_cache;
@@ -144,7 +179,7 @@ private:
Object *editor_settings = nullptr;
#endif
- int current_slider_count = SLIDER_COUNT;
+ int current_slider_count = MODE_SLIDER_COUNT;
const float DEFAULT_GAMEPAD_EVENT_DELAY_MS = 1.0 / 2;
const float GAMEPAD_EVENT_REPEAT_RATE_MS = 1.0 / 30;
@@ -394,6 +429,7 @@ public:
void _quick_open_palette_file_selected(const String &p_path);
#endif
+ GridContainer *get_slider_container();
HSlider *get_slider(int idx);
Vector get_active_slider_values();
diff --git a/scene/gui/color_picker_shape.cpp b/scene/gui/color_picker_shape.cpp
index 23aebdc107..ce9de12a29 100644
--- a/scene/gui/color_picker_shape.cpp
+++ b/scene/gui/color_picker_shape.cpp
@@ -131,7 +131,7 @@ void ColorPickerShape::draw_sv_square(Control *p_control, const Rect2 &p_square,
Color(1, 1, 1, 1),
Color(1, 1, 1, 1),
Color(0, 0, 0, 1),
- Color(0, 0, 0, 1)
+ Color(0, 0, 0, 1),
};
p_control->draw_polygon(points, colors);
@@ -139,7 +139,7 @@ void ColorPickerShape::draw_sv_square(Control *p_control, const Rect2 &p_square,
Color(color1, 0),
Color(color1, 1),
Color(color2, 1),
- Color(color2, 0)
+ Color(color2, 0),
};
p_control->draw_polygon(points, colors);
@@ -356,6 +356,220 @@ void ColorPickerShapeRectangle::grab_focus() {
hue_slider->grab_focus();
}
+void ColorPickerShapeOKHSRectangle::_initialize_controls() {
+ rectangle_margin = memnew(MarginContainer);
+ color_picker->shape_container->add_child(rectangle_margin);
+
+ Ref material;
+ material.instantiate();
+ material->set_shader(_get_shader());
+
+ square = memnew(Control);
+ rectangle_margin->add_child(square);
+ square->connect(SceneStringName(draw), callable_mp(this, &ColorPickerShapeOKHSRectangle::_square_draw));
+ square->set_material(material);
+
+ square_overlay = memnew(Control);
+ rectangle_margin->add_child(square_overlay);
+ square_overlay->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT);
+ square_overlay->connect(SceneStringName(gui_input), callable_mp(this, &ColorPickerShapeOKHSRectangle::_square_overlay_input));
+ square_overlay->connect(SceneStringName(draw), callable_mp(this, &ColorPickerShapeOKHSRectangle::_square_overlay_draw));
+ connect_shape_focus(square_overlay);
+
+ value_slider = memnew(Control);
+ color_picker->shape_container->add_child(value_slider);
+ value_slider->connect(SceneStringName(gui_input), callable_mp(this, &ColorPickerShapeOKHSRectangle::_value_slider_input));
+ value_slider->connect(SceneStringName(draw), callable_mp(this, &ColorPickerShapeOKHSRectangle::_value_slider_draw));
+ connect_shape_focus(value_slider);
+
+ controls.append(rectangle_margin);
+ controls.append(square);
+ controls.append(square_overlay);
+ controls.append(value_slider);
+}
+
+void ColorPickerShapeOKHSRectangle::update_theme() {
+ const ColorPicker::ThemeCache &theme_cache = color_picker->theme_cache;
+ rectangle_margin->set_custom_minimum_size(Size2(theme_cache.sv_width, theme_cache.sv_height));
+ value_slider->set_custom_minimum_size(Size2(theme_cache.h_width, 0));
+}
+
+void ColorPickerShapeOKHSRectangle::grab_focus() {
+ square_overlay->grab_focus();
+}
+
+void ColorPickerShapeOKHSRectangle::_update_cursor(const Vector2 &p_color_change_vector, bool p_is_echo) {
+ if (square_overlay->has_focus()) {
+ color_picker->ok_hsl_h = CLAMP(color_picker->ok_hsl_h + p_color_change_vector.x / 100.0, 0, 1);
+ color_picker->ok_hsl_s = CLAMP(color_picker->ok_hsl_s - p_color_change_vector.y / 100.0, 0, 1);
+ } else if (value_slider->has_focus()) {
+ color_picker->ok_hsl_l = CLAMP(color_picker->ok_hsl_l + p_color_change_vector.y * echo_multiplier / 360.0, 0, 1);
+ }
+}
+
+void ColorPickerShapeOKHSRectangle::_square_draw() {
+ Ref material = square->get_material();
+ material->set_shader_parameter(SNAME("ok_hsl_l"), color_picker->ok_hsl_l);
+ square->draw_rect(Rect2(Point2(), square->get_size()), Color(1, 1, 1));
+}
+
+void ColorPickerShapeOKHSRectangle::_square_overlay_input(const Ref &p_event) {
+ handle_cursor_editing(p_event, square_overlay);
+
+ Vector2 event_position;
+ if (!can_handle(p_event, event_position)) {
+ return;
+ }
+ event_position = (event_position / square_overlay->get_size()).clampf(0.0, 1.0);
+
+ color_picker->ok_hsl_h = event_position.x;
+ color_picker->ok_hsl_s = 1.0 - event_position.y;
+
+ apply_color();
+}
+
+void ColorPickerShapeOKHSRectangle::_square_overlay_draw() {
+ const Rect2 rect = Rect2(Vector2(), square_overlay->get_size());
+ const Vector2 end = rect.get_end();
+ Vector2 cursor_pos;
+ cursor_pos.x = CLAMP(rect.position.x + rect.size.x * color_picker->ok_hsl_h, rect.position.x, end.x);
+ cursor_pos.y = CLAMP(rect.position.y + rect.size.y * (1.0 - color_picker->ok_hsl_s), rect.position.y, end.y);
+
+ draw_focus_rect(square_overlay);
+ draw_cursor(square_overlay, cursor_pos);
+}
+
+void ColorPickerShapeOKHSRectangle::_value_slider_input(const Ref &p_event) {
+ handle_cursor_editing(p_event, value_slider);
+
+ Vector2 event_position;
+ if (!can_handle(p_event, event_position)) {
+ return;
+ }
+ color_picker->ok_hsl_l = 1 - CLAMP(event_position.y / value_slider->get_size().y, 0.0, 1.0);
+ apply_color();
+}
+
+void ColorPickerShapeOKHSRectangle::_value_slider_draw() {
+ const float ok_hsl_h = color_picker->ok_hsl_h;
+ const float ok_hsl_s = color_picker->ok_hsl_s;
+
+ const Vector2 size = value_slider->get_size();
+ PackedVector2Array points{
+ Vector2(size.x, 0),
+ Vector2(size.x, size.y * 0.5),
+ size,
+ Vector2(0, size.y),
+ Vector2(0, size.y * 0.5),
+ Vector2(),
+ };
+
+ Color color1 = Color::from_ok_hsl(ok_hsl_h, ok_hsl_s, 1);
+ Color color2 = Color::from_ok_hsl(ok_hsl_h, ok_hsl_s, 0.5);
+ Color color3 = Color::from_ok_hsl(ok_hsl_h, ok_hsl_s, 0);
+ PackedColorArray colors = {
+ color1,
+ color2,
+ color3,
+ color3,
+ color2,
+ color1,
+ };
+ value_slider->draw_polygon(points, colors);
+
+ draw_focus_rect(value_slider);
+
+ int y = size.y * (1 - CLAMP(color_picker->ok_hsl_l, 0, 1));
+ const Color color = Color::from_ok_hsl(ok_hsl_h, 1, color_picker->ok_hsl_l);
+ value_slider->draw_line(Vector2(0, y), Vector2(size.x, y), color.inverted());
+}
+
+void ColorPickerShapeOKHLRectangle::_update_cursor(const Vector2 &p_color_change_vector, bool p_is_echo) {
+ if (square_overlay->has_focus()) {
+ color_picker->ok_hsl_h = CLAMP(color_picker->ok_hsl_h + p_color_change_vector.x / 100.0, 0, 1);
+ color_picker->ok_hsl_l = CLAMP(color_picker->ok_hsl_l - p_color_change_vector.y / 100.0, 0, 1);
+ } else if (value_slider->has_focus()) {
+ color_picker->ok_hsl_s = CLAMP(color_picker->ok_hsl_s + p_color_change_vector.y * echo_multiplier / 360.0, 0, 1);
+ }
+}
+
+void ColorPickerShapeOKHLRectangle::_square_overlay_input(const Ref &p_event) {
+ handle_cursor_editing(p_event, square_overlay);
+
+ Vector2 event_position;
+ if (!can_handle(p_event, event_position)) {
+ return;
+ }
+ event_position = (event_position / square_overlay->get_size()).clampf(0.0, 1.0);
+
+ color_picker->ok_hsl_h = event_position.x;
+ color_picker->ok_hsl_l = 1.0 - event_position.y;
+
+ apply_color();
+}
+
+void ColorPickerShapeOKHLRectangle::_square_overlay_draw() {
+ const Rect2 rect = Rect2(Vector2(), square_overlay->get_size());
+ const Vector2 end = rect.get_end();
+ Vector2 cursor_pos;
+ cursor_pos.x = CLAMP(rect.position.x + rect.size.x * color_picker->ok_hsl_h, rect.position.x, end.x);
+ cursor_pos.y = CLAMP(rect.position.y + rect.size.y * (1.0 - color_picker->ok_hsl_l), rect.position.y, end.y);
+
+ draw_focus_rect(square_overlay);
+ draw_cursor(square_overlay, cursor_pos);
+}
+
+void ColorPickerShapeOKHLRectangle::_square_draw() {
+ Ref material = square->get_material();
+ material->set_shader_parameter(SNAME("ok_hsl_s"), color_picker->ok_hsl_s);
+ square->draw_rect(Rect2(Point2(), square->get_size()), Color(1, 1, 1));
+}
+
+void ColorPickerShapeOKHLRectangle::_value_slider_input(const Ref &p_event) {
+ handle_cursor_editing(p_event, value_slider);
+
+ Vector2 event_position;
+ if (!can_handle(p_event, event_position)) {
+ return;
+ }
+ color_picker->ok_hsl_s = 1 - CLAMP(event_position.y / value_slider->get_size().y, 0.0, 1.0);
+ apply_color();
+}
+
+void ColorPickerShapeOKHLRectangle::_value_slider_draw() {
+ const float ok_hsl_h = color_picker->ok_hsl_h;
+ const float ok_hsl_l = color_picker->ok_hsl_l;
+
+ const Vector2 size = value_slider->get_size();
+ PackedVector2Array points{
+ Vector2(size.x, 0),
+ Vector2(size.x, size.y * 0.5),
+ size,
+ Vector2(0, size.y),
+ Vector2(0, size.y * 0.5),
+ Vector2(),
+ };
+
+ Color color1 = Color::from_ok_hsl(ok_hsl_h, 1, ok_hsl_l);
+ Color color2 = Color::from_ok_hsl(ok_hsl_h, 0.5, ok_hsl_l);
+ Color color3 = Color::from_ok_hsl(ok_hsl_h, 0, ok_hsl_l);
+ PackedColorArray colors = {
+ color1,
+ color2,
+ color3,
+ color3,
+ color2,
+ color1,
+ };
+ value_slider->draw_polygon(points, colors);
+
+ draw_focus_rect(value_slider);
+
+ int y = size.y * (1 - CLAMP(color_picker->ok_hsl_s, 0, 1));
+ const Color color = Color::from_ok_hsl(ok_hsl_h, 1, ok_hsl_l);
+ value_slider->draw_line(Vector2(0, y), Vector2(size.x, y), color.inverted());
+}
+
float ColorPickerShapeWheel::_get_h_on_wheel(const Vector2 &p_color_change_vector) {
int h_change = get_edge_h_change(p_color_change_vector);
@@ -645,7 +859,7 @@ void ColorPickerShapeVHSCircle::_value_slider_draw() {
Vector2(),
Vector2(size.x, 0),
size,
- Vector2(0, size.y)
+ Vector2(0, size.y),
};
Color color = Color::from_hsv(color_picker->h, color_picker->s, 1);
@@ -653,7 +867,7 @@ void ColorPickerShapeVHSCircle::_value_slider_draw() {
color,
color,
Color(),
- Color()
+ Color(),
};
value_slider->draw_polygon(points, colors);
@@ -736,7 +950,7 @@ void ColorPickerShapeOKHSLCircle::_value_slider_draw() {
size,
Vector2(0, size.y),
Vector2(0, size.y * 0.5),
- Vector2()
+ Vector2(),
};
Color color1 = Color::from_ok_hsl(ok_hsl_h, ok_hsl_s, 1);
@@ -755,7 +969,7 @@ void ColorPickerShapeOKHSLCircle::_value_slider_draw() {
draw_focus_rect(value_slider);
int y = size.y * (1 - CLAMP(ok_hsl_l, 0, 1));
- value_slider->draw_line(Vector2(0, y), Vector2(size.x, y), Color::from_hsv(ok_hsl_h, 1, ok_hsl_l).inverted());
+ value_slider->draw_line(Vector2(0, y), Vector2(size.x, y), Color::from_ok_hsl(ok_hsl_h, 1, ok_hsl_l).inverted());
}
void ColorPickerShapeOKHSLCircle::_update_cursor(const Vector2 &p_color_change_vector, bool p_is_echo) {
diff --git a/scene/gui/color_picker_shape.h b/scene/gui/color_picker_shape.h
index 6f8ac6a5dd..27418fb12c 100644
--- a/scene/gui/color_picker_shape.h
+++ b/scene/gui/color_picker_shape.h
@@ -104,6 +104,60 @@ public:
ColorPickerShape(p_color_picker) {}
};
+class ColorPickerShapeOKHSRectangle : public ColorPickerShape {
+ GDCLASS(ColorPickerShapeOKHSRectangle, ColorPickerShape);
+
+ MarginContainer *rectangle_margin = nullptr;
+
+protected:
+ Control *square = nullptr;
+ Control *square_overlay = nullptr;
+ Control *value_slider = nullptr;
+ virtual Ref _get_shader() const { return ColorPicker::rectangle_ok_color_hs_shader; }
+ virtual void _initialize_controls() override;
+ virtual void _update_cursor(const Vector2 &p_color_change_vector, bool p_is_echo) override;
+
+ virtual void _square_draw();
+ virtual void _square_overlay_input(const Ref &p_event);
+ virtual void _square_overlay_draw();
+
+ virtual void _value_slider_input(const Ref &p_event);
+ virtual void _value_slider_draw();
+
+public:
+ virtual String get_name() const override { return ETR("OK HS Rectangle"); }
+ virtual bool is_ok_hsl() const override { return true; }
+ virtual Ref get_icon() const override { return color_picker->theme_cache.shape_rect; }
+ virtual void update_theme() override;
+ virtual void grab_focus() override;
+
+ ColorPickerShapeOKHSRectangle(ColorPicker *p_color_picker) :
+ ColorPickerShape(p_color_picker) {}
+};
+
+class ColorPickerShapeOKHLRectangle : public ColorPickerShapeOKHSRectangle {
+ GDCLASS(ColorPickerShapeOKHLRectangle, ColorPickerShapeOKHSRectangle);
+
+protected:
+ virtual Ref _get_shader() const override { return ColorPicker::rectangle_ok_color_hl_shader; }
+ virtual void _update_cursor(const Vector2 &p_color_change_vector, bool p_is_echo) override;
+
+ virtual void _square_draw() override;
+ virtual void _square_overlay_input(const Ref &p_event) override;
+ virtual void _square_overlay_draw() override;
+
+ virtual void _value_slider_input(const Ref &p_event) override;
+ virtual void _value_slider_draw() override;
+
+public:
+ virtual String get_name() const override { return ETR("OK HL Rectangle"); }
+ virtual bool is_ok_hsl() const override { return true; }
+ virtual Ref get_icon() const override { return color_picker->theme_cache.shape_rect; }
+
+ ColorPickerShapeOKHLRectangle(ColorPicker *p_color_picker) :
+ ColorPickerShapeOKHSRectangle(p_color_picker) {}
+};
+
class ColorPickerShapeWheel : public ColorPickerShape {
GDCLASS(ColorPickerShapeWheel, ColorPickerShape);