1
0
mirror of https://github.com/godotengine/godot.git synced 2025-11-04 12:00:25 +00:00

ColorPicker: Add okhsl HS and HL rectangular picker shapes

This commit is contained in:
LuoZhihao
2025-06-07 22:30:40 +08:00
parent 26df04377e
commit 7b4c95e6d8
7 changed files with 383 additions and 37 deletions

View File

@@ -144,6 +144,12 @@
<constant name="SHAPE_NONE" value="4" enum="PickerShapeType">
The color space shape and the shape select button are hidden. Can't be selected from the shapes popup.
</constant>
<constant name="SHAPE_OK_HS_RECTANGLE" value="5" enum="PickerShapeType">
OKHSL Color Model rectangle with constant lightness.
</constant>
<constant name="SHAPE_OK_HL_RECTANGLE" value="6" enum="PickerShapeType">
OKHSL Color Model rectangle with constant saturation.
</constant>
</constants>
<theme_items>
<theme_item name="focused_not_editing_cursor_color" data_type="color" type="Color" default="Color(1, 1, 1, 0.275)">

View File

@@ -569,7 +569,7 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> 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

View File

@@ -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);

View File

@@ -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<float> 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<StyleBoxEmpty> 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));

View File

@@ -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<Shader> wheel_shader;
static inline Ref<Shader> circle_shader;
static inline Ref<Shader> circle_ok_color_shader;
static inline Ref<Shader> rectangle_ok_color_hs_shader;
static inline Ref<Shader> rectangle_ok_color_hl_shader;
static inline List<Color> preset_cache;
static inline List<Color> 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<float> get_active_slider_values();

View File

@@ -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<ShaderMaterial> 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<ShaderMaterial> 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<InputEvent> &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<InputEvent> &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<InputEvent> &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<ShaderMaterial> 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<InputEvent> &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) {

View File

@@ -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<Shader> _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<InputEvent> &p_event);
virtual void _square_overlay_draw();
virtual void _value_slider_input(const Ref<InputEvent> &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<Texture2D> 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<Shader> _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<InputEvent> &p_event) override;
virtual void _square_overlay_draw() override;
virtual void _value_slider_input(const Ref<InputEvent> &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<Texture2D> 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);