diff options
author | RĂ©mi Verschelde <remi@verschelde.fr> | 2022-07-08 09:06:47 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-07-08 09:06:47 +0200 |
commit | 7d3ff927dea31b75cf9801bdcbcf0e0cc8e975b0 (patch) | |
tree | 83f864e2223fa89dd2e4c49dbf7dbea2f8d095f7 | |
parent | 2b6dadd46b9a2bb68c6814989360e02f064a47b1 (diff) | |
parent | 0011d93c810148e2c5190a7355fb6f788d073db7 (diff) |
Merge pull request #62075 from Vitika9/gsoc-colorpicker
-rw-r--r-- | doc/classes/ColorPicker.xml | 25 | ||||
-rw-r--r-- | editor/editor_node.cpp | 2 | ||||
-rw-r--r-- | editor/editor_properties.cpp | 7 | ||||
-rw-r--r-- | editor/plugins/script_text_editor.cpp | 6 | ||||
-rw-r--r-- | editor/property_editor.cpp | 6 | ||||
-rw-r--r-- | scene/gui/color_mode.cpp | 330 | ||||
-rw-r--r-- | scene/gui/color_mode.h | 143 | ||||
-rw-r--r-- | scene/gui/color_picker.cpp | 505 | ||||
-rw-r--r-- | scene/gui/color_picker.h | 93 |
9 files changed, 788 insertions, 329 deletions
diff --git a/doc/classes/ColorPicker.xml b/doc/classes/ColorPicker.xml index 7c9c4ed4d6..cc9c5877c5 100644 --- a/doc/classes/ColorPicker.xml +++ b/doc/classes/ColorPicker.xml @@ -37,16 +37,15 @@ <member name="color" type="Color" setter="set_pick_color" getter="get_pick_color" default="Color(1, 1, 1, 1)"> The currently selected color. </member> + <member name="color_mode" type="int" setter="set_color_mode" getter="get_color_mode" enum="ColorPicker.ColorModeType" default="0"> + The currently selected color mode. See [enum ColorModeType]. + </member> <member name="deferred_mode" type="bool" setter="set_deferred_mode" getter="is_deferred_mode" default="false"> If [code]true[/code], the color will apply only after the user releases the mouse button, otherwise it will apply immediately even in mouse motion event (which can cause performance issues). </member> <member name="edit_alpha" type="bool" setter="set_edit_alpha" getter="is_editing_alpha" default="true"> If [code]true[/code], shows an alpha channel slider (opacity). </member> - <member name="hsv_mode" type="bool" setter="set_hsv_mode" getter="is_hsv_mode" default="false"> - If [code]true[/code], allows editing the color with Hue/Saturation/Value sliders. - [b]Note:[/b] Cannot be enabled if raw mode is on. - </member> <member name="picker_shape" type="int" setter="set_picker_shape" getter="get_picker_shape" enum="ColorPicker.PickerShapeType" default="0"> The shape of the color space view. See [enum PickerShapeType]. </member> @@ -56,10 +55,6 @@ <member name="presets_visible" type="bool" setter="set_presets_visible" getter="are_presets_visible" default="true"> If [code]true[/code], saved color presets are visible. </member> - <member name="raw_mode" type="bool" setter="set_raw_mode" getter="is_raw_mode" default="false"> - If [code]true[/code], allows the color R, G, B component values to go beyond 1.0, which can be used for certain special operations that require it (like tinting without darkening or rendering sprites in HDR). - [b]Note:[/b] Cannot be enabled if HSV mode is on. - </member> </members> <signals> <signal name="color_changed"> @@ -82,6 +77,20 @@ </signal> </signals> <constants> + <constant name="MODE_RGB" value="0" enum="ColorModeType"> + Allows editing the color with Red/Green/Blue sliders. + </constant> + <constant name="MODE_HSV" value="1" enum="ColorModeType"> + Allows editing the color with Hue/Saturation/Value sliders. + </constant> + <constant name="MODE_RAW" value="2" enum="ColorModeType"> + Allows the color R, G, B component values to go beyond 1.0, which can be used for certain special operations that require it (like tinting without darkening or rendering sprites in HDR). + </constant> + <constant name="MODE_OKHSL" value="3" enum="ColorModeType"> + Allows editing the color with Hue/Saturation/Lightness sliders. + OKHSL is a new color space similar to HSL but that better match perception by leveraging the Oklab color space which is designed to be simple to use, while doing a good job at predicting perceived lightness, chroma and hue. + [url=https://bottosson.github.io/posts/colorpicker/]Okhsv and Okhsl color spaces[/url] + </constant> <constant name="SHAPE_HSV_RECTANGLE" value="0" enum="PickerShapeType"> HSV Color Model rectangle color space. </constant> diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index eafbf11df0..6243ebc852 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -6136,7 +6136,7 @@ EditorNode::EditorNode() { EDITOR_DEF("interface/inspector/open_resources_in_current_inspector", true); EDITOR_DEF("interface/inspector/resources_to_open_in_new_inspector", "Script,MeshLibrary"); EDITOR_DEF("interface/inspector/default_color_picker_mode", 0); - EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::INT, "interface/inspector/default_color_picker_mode", PROPERTY_HINT_ENUM, "RGB,HSV,RAW", PROPERTY_USAGE_DEFAULT)); + EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::INT, "interface/inspector/default_color_picker_mode", PROPERTY_HINT_ENUM, "RGB,HSV,RAW,OKHSL", PROPERTY_USAGE_DEFAULT)); EDITOR_DEF("interface/inspector/default_color_picker_shape", (int32_t)ColorPicker::SHAPE_OKHSL_CIRCLE); EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::INT, "interface/inspector/default_color_picker_shape", PROPERTY_HINT_ENUM, "HSV Rectangle,HSV Rectangle Wheel,VHS Circle,OKHSL Circle", PROPERTY_USAGE_DEFAULT)); diff --git a/editor/editor_properties.cpp b/editor/editor_properties.cpp index 6a035225e5..d06d22ae5b 100644 --- a/editor/editor_properties.cpp +++ b/editor/editor_properties.cpp @@ -3010,12 +3010,7 @@ void EditorPropertyColor::_popup_closed() { void EditorPropertyColor::_picker_created() { // get default color picker mode from editor settings int default_color_mode = EDITOR_GET("interface/inspector/default_color_picker_mode"); - if (default_color_mode == 1) { - picker->get_picker()->set_hsv_mode(true); - } else if (default_color_mode == 2) { - picker->get_picker()->set_raw_mode(true); - } - + picker->get_picker()->set_color_mode((ColorPicker::ColorModeType)default_color_mode); int picker_shape = EDITOR_GET("interface/inspector/default_color_picker_shape"); picker->get_picker()->set_picker_shape((ColorPicker::PickerShapeType)picker_shape); } diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp index 7c3520c39d..66cd85a26a 100644 --- a/editor/plugins/script_text_editor.cpp +++ b/editor/plugins/script_text_editor.cpp @@ -1865,11 +1865,7 @@ void ScriptTextEditor::_enable_code_editor() { // get default color picker mode from editor settings int default_color_mode = EDITOR_GET("interface/inspector/default_color_picker_mode"); - if (default_color_mode == 1) { - color_picker->set_hsv_mode(true); - } else if (default_color_mode == 2) { - color_picker->set_raw_mode(true); - } + color_picker->set_color_mode((ColorPicker::ColorModeType)default_color_mode); int picker_shape = EDITOR_GET("interface/inspector/default_color_picker_shape"); color_picker->set_picker_shape((ColorPicker::PickerShapeType)picker_shape); diff --git a/editor/property_editor.cpp b/editor/property_editor.cpp index d936e821df..9f13a9d520 100644 --- a/editor/property_editor.cpp +++ b/editor/property_editor.cpp @@ -831,11 +831,7 @@ bool CustomPropertyEditor::edit(Object *p_owner, const String &p_name, Variant:: // get default color picker mode from editor settings int default_color_mode = EDITOR_GET("interface/inspector/default_color_picker_mode"); - if (default_color_mode == 1) { - color_picker->set_hsv_mode(true); - } else if (default_color_mode == 2) { - color_picker->set_raw_mode(true); - } + color_picker->set_color_mode((ColorPicker::ColorModeType)default_color_mode); int picker_shape = EDITOR_GET("interface/inspector/default_color_picker_shape"); color_picker->set_picker_shape((ColorPicker::PickerShapeType)picker_shape); diff --git a/scene/gui/color_mode.cpp b/scene/gui/color_mode.cpp new file mode 100644 index 0000000000..af78d67e5a --- /dev/null +++ b/scene/gui/color_mode.cpp @@ -0,0 +1,330 @@ +/*************************************************************************/ +/* color_mode.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "color_mode.h" + +#include "core/math/color.h" +#include "scene/gui/slider.h" +#include "thirdparty/misc/ok_color.h" + +ColorMode::ColorMode(ColorPicker *p_color_picker) { + color_picker = p_color_picker; +} + +String ColorModeRGB::get_slider_label(int idx) const { + ERR_FAIL_INDEX_V_MSG(idx, 3, String(), "Couldn't get slider label."); + return labels[idx]; +} + +float ColorModeRGB::get_slider_max(int idx) const { + ERR_FAIL_INDEX_V_MSG(idx, 4, 0, "Couldn't get slider max value."); + Color color = color_picker->get_pick_color(); + return next_power_of_2(MAX(255, color.components[idx] * 255.0)) - 1; +} + +float ColorModeRGB::get_slider_value(int idx) const { + ERR_FAIL_INDEX_V_MSG(idx, 4, 0, "Couldn't get slider value."); + return color_picker->get_pick_color().components[idx] * 255; +} + +Color ColorModeRGB::get_color() const { + Vector<float> values = color_picker->get_active_slider_values(); + Color color; + for (int i = 0; i < 4; i++) { + color.components[i] = values[i] / 255.0; + } + return color; +} + +void ColorModeRGB::slider_draw(int p_which) { + Vector<Vector2> pos; + pos.resize(4); + Vector<Color> col; + col.resize(4); + HSlider *slider = color_picker->get_slider(p_which); + Size2 size = slider->get_size(); + Color left_color; + Color right_color; + Color color = color_picker->get_pick_color(); + const real_t margin = 4 * color_picker->get_theme_default_base_scale(); + + if (p_which == ColorPicker::SLIDER_COUNT) { + slider->draw_texture_rect(color_picker->get_theme_icon(SNAME("sample_bg"), SNAME("ColorPicker")), Rect2(Point2(0, margin), Size2(size.x, margin)), true); + + left_color = color; + left_color.a = 0; + right_color = color; + right_color.a = 1; + } else { + left_color = Color( + p_which == 0 ? 0 : color.r, + p_which == 1 ? 0 : color.g, + p_which == 2 ? 0 : color.b); + right_color = Color( + p_which == 0 ? 1 : color.r, + p_which == 1 ? 1 : color.g, + p_which == 2 ? 1 : color.b); + } + + col.set(0, left_color); + col.set(1, right_color); + col.set(2, right_color); + col.set(3, left_color); + pos.set(0, Vector2(0, margin)); + pos.set(1, Vector2(size.x, margin)); + pos.set(2, Vector2(size.x, margin * 2)); + pos.set(3, Vector2(0, margin * 2)); + + slider->draw_polygon(pos, col); +} + +String ColorModeHSV::get_slider_label(int idx) const { + ERR_FAIL_INDEX_V_MSG(idx, 3, String(), "Couldn't get slider label."); + return labels[idx]; +} + +float ColorModeHSV::get_slider_max(int idx) const { + ERR_FAIL_INDEX_V_MSG(idx, 4, 0, "Couldn't get slider max value."); + return slider_max[idx]; +} + +float ColorModeHSV::get_slider_value(int idx) const { + switch (idx) { + case 0: + return color_picker->get_pick_color().get_h() * 360.0; + case 1: + return color_picker->get_pick_color().get_s() * 100.0; + case 2: + return color_picker->get_pick_color().get_v() * 100.0; + case 3: + return Math::round(color_picker->get_pick_color().components[3] * 255.0); + default: + ERR_FAIL_V_MSG(0, "Couldn't get slider value."); + } +} + +Color ColorModeHSV::get_color() const { + Vector<float> values = color_picker->get_active_slider_values(); + Color color; + color.set_hsv(values[0] / 360.0, values[1] / 100.0, values[2] / 100.0, values[3] / 255.0); + return color; +} + +void ColorModeHSV::slider_draw(int p_which) { + Vector<Vector2> pos; + pos.resize(4); + Vector<Color> col; + col.resize(4); + HSlider *slider = color_picker->get_slider(p_which); + Size2 size = slider->get_size(); + Color left_color; + Color right_color; + Color color = color_picker->get_pick_color(); + const real_t margin = 4 * color_picker->get_theme_default_base_scale(); + + if (p_which == ColorPicker::SLIDER_COUNT) { + slider->draw_texture_rect(color_picker->get_theme_icon(SNAME("sample_bg"), SNAME("ColorPicker")), Rect2(Point2(0, margin), Size2(size.x, margin)), true); + + left_color = color; + left_color.a = 0; + right_color = color; + right_color.a = 1; + } else if (p_which == 0) { + Ref<Texture2D> hue = color_picker->get_theme_icon(SNAME("color_hue"), SNAME("ColorPicker")); + slider->draw_set_transform(Point2(), -Math_PI / 2, Size2(1.0, 1.0)); + slider->draw_texture_rect(hue, Rect2(Vector2(margin * -2, 0), Vector2(slider->get_size().x, margin)), false, Color(1, 1, 1), true); + return; + } else { + Color s_col; + Color v_col; + s_col.set_hsv(color.get_h(), 0, color.get_v()); + left_color = (p_which == 1) ? s_col : Color(0, 0, 0); + s_col.set_hsv(color.get_h(), 1, color.get_v()); + v_col.set_hsv(color.get_h(), color.get_s(), 1); + right_color = (p_which == 1) ? s_col : v_col; + } + col.set(0, left_color); + col.set(1, right_color); + col.set(2, right_color); + col.set(3, left_color); + pos.set(0, Vector2(0, margin)); + pos.set(1, Vector2(size.x, margin)); + pos.set(2, Vector2(size.x, margin * 2)); + pos.set(3, Vector2(0, margin * 2)); + + slider->draw_polygon(pos, col); +} + +String ColorModeRAW::get_slider_label(int idx) const { + ERR_FAIL_INDEX_V_MSG(idx, 3, String(), "Couldn't get slider label."); + return labels[idx]; +} + +float ColorModeRAW::get_slider_max(int idx) const { + ERR_FAIL_INDEX_V_MSG(idx, 4, 0, "Couldn't get slider max value."); + return slider_max[idx]; +} + +float ColorModeRAW::get_slider_value(int idx) const { + ERR_FAIL_INDEX_V_MSG(idx, 4, 0, "Couldn't get slider value."); + return color_picker->get_pick_color().components[idx]; +} + +Color ColorModeRAW::get_color() const { + Vector<float> values = color_picker->get_active_slider_values(); + Color color; + for (int i = 0; i < 4; i++) { + color.components[i] = values[i]; + } + return color; +} + +void ColorModeRAW::slider_draw(int p_which) { + Vector<Vector2> pos; + pos.resize(4); + Vector<Color> col; + col.resize(4); + HSlider *slider = color_picker->get_slider(p_which); + Size2 size = slider->get_size(); + Color left_color; + Color right_color; + Color color = color_picker->get_pick_color(); + const real_t margin = 4 * color_picker->get_theme_default_base_scale(); + + if (p_which == ColorPicker::SLIDER_COUNT) { + slider->draw_texture_rect(color_picker->get_theme_icon(SNAME("sample_bg"), SNAME("ColorPicker")), Rect2(Point2(0, margin), Size2(size.x, margin)), true); + + left_color = color; + left_color.a = 0; + right_color = color; + right_color.a = 1; + + col.set(0, left_color); + col.set(1, right_color); + col.set(2, right_color); + col.set(3, left_color); + pos.set(0, Vector2(0, margin)); + pos.set(1, Vector2(size.x, margin)); + pos.set(2, Vector2(size.x, margin * 2)); + pos.set(3, Vector2(0, margin * 2)); + + slider->draw_polygon(pos, col); + } +} + +bool ColorModeRAW::apply_theme() const { + for (int i = 0; i < 4; i++) { + HSlider *slider = color_picker->get_slider(i); + slider->remove_theme_icon_override("grabber"); + slider->remove_theme_icon_override("grabber_highlight"); + slider->remove_theme_style_override("slider"); + slider->remove_theme_style_override("grabber_area"); + slider->remove_theme_style_override("grabber_area_highlight"); + } + + return true; +} + +String ColorModeOKHSL::get_slider_label(int idx) const { + ERR_FAIL_INDEX_V_MSG(idx, 3, String(), "Couldn't get slider label."); + return labels[idx]; +} + +float ColorModeOKHSL::get_slider_max(int idx) const { + ERR_FAIL_INDEX_V_MSG(idx, 4, 0, "Couldn't get slider max value."); + return slider_max[idx]; +} + +float ColorModeOKHSL::get_slider_value(int idx) const { + switch (idx) { + case 0: + return color_picker->get_pick_color().get_ok_hsl_h() * 360.0; + case 1: + return color_picker->get_pick_color().get_ok_hsl_s() * 100.0; + case 2: + return color_picker->get_pick_color().get_ok_hsl_l() * 100.0; + case 3: + return Math::round(color_picker->get_pick_color().components[3] * 255.0); + default: + ERR_FAIL_V_MSG(0, "Couldn't get slider value."); + } +} + +Color ColorModeOKHSL::get_color() const { + Vector<float> values = color_picker->get_active_slider_values(); + Color color; + color.set_ok_hsl(values[0] / 360.0, values[1] / 100.0, values[2] / 100.0, values[3] / 255.0); + return color; +} + +void ColorModeOKHSL::slider_draw(int p_which) { + Vector<Vector2> pos; + pos.resize(4); + Vector<Color> col; + col.resize(4); + HSlider *slider = color_picker->get_slider(p_which); + Size2 size = slider->get_size(); + Color left_color; + Color right_color; + Color color = color_picker->get_pick_color(); + const real_t margin = 4 * color_picker->get_theme_default_base_scale(); + + if (p_which == ColorPicker::SLIDER_COUNT) { + slider->draw_texture_rect(color_picker->get_theme_icon(SNAME("sample_bg"), SNAME("ColorPicker")), Rect2(Point2(0, margin), Size2(size.x, margin)), true); + + left_color = color; + left_color.a = 0; + right_color = color; + right_color.a = 1; + } else if (p_which == 0) { + Ref<Texture2D> hue = color_picker->get_theme_icon(SNAME("color_hue"), SNAME("ColorPicker")); + slider->draw_set_transform(Point2(), -Math_PI / 2, Size2(1.0, 1.0)); + slider->draw_texture_rect(hue, Rect2(Vector2(margin * -2, 0), Vector2(slider->get_size().x, margin)), false, Color(1, 1, 1), true); + return; + } else { + Color s_col; + Color v_col; + s_col.set_ok_hsl(color.get_h(), 0, color.get_v()); + left_color = (p_which == 1) ? s_col : Color(0, 0, 0); + s_col.set_ok_hsl(color.get_h(), 1, color.get_v()); + v_col.set_ok_hsl(color.get_h(), color.get_s(), 1); + right_color = (p_which == 1) ? s_col : v_col; + } + col.set(0, left_color); + col.set(1, right_color); + col.set(2, right_color); + col.set(3, left_color); + pos.set(0, Vector2(0, margin)); + pos.set(1, Vector2(size.x, margin)); + pos.set(2, Vector2(size.x, margin * 2)); + pos.set(3, Vector2(0, margin * 2)); + + slider->draw_polygon(pos, col); +} diff --git a/scene/gui/color_mode.h b/scene/gui/color_mode.h new file mode 100644 index 0000000000..8a19699c40 --- /dev/null +++ b/scene/gui/color_mode.h @@ -0,0 +1,143 @@ +/*************************************************************************/ +/* color_mode.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef COLOR_MODE_H +#define COLOR_MODE_H + +#include "scene/gui/color_picker.h" + +struct Color; + +class ColorMode { +public: + ColorPicker *color_picker = nullptr; + + virtual String get_name() const = 0; + + virtual int get_slider_count() const { return 3; }; + virtual float get_slider_step() const = 0; + virtual String get_slider_label(int idx) const = 0; + virtual float get_slider_max(int idx) const = 0; + virtual float get_slider_value(int idx) const = 0; + + virtual Color get_color() const = 0; + + virtual void slider_draw(int p_which) = 0; + virtual bool apply_theme() const { return false; } + virtual ColorPicker::PickerShapeType get_shape_override() const { return ColorPicker::SHAPE_MAX; } + + ColorMode(ColorPicker *p_color_picker); + virtual ~ColorMode(){}; +}; + +class ColorModeHSV : public ColorMode { +public: + String labels[3] = { "H", "S", "V" }; + float slider_max[4] = { 359, 100, 100, 255 }; + + virtual String get_name() const override { return "HSV"; } + + virtual float get_slider_step() const override { return 1.0; } + virtual String get_slider_label(int idx) const override; + virtual float get_slider_max(int idx) const override; + virtual float get_slider_value(int idx) const override; + + virtual Color get_color() const override; + + virtual void slider_draw(int p_which) override; + + ColorModeHSV(ColorPicker *p_color_picker) : + ColorMode(p_color_picker){}; +}; + +class ColorModeRGB : public ColorMode { +public: + String labels[3] = { "R", "G", "B" }; + + virtual String get_name() const override { return "RGB"; } + + virtual float get_slider_step() const override { return 1; } + virtual String get_slider_label(int idx) const override; + virtual float get_slider_max(int idx) const override; + virtual float get_slider_value(int idx) const override; + + virtual Color get_color() const override; + + virtual void slider_draw(int p_which) override; + + ColorModeRGB(ColorPicker *p_color_picker) : + ColorMode(p_color_picker){}; +}; + +class ColorModeRAW : public ColorMode { +public: + String labels[3] = { "R", "G", "B" }; + float slider_max[4] = { 100, 100, 100, 1 }; + + virtual String get_name() const override { return "RAW"; } + + virtual float get_slider_step() const override { return 0.01; } + virtual String get_slider_label(int idx) const override; + virtual float get_slider_max(int idx) const override; + virtual float get_slider_value(int idx) const override; + + virtual Color get_color() const override; + + virtual void slider_draw(int p_which) override; + virtual bool apply_theme() const override; + + ColorModeRAW(ColorPicker *p_color_picker) : + ColorMode(p_color_picker){}; +}; + +class ColorModeOKHSL : public ColorMode { +public: + String labels[3] = { "H", "S", "L" }; + float slider_max[4] = { 359, 100, 100, 255 }; + + virtual String get_name() const override { return "OKHSL"; } + + virtual float get_slider_step() const override { return 1.0; } + virtual String get_slider_label(int idx) const override; + virtual float get_slider_max(int idx) const override; + virtual float get_slider_value(int idx) const override; + + virtual Color get_color() const override; + + virtual void slider_draw(int p_which) override; + virtual ColorPicker::PickerShapeType get_shape_override() const override { return ColorPicker::SHAPE_OKHSL_CIRCLE; } + + ColorModeOKHSL(ColorPicker *p_color_picker) : + ColorMode(p_color_picker){}; + + ~ColorModeOKHSL(){}; +}; + +#endif // COLOR_MODE_H diff --git a/scene/gui/color_picker.cpp b/scene/gui/color_picker.cpp index 28d645e8f6..492a81f933 100644 --- a/scene/gui/color_picker.cpp +++ b/scene/gui/color_picker.cpp @@ -34,7 +34,7 @@ #include "core/math/color.h" #include "core/os/keyboard.h" #include "core/os/os.h" -#include "scene/main/window.h" +#include "scene/gui/color_mode.h" #ifdef TOOLS_ENABLED #include "editor/editor_settings.h" @@ -75,10 +75,14 @@ void ColorPicker::_notification(int p_what) { wheel_edit->set_custom_minimum_size(Size2(get_theme_constant(SNAME("sv_width")), get_theme_constant(SNAME("sv_height")))); wheel_margin->add_theme_constant_override("margin_bottom", 8 * get_theme_default_base_scale()); - for (int i = 0; i < 4; i++) { + for (int i = 0; i < SLIDER_COUNT; i++) { labels[i]->set_custom_minimum_size(Size2(get_theme_constant(SNAME("label_width")), 0)); set_offset((Side)i, get_offset((Side)i) + get_theme_constant(SNAME("margin"))); } + alpha_label->set_custom_minimum_size(Size2(get_theme_constant(SNAME("label_width")), 0)); + set_offset((Side)0, get_offset((Side)0) + get_theme_constant(SNAME("margin"))); + + _reset_theme(); if (Engine::get_singleton()->is_editor_hint()) { // Adjust for the width of the "Script" icon. @@ -194,75 +198,38 @@ void ColorPicker::set_focus_on_line_edit() { } void ColorPicker::_update_controls() { - const char *rgb[3] = { "R", "G", "B" }; - const char *hsv[3] = { "H", "S", "V" }; - const char *hsl[3] = { "H", "S", "L" }; - if (hsv_mode_enabled && picker_type == SHAPE_OKHSL_CIRCLE) { - for (int i = 0; i < 3; i++) { - labels[i]->set_text(hsl[i]); - } - } else if (hsv_mode_enabled && picker_type != SHAPE_OKHSL_CIRCLE) { - for (int i = 0; i < 3; i++) { - labels[i]->set_text(hsv[i]); - } - } else { - for (int i = 0; i < 3; i++) { - labels[i]->set_text(rgb[i]); - } + int mode_sliders_count = modes[current_mode]->get_slider_count(); + + for (int i = current_slider_count; i < mode_sliders_count; i++) { + sliders[i]->show(); + labels[i]->show(); + values[i]->show(); } - if (picker_type == SHAPE_OKHSL_CIRCLE) { - btn_hsv->set_text(RTR("OKHSL")); - } else { - btn_hsv->set_text(RTR("HSV")); - } - if (hsv_mode_enabled) { - set_raw_mode(false); - set_hsv_mode(true); - btn_raw->set_disabled(true); - } else if (raw_mode_enabled) { - set_raw_mode(true); - set_hsv_mode(false); - btn_raw->set_disabled(false); - btn_hsv->set_disabled(true); - } else { - set_raw_mode(false); - set_hsv_mode(false); - btn_raw->set_disabled(false); - btn_hsv->set_disabled(false); - } - - if (raw_mode_enabled) { - for (int i = 0; i < 3; i++) { - scroll[i]->remove_theme_icon_override("grabber"); - scroll[i]->remove_theme_icon_override("grabber_highlight"); - scroll[i]->remove_theme_style_override("slider"); - scroll[i]->remove_theme_style_override("grabber_area"); - scroll[i]->remove_theme_style_override("grabber_area_highlight"); - } - } else { - Ref<StyleBoxEmpty> style_box_empty(memnew(StyleBoxEmpty)); - Ref<Texture2D> bar_arrow = get_theme_icon(SNAME("bar_arrow")); - - for (int i = 0; i < 4; i++) { - scroll[i]->add_theme_icon_override("grabber", bar_arrow); - scroll[i]->add_theme_icon_override("grabber_highlight", bar_arrow); - scroll[i]->add_theme_style_override("slider", style_box_empty); - scroll[i]->add_theme_style_override("grabber_area", style_box_empty); - scroll[i]->add_theme_style_override("grabber_area_highlight", style_box_empty); - } + for (int i = mode_sliders_count; i < current_slider_count; i++) { + sliders[i]->hide(); + labels[i]->hide(); + values[i]->hide(); } + current_slider_count = mode_sliders_count; + + for (int i = 0; i < current_slider_count; i++) { + labels[i]->set_text(modes[current_mode]->get_slider_label(i)); + } + alpha_label->set_text("A"); + + slider_theme_modified = modes[current_mode]->apply_theme(); if (edit_alpha) { - values[3]->show(); - scroll[3]->show(); - labels[3]->show(); + alpha_value->show(); + alpha_slider->show(); + alpha_label->show(); } else { - values[3]->hide(); - scroll[3]->hide(); - labels[3]->hide(); + alpha_value->hide(); + alpha_slider->hide(); + alpha_label->hide(); } - switch (picker_type) { + switch (_get_actual_shape()) { case SHAPE_HSV_RECTANGLE: wheel_edit->hide(); w_edit->show(); @@ -297,7 +264,7 @@ void ColorPicker::_update_controls() { void ColorPicker::_set_pick_color(const Color &p_color, bool p_update_sliders) { color = p_color; if (color != last_color) { - if (picker_type == SHAPE_OKHSL_CIRCLE) { + if (_get_actual_shape() == SHAPE_OKHSL_CIRCLE) { h = color.get_ok_hsl_h(); s = color.get_ok_hsl_s(); v = color.get_ok_hsl_l(); @@ -353,27 +320,93 @@ void ColorPicker::_value_changed(double) { return; } - if (hsv_mode_enabled) { - h = scroll[0]->get_value() / 360.0; - s = scroll[1]->get_value() / 100.0; - v = scroll[2]->get_value() / 100.0; - if (picker_type == SHAPE_OKHSL_CIRCLE) { - color.set_ok_hsl(h, s, v, Math::round(scroll[3]->get_value() / 255.0)); - } else { - color.set_hsv(h, s, v, Math::round(scroll[3]->get_value() / 255.0)); - } + color = modes[current_mode]->get_color(); + if (current_mode == MODE_HSV || current_mode == MODE_OKHSL) { + h = sliders[0]->get_value() / 360.0; + s = sliders[1]->get_value() / 100.0; + v = sliders[2]->get_value() / 100.0; last_color = color; - } else { - for (int i = 0; i < 4; i++) { - color.components[i] = scroll[i]->get_value() / (raw_mode_enabled ? 1.0 : 255.0); - } } _set_pick_color(color, false); emit_signal(SNAME("color_changed"), color); } +void ColorPicker::add_mode(ColorMode *p_mode) { + modes.push_back(p_mode); + mode_option_button->add_item(RTR(p_mode->get_name())); +} + +void ColorPicker::create_slider(GridContainer *gc, int idx) { + Label *l = memnew(Label()); + l->set_v_size_flags(SIZE_SHRINK_CENTER); + gc->add_child(l); + + HSlider *s = memnew(HSlider); + s->set_v_size_flags(SIZE_SHRINK_CENTER); + s->set_focus_mode(FOCUS_NONE); + gc->add_child(s); + + SpinBox *v = memnew(SpinBox); + s->share(v); + gc->add_child(v); + v->get_line_edit()->connect("focus_entered", callable_mp(this, &ColorPicker::_focus_enter)); + v->get_line_edit()->connect("focus_exited", callable_mp(this, &ColorPicker::_focus_exit)); + + s->set_h_size_flags(SIZE_EXPAND_FILL); + + s->connect("value_changed", callable_mp(this, &ColorPicker::_value_changed)); + s->connect("draw", callable_mp(this, &ColorPicker::_slider_draw), make_binds(idx)); + + if (idx < SLIDER_COUNT) { + sliders[idx] = s; + values[idx] = v; + labels[idx] = l; + } else { + alpha_slider = s; + alpha_value = v; + alpha_label = l; + } +} + +HSlider *ColorPicker::get_slider(int idx) { + if (idx < SLIDER_COUNT) { + return sliders[idx]; + } + return alpha_slider; +} + +Vector<float> ColorPicker::get_active_slider_values() { + Vector<float> values; + for (int i = 0; i < current_slider_count; i++) { + values.push_back(sliders[i]->get_value()); + } + values.push_back(alpha_slider->get_value()); + return values; +} + +ColorPicker::PickerShapeType ColorPicker::_get_actual_shape() const { + return modes[current_mode]->get_shape_override() != SHAPE_MAX ? modes[current_mode]->get_shape_override() : current_shape; +} + +void ColorPicker::_reset_theme() { + Ref<StyleBoxEmpty> style_box_empty(memnew(StyleBoxEmpty)); + + for (int i = 0; i < SLIDER_COUNT; i++) { + sliders[i]->add_theme_icon_override("grabber", get_theme_icon(SNAME("bar_arrow"), SNAME("ColorPicker"))); + sliders[i]->add_theme_icon_override("grabber_highlight", get_theme_icon(SNAME("bar_arrow"), SNAME("ColorPicker"))); + sliders[i]->add_theme_style_override("slider", style_box_empty); + sliders[i]->add_theme_style_override("grabber_area", style_box_empty); + sliders[i]->add_theme_style_override("grabber_area_highlight", style_box_empty); + } + alpha_slider->add_theme_icon_override("grabber", get_theme_icon(SNAME("bar_arrow"), SNAME("ColorPicker"))); + alpha_slider->add_theme_icon_override("grabber_highlight", get_theme_icon(SNAME("bar_arrow"), SNAME("ColorPicker"))); + alpha_slider->add_theme_style_override("slider", style_box_empty); + alpha_slider->add_theme_style_override("grabber_area", style_box_empty); + alpha_slider->add_theme_style_override("grabber_area_highlight", style_box_empty); +} + void ColorPicker::_html_submitted(const String &p_html) { if (updating || text_is_constructor || !c_text->is_visible()) { return; @@ -397,35 +430,15 @@ void ColorPicker::_update_color(bool p_update_sliders) { updating = true; if (p_update_sliders) { - if (hsv_mode_enabled) { - for (int i = 0; i < 4; i++) { - scroll[i]->set_step(1.0); - } - scroll[0]->set_max(359); - scroll[0]->set_value(h * 360.0); - scroll[1]->set_max(100); - scroll[1]->set_value(s * 100.0); - scroll[2]->set_max(100); - scroll[2]->set_value(v * 100.0); - scroll[3]->set_max(255); - scroll[3]->set_value(Math::round(color.components[3] * 255.0)); - } else { - for (int i = 0; i < 4; i++) { - if (raw_mode_enabled) { - scroll[i]->set_step(0.01); - scroll[i]->set_max(100); - if (i == 3) { - scroll[i]->set_max(1); - } - scroll[i]->set_value(color.components[i]); - } else { - scroll[i]->set_step(1); - const float byte_value = Math::round(color.components[i] * 255.0); - scroll[i]->set_max(next_power_of_2(MAX(255, byte_value)) - 1); - scroll[i]->set_value(byte_value); - } - } + float step = modes[current_mode]->get_slider_step(); + for (int i = 0; i < current_slider_count; i++) { + sliders[i]->set_max(modes[current_mode]->get_slider_max(i)); + sliders[i]->set_step(step); + sliders[i]->set_value(modes[current_mode]->get_slider_value(i)); } + alpha_slider->set_max(modes[current_mode]->get_slider_max(current_slider_count)); + alpha_slider->set_step(step); + alpha_slider->set_value(modes[current_mode]->get_slider_value(current_slider_count)); } _update_text_value(); @@ -433,9 +446,10 @@ void ColorPicker::_update_color(bool p_update_sliders) { sample->update(); uv_edit->update(); w_edit->update(); - for (int i = 0; i < 4; i++) { - scroll[i]->update(); + for (int i = 0; i < current_slider_count; i++) { + sliders[i]->update(); } + alpha_slider->update(); wheel->update(); wheel_uv->update(); updating = false; @@ -481,15 +495,16 @@ Color ColorPicker::get_pick_color() const { return color; } -void ColorPicker::set_picker_shape(PickerShapeType p_picker_type) { - ERR_FAIL_INDEX(p_picker_type, SHAPE_MAX); - picker_type = p_picker_type; +void ColorPicker::set_picker_shape(PickerShapeType p_shape) { + ERR_FAIL_INDEX(p_shape, SHAPE_MAX); + current_shape = p_shape; + _update_controls(); _update_color(); } ColorPicker::PickerShapeType ColorPicker::get_picker_shape() const { - return picker_type; + return current_shape; } inline int ColorPicker::_get_preset_size() { @@ -505,6 +520,21 @@ void ColorPicker::_add_preset_button(int p_size, const Color &p_color) { preset_container->add_child(btn_preset); } +void ColorPicker::_set_color_mode(ColorModeType p_mode) { + if (slider_theme_modified) { + _reset_theme(); + } + + current_mode = p_mode; + + if (!is_inside_tree()) { + return; + } + + _update_controls(); + _update_color(); +} + void ColorPicker::add_preset(const Color &p_color) { if (presets.find(p_color)) { presets.move_to_back(presets.find(p_color)); @@ -564,46 +594,14 @@ PackedColorArray ColorPicker::get_presets() const { return arr; } -void ColorPicker::set_hsv_mode(bool p_enabled) { - if (hsv_mode_enabled == p_enabled || raw_mode_enabled) { - return; - } - hsv_mode_enabled = p_enabled; - if (btn_hsv->is_pressed() != p_enabled) { - btn_hsv->set_pressed(p_enabled); - } - - if (!is_inside_tree()) { - return; - } - - _update_controls(); - _update_color(); -} - -bool ColorPicker::is_hsv_mode() const { - return hsv_mode_enabled; -} - -void ColorPicker::set_raw_mode(bool p_enabled) { - if (raw_mode_enabled == p_enabled || hsv_mode_enabled) { - return; - } - raw_mode_enabled = p_enabled; - if (btn_raw->is_pressed() != p_enabled) { - btn_raw->set_pressed(p_enabled); - } - - if (!is_inside_tree()) { - return; - } - - _update_controls(); - _update_color(); +void ColorPicker::set_color_mode(ColorModeType p_mode) { + ERR_FAIL_INDEX(p_mode, MODE_MAX); + mode_option_button->select(p_mode); + _set_color_mode(p_mode); } -bool ColorPicker::is_raw_mode() const { - return raw_mode_enabled; +ColorPicker::ColorModeType ColorPicker::get_color_mode() const { + return current_mode; } void ColorPicker::set_deferred_mode(bool p_enabled) { @@ -690,6 +688,8 @@ void ColorPicker::_hsv_draw(int p_which, Control *c) { if (!c) { return; } + + PickerShapeType actual_shape = _get_actual_shape(); if (p_which == 0) { Vector<Point2> points; Vector<Color> colors; @@ -697,7 +697,7 @@ void ColorPicker::_hsv_draw(int p_which, Control *c) { Color col = color; Vector2 center = c->get_size() / 2.0; - switch (picker_type) { + switch (actual_shape) { case SHAPE_HSV_WHEEL: { points.resize(4); colors.resize(4); @@ -759,7 +759,7 @@ void ColorPicker::_hsv_draw(int p_which, Control *c) { Ref<Texture2D> cursor = get_theme_icon(SNAME("picker_cursor"), SNAME("ColorPicker")); int x; int y; - if (picker_type == SHAPE_VHS_CIRCLE || picker_type == SHAPE_OKHSL_CIRCLE) { + if (actual_shape == SHAPE_VHS_CIRCLE || actual_shape == SHAPE_OKHSL_CIRCLE) { x = center.x + (center.x * Math::cos(h * Math_TAU) * s) - (cursor->get_width() / 2); y = center.y + (center.y * Math::sin(h * Math_TAU) * s) - (cursor->get_height() / 2); } else { @@ -773,7 +773,7 @@ void ColorPicker::_hsv_draw(int p_which, Control *c) { c->draw_texture(cursor, Point2(x, y)); col.set_hsv(h, 1, 1); - if (picker_type == SHAPE_HSV_WHEEL) { + if (actual_shape == SHAPE_HSV_WHEEL) { points.resize(4); double h1 = h - (0.5 / 360); double h2 = h + (0.5 / 360); @@ -785,14 +785,14 @@ void ColorPicker::_hsv_draw(int p_which, Control *c) { } } else if (p_which == 1) { - if (picker_type == SHAPE_HSV_RECTANGLE) { + if (actual_shape == SHAPE_HSV_RECTANGLE) { Ref<Texture2D> hue = get_theme_icon(SNAME("color_hue"), SNAME("ColorPicker")); c->draw_texture_rect(hue, Rect2(Point2(), c->get_size())); int y = c->get_size().y - c->get_size().y * (1.0 - h); Color col; col.set_hsv(h, 1, 1); c->draw_line(Point2(0, y), Point2(c->get_size().x, y), col.inverted()); - } else if (picker_type == SHAPE_OKHSL_CIRCLE) { + } else if (actual_shape == SHAPE_OKHSL_CIRCLE) { Vector<Point2> points; Vector<Color> colors; Color col; @@ -811,7 +811,7 @@ void ColorPicker::_hsv_draw(int p_which, Control *c) { int y = c->get_size().y - c->get_size().y * CLAMP(v, 0, 1); col.set_ok_hsl(h, 1, v); c->draw_line(Point2(0, y), Point2(c->get_size().x, y), col.inverted()); - } else if (picker_type == SHAPE_VHS_CIRCLE) { + } else if (actual_shape == SHAPE_VHS_CIRCLE) { Vector<Point2> points; Vector<Color> colors; Color col; @@ -833,87 +833,24 @@ void ColorPicker::_hsv_draw(int p_which, Control *c) { } } else if (p_which == 2) { c->draw_rect(Rect2(Point2(), c->get_size()), Color(1, 1, 1)); - if (picker_type == SHAPE_VHS_CIRCLE || picker_type == SHAPE_OKHSL_CIRCLE) { + if (actual_shape == SHAPE_VHS_CIRCLE || actual_shape == SHAPE_OKHSL_CIRCLE) { circle_mat->set_shader_param("v", v); } } } void ColorPicker::_slider_draw(int p_which) { - Vector<Vector2> pos; - pos.resize(4); - Vector<Color> col; - col.resize(4); - Size2 size = scroll[p_which]->get_size(); - Color left_color; - Color right_color; - const real_t margin = 4 * get_theme_default_base_scale(); - - if (p_which == 3) { - scroll[p_which]->draw_texture_rect(get_theme_icon(SNAME("sample_bg"), SNAME("ColorPicker")), Rect2(Point2(0, margin), Size2(size.x, margin)), true); - - left_color = color; - left_color.a = 0; - right_color = color; - right_color.a = 1; - } else { - if (raw_mode_enabled) { - return; - } - if (hsv_mode_enabled) { - if (p_which == 0) { - Ref<Texture2D> hue = get_theme_icon(SNAME("color_hue"), SNAME("ColorPicker")); - scroll[p_which]->draw_set_transform(Point2(), -Math_PI / 2, Size2(1.0, 1.0)); - scroll[p_which]->draw_texture_rect(hue, Rect2(Vector2(margin * -2, 0), Vector2(scroll[p_which]->get_size().x, margin)), false, Color(1, 1, 1), true); - return; - } - Color s_col; - Color v_col; - if (picker_type == SHAPE_OKHSL_CIRCLE) { - s_col.set_ok_hsl(h, 0, v); - } else { - s_col.set_hsv(h, 0, v); - } - left_color = (p_which == 1) ? s_col : Color(0, 0, 0); - if (picker_type == SHAPE_OKHSL_CIRCLE) { - s_col.set_ok_hsl(h, 1, v); - v_col.set_ok_hsl(h, s, 1); - } else { - s_col.set_hsv(h, 1, v); - v_col.set_hsv(h, s, 1); - } - right_color = (p_which == 1) ? s_col : v_col; - } else { - left_color = Color( - p_which == 0 ? 0 : color.r, - p_which == 1 ? 0 : color.g, - p_which == 2 ? 0 : color.b); - right_color = Color( - p_which == 0 ? 1 : color.r, - p_which == 1 ? 1 : color.g, - p_which == 2 ? 1 : color.b); - } - } - - col.set(0, left_color); - col.set(1, right_color); - col.set(2, right_color); - col.set(3, left_color); - pos.set(0, Vector2(0, margin)); - pos.set(1, Vector2(size.x, margin)); - pos.set(2, Vector2(size.x, margin * 2)); - pos.set(3, Vector2(0, margin * 2)); - - scroll[p_which]->draw_polygon(pos, col); + modes[current_mode]->slider_draw(p_which); } void ColorPicker::_uv_input(const Ref<InputEvent> &p_event, Control *c) { Ref<InputEventMouseButton> bev = p_event; + PickerShapeType current_picker = _get_actual_shape(); if (bev.is_valid()) { if (bev->is_pressed() && bev->get_button_index() == MouseButton::LEFT) { Vector2 center = c->get_size() / 2.0; - if (picker_type == SHAPE_VHS_CIRCLE || picker_type == SHAPE_OKHSL_CIRCLE) { + if (current_picker == SHAPE_VHS_CIRCLE || current_picker == SHAPE_OKHSL_CIRCLE) { real_t dist = center.distance_to(bev->get_position()); if (dist <= center.x) { real_t rad = center.angle_to_point(bev->get_position()); @@ -951,11 +888,12 @@ void ColorPicker::_uv_input(const Ref<InputEvent> &p_event, Control *c) { } } changing_color = true; - if (picker_type == SHAPE_OKHSL_CIRCLE) { + if (current_picker == SHAPE_OKHSL_CIRCLE) { color.set_ok_hsl(h, s, v, color.a); - } else if (picker_type != SHAPE_OKHSL_CIRCLE) { + } else { color.set_hsv(h, s, v, color.a); } + last_color = color; set_pick_color(color); @@ -981,7 +919,7 @@ void ColorPicker::_uv_input(const Ref<InputEvent> &p_event, Control *c) { } Vector2 center = c->get_size() / 2.0; - if (picker_type == SHAPE_VHS_CIRCLE || picker_type == SHAPE_OKHSL_CIRCLE) { + if (current_picker == SHAPE_VHS_CIRCLE || current_picker == SHAPE_OKHSL_CIRCLE) { real_t dist = center.distance_to(mev->get_position()); real_t rad = center.angle_to_point(mev->get_position()); h = ((rad >= 0) ? rad : (Math_TAU + rad)) / Math_TAU; @@ -1002,9 +940,9 @@ void ColorPicker::_uv_input(const Ref<InputEvent> &p_event, Control *c) { v = 1.0 - (y - corner_y) / real_size.y; } } - if (picker_type != SHAPE_OKHSL_CIRCLE) { + if (current_picker != SHAPE_OKHSL_CIRCLE) { color.set_hsv(h, s, v, color.a); - } else if (picker_type == SHAPE_OKHSL_CIRCLE) { + } else { color.set_ok_hsl(h, s, v, color.a); } last_color = color; @@ -1018,12 +956,13 @@ void ColorPicker::_uv_input(const Ref<InputEvent> &p_event, Control *c) { void ColorPicker::_w_input(const Ref<InputEvent> &p_event) { Ref<InputEventMouseButton> bev = p_event; + PickerShapeType actual_shape = _get_actual_shape(); if (bev.is_valid()) { if (bev->is_pressed() && bev->get_button_index() == MouseButton::LEFT) { changing_color = true; float y = CLAMP((float)bev->get_position().y, 0, w_edit->get_size().height); - if (picker_type == SHAPE_VHS_CIRCLE || picker_type == SHAPE_OKHSL_CIRCLE) { + if (actual_shape == SHAPE_VHS_CIRCLE || actual_shape == SHAPE_OKHSL_CIRCLE) { v = 1.0 - (y / w_edit->get_size().height); } else { h = y / w_edit->get_size().height; @@ -1031,9 +970,9 @@ void ColorPicker::_w_input(const Ref<InputEvent> &p_event) { } else { changing_color = false; } - if (picker_type != SHAPE_OKHSL_CIRCLE) { + if (actual_shape != SHAPE_OKHSL_CIRCLE) { color.set_hsv(h, s, v, color.a); - } else if (picker_type == SHAPE_OKHSL_CIRCLE) { + } else { color.set_ok_hsl(h, s, v, color.a); } last_color = color; @@ -1053,16 +992,18 @@ void ColorPicker::_w_input(const Ref<InputEvent> &p_event) { return; } float y = CLAMP((float)mev->get_position().y, 0, w_edit->get_size().height); - if (picker_type == SHAPE_VHS_CIRCLE || picker_type == SHAPE_OKHSL_CIRCLE) { + if (actual_shape == SHAPE_VHS_CIRCLE || actual_shape == SHAPE_OKHSL_CIRCLE) { v = 1.0 - (y / w_edit->get_size().height); } else { h = y / w_edit->get_size().height; } - if (hsv_mode_enabled && picker_type != SHAPE_OKHSL_CIRCLE) { + + if (current_mode == MODE_HSV) { color.set_hsv(h, s, v, color.a); - } else if (hsv_mode_enabled && picker_type == SHAPE_OKHSL_CIRCLE) { + } else if (current_mode == MODE_OKHSL) { color.set_ok_hsl(h, s, v, color.a); } + last_color = color; set_pick_color(color); _update_color(); @@ -1153,21 +1094,30 @@ void ColorPicker::_focus_enter() { c_text->select(0, 0); } - for (int i = 0; i < 4; i++) { + for (int i = 0; i < current_slider_count; i++) { if (values[i]->get_line_edit()->has_focus() && !has_ctext_focus) { values[i]->get_line_edit()->select_all(); } else { values[i]->get_line_edit()->select(0, 0); } } + if (alpha_value->get_line_edit()->has_focus() && !has_ctext_focus) { + alpha_value->get_line_edit()->select_all(); + } else { + alpha_value->get_line_edit()->select(0, 0); + } } void ColorPicker::_focus_exit() { - for (int i = 0; i < 4; i++) { + for (int i = 0; i < current_slider_count; i++) { if (!values[i]->get_line_edit()->get_menu()->is_visible()) { values[i]->get_line_edit()->select(0, 0); } } + if (!alpha_value->get_line_edit()->get_menu()->is_visible()) { + alpha_value->get_line_edit()->select(0, 0); + } + c_text->select(0, 0); } @@ -1207,12 +1157,10 @@ bool ColorPicker::are_presets_visible() const { void ColorPicker::_bind_methods() { ClassDB::bind_method(D_METHOD("set_pick_color", "color"), &ColorPicker::set_pick_color); ClassDB::bind_method(D_METHOD("get_pick_color"), &ColorPicker::get_pick_color); - ClassDB::bind_method(D_METHOD("set_hsv_mode", "enabled"), &ColorPicker::set_hsv_mode); - ClassDB::bind_method(D_METHOD("is_hsv_mode"), &ColorPicker::is_hsv_mode); - ClassDB::bind_method(D_METHOD("set_raw_mode", "enabled"), &ColorPicker::set_raw_mode); - ClassDB::bind_method(D_METHOD("is_raw_mode"), &ColorPicker::is_raw_mode); ClassDB::bind_method(D_METHOD("set_deferred_mode", "mode"), &ColorPicker::set_deferred_mode); ClassDB::bind_method(D_METHOD("is_deferred_mode"), &ColorPicker::is_deferred_mode); + ClassDB::bind_method(D_METHOD("set_color_mode", "color_mode"), &ColorPicker::set_color_mode); + ClassDB::bind_method(D_METHOD("get_color_mode"), &ColorPicker::get_color_mode); ClassDB::bind_method(D_METHOD("set_edit_alpha", "show"), &ColorPicker::set_edit_alpha); ClassDB::bind_method(D_METHOD("is_editing_alpha"), &ColorPicker::is_editing_alpha); ClassDB::bind_method(D_METHOD("set_presets_enabled", "enabled"), &ColorPicker::set_presets_enabled); @@ -1222,13 +1170,12 @@ void ColorPicker::_bind_methods() { ClassDB::bind_method(D_METHOD("add_preset", "color"), &ColorPicker::add_preset); ClassDB::bind_method(D_METHOD("erase_preset", "color"), &ColorPicker::erase_preset); ClassDB::bind_method(D_METHOD("get_presets"), &ColorPicker::get_presets); - ClassDB::bind_method(D_METHOD("set_picker_shape", "picker"), &ColorPicker::set_picker_shape); + ClassDB::bind_method(D_METHOD("set_picker_shape", "shape"), &ColorPicker::set_picker_shape); ClassDB::bind_method(D_METHOD("get_picker_shape"), &ColorPicker::get_picker_shape); ADD_PROPERTY(PropertyInfo(Variant::COLOR, "color"), "set_pick_color", "get_pick_color"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "edit_alpha"), "set_edit_alpha", "is_editing_alpha"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "hsv_mode"), "set_hsv_mode", "is_hsv_mode"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "raw_mode"), "set_raw_mode", "is_raw_mode"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "color_mode", PROPERTY_HINT_ENUM, "RGB,HSV,RAW,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"), "set_picker_shape", "get_picker_shape"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "presets_enabled"), "set_presets_enabled", "are_presets_enabled"); @@ -1238,6 +1185,11 @@ void ColorPicker::_bind_methods() { ADD_SIGNAL(MethodInfo("preset_added", PropertyInfo(Variant::COLOR, "color"))); ADD_SIGNAL(MethodInfo("preset_removed", PropertyInfo(Variant::COLOR, "color"))); + BIND_ENUM_CONSTANT(MODE_RGB); + BIND_ENUM_CONSTANT(MODE_HSV); + BIND_ENUM_CONSTANT(MODE_RAW); + BIND_ENUM_CONSTANT(MODE_OKHSL); + BIND_ENUM_CONSTANT(SHAPE_HSV_RECTANGLE); BIND_ENUM_CONSTANT(SHAPE_HSV_WHEEL); BIND_ENUM_CONSTANT(SHAPE_VHS_CIRCLE); @@ -1250,6 +1202,7 @@ ColorPicker::ColorPicker() : add_child(hb_edit, false, INTERNAL_MODE_FRONT); hb_edit->set_v_size_flags(SIZE_EXPAND_FILL); + uv_edit = memnew(Control); hb_edit->add_child(uv_edit); uv_edit->connect("gui_input", callable_mp(this, &ColorPicker::_uv_input), make_binds(uv_edit)); uv_edit->set_mouse_filter(MOUSE_FILTER_PASS); @@ -1260,11 +1213,13 @@ ColorPicker::ColorPicker() : HBoxContainer *hb_smpl = memnew(HBoxContainer); add_child(hb_smpl, false, INTERNAL_MODE_FRONT); + sample = memnew(TextureRect); hb_smpl->add_child(sample); sample->set_h_size_flags(SIZE_EXPAND_FILL); sample->connect("gui_input", callable_mp(this, &ColorPicker::_sample_input)); sample->connect("draw", callable_mp(this, &ColorPicker::_sample_draw)); + btn_pick = memnew(Button); btn_pick->set_flat(true); hb_smpl->add_child(btn_pick); btn_pick->set_toggle_mode(true); @@ -1277,51 +1232,35 @@ ColorPicker::ColorPicker() : add_child(memnew(HSeparator), false, INTERNAL_MODE_FRONT); VBoxContainer *vbr = memnew(VBoxContainer); + add_child(vbr, false, INTERNAL_MODE_FRONT); vbr->set_h_size_flags(SIZE_EXPAND_FILL); - for (int i = 0; i < 4; i++) { - HBoxContainer *hbc = memnew(HBoxContainer); + GridContainer *gc = memnew(GridContainer); - labels[i] = memnew(Label()); - labels[i]->set_custom_minimum_size(Size2(get_theme_constant(SNAME("label_width")), 0)); - labels[i]->set_v_size_flags(SIZE_SHRINK_CENTER); - hbc->add_child(labels[i]); + vbr->add_child(gc); + gc->set_h_size_flags(SIZE_EXPAND_FILL); + gc->set_columns(3); - scroll[i] = memnew(HSlider); - scroll[i]->set_v_size_flags(SIZE_SHRINK_CENTER); - scroll[i]->set_focus_mode(FOCUS_NONE); - hbc->add_child(scroll[i]); - - values[i] = memnew(SpinBox); - scroll[i]->share(values[i]); - hbc->add_child(values[i]); - values[i]->get_line_edit()->connect("focus_entered", callable_mp(this, &ColorPicker::_focus_enter)); - values[i]->get_line_edit()->connect("focus_exited", callable_mp(this, &ColorPicker::_focus_exit)); - - scroll[i]->set_min(0); - scroll[i]->set_page(0); - scroll[i]->set_h_size_flags(SIZE_EXPAND_FILL); - - scroll[i]->connect("value_changed", callable_mp(this, &ColorPicker::_value_changed)); - scroll[i]->connect("draw", callable_mp(this, &ColorPicker::_slider_draw), make_binds(i)); - - vbr->add_child(hbc); + for (int i = 0; i < SLIDER_COUNT + 1; i++) { + create_slider(gc, i); } - labels[3]->set_text("A"); + alpha_label->set_text("A"); HBoxContainer *hhb = memnew(HBoxContainer); vbr->add_child(hhb); - hhb->add_child(btn_hsv); - btn_hsv->set_text(RTR("HSV")); - btn_hsv->connect("toggled", callable_mp(this, &ColorPicker::set_hsv_mode)); + mode_option_button = memnew(OptionButton); - hhb->add_child(btn_raw); - btn_raw->set_text(RTR("Raw")); - btn_raw->connect("toggled", callable_mp(this, &ColorPicker::set_raw_mode)); + hhb->add_child(mode_option_button); + add_mode(new ColorModeRGB(this)); + add_mode(new ColorModeHSV(this)); + add_mode(new ColorModeRAW(this)); + add_mode(new ColorModeOKHSL(this)); + mode_option_button->connect("item_selected", callable_mp(this, &ColorPicker::_set_color_mode)); + text_type = memnew(Button); hhb->add_child(text_type); text_type->set_text("#"); text_type->set_tooltip(RTR("Switch between hexadecimal and code values.")); @@ -1332,12 +1271,14 @@ ColorPicker::ColorPicker() : text_type->set_mouse_filter(MOUSE_FILTER_IGNORE); } + c_text = memnew(LineEdit); hhb->add_child(c_text); c_text->set_h_size_flags(SIZE_EXPAND_FILL); c_text->connect("text_submitted", callable_mp(this, &ColorPicker::_html_submitted)); c_text->connect("focus_entered", callable_mp(this, &ColorPicker::_focus_enter)); c_text->connect("focus_exited", callable_mp(this, &ColorPicker::_html_focus_exit)); + wheel_edit = memnew(AspectRatioContainer); wheel_edit->set_h_size_flags(SIZE_EXPAND_FILL); wheel_edit->set_v_size_flags(SIZE_EXPAND_FILL); hb_edit->add_child(wheel_edit); @@ -1347,41 +1288,53 @@ ColorPicker::ColorPicker() : circle_mat.instantiate(); circle_mat->set_shader(circle_shader); + wheel_margin = memnew(MarginContainer); wheel_margin->add_theme_constant_override("margin_bottom", 8); wheel_edit->add_child(wheel_margin); + wheel = memnew(Control); wheel_margin->add_child(wheel); wheel->set_mouse_filter(MOUSE_FILTER_PASS); wheel->connect("draw", callable_mp(this, &ColorPicker::_hsv_draw), make_binds(2, wheel)); + wheel_uv = memnew(Control); wheel_margin->add_child(wheel_uv); wheel_uv->connect("gui_input", callable_mp(this, &ColorPicker::_uv_input), make_binds(wheel_uv)); wheel_uv->connect("draw", callable_mp(this, &ColorPicker::_hsv_draw), make_binds(0, wheel_uv)); + w_edit = memnew(Control); hb_edit->add_child(w_edit); w_edit->set_h_size_flags(SIZE_FILL); w_edit->set_v_size_flags(SIZE_EXPAND_FILL); w_edit->connect("gui_input", callable_mp(this, &ColorPicker::_w_input)); w_edit->connect("draw", callable_mp(this, &ColorPicker::_hsv_draw), make_binds(1, w_edit)); - picker_type = SHAPE_HSV_RECTANGLE; _update_controls(); updating = false; set_pick_color(Color(1, 1, 1)); + preset_separator = memnew(HSeparator); add_child(preset_separator, false, INTERNAL_MODE_FRONT); + preset_container = memnew(GridContainer); preset_container->set_h_size_flags(SIZE_EXPAND_FILL); preset_container->set_columns(preset_column_count); add_child(preset_container, false, INTERNAL_MODE_FRONT); + btn_add_preset = memnew(Button); btn_add_preset->set_icon_alignment(HORIZONTAL_ALIGNMENT_CENTER); btn_add_preset->set_tooltip(RTR("Add current color as a preset.")); btn_add_preset->connect("pressed", callable_mp(this, &ColorPicker::_add_preset_pressed)); preset_container->add_child(btn_add_preset); } +ColorPicker::~ColorPicker() { + for (int i = 0; i < modes.size(); i++) { + delete modes[i]; + } +} + ///////////////// void ColorPickerButton::_about_to_popup() { diff --git a/scene/gui/color_picker.h b/scene/gui/color_picker.h index 953be032ec..e219c78319 100644 --- a/scene/gui/color_picker.h +++ b/scene/gui/color_picker.h @@ -34,16 +34,23 @@ #include "scene/gui/aspect_ratio_container.h" #include "scene/gui/box_container.h" #include "scene/gui/button.h" -#include "scene/gui/check_button.h" +#include "scene/gui/control.h" #include "scene/gui/grid_container.h" #include "scene/gui/label.h" #include "scene/gui/line_edit.h" +#include "scene/gui/option_button.h" #include "scene/gui/popup.h" #include "scene/gui/separator.h" #include "scene/gui/slider.h" #include "scene/gui/spin_box.h" #include "scene/gui/texture_rect.h" +class ColorMode; +class ColorModeRGB; +class ColorModeHSV; +class ColorModeRAW; +class ColorModeOKHSL; + class ColorPresetButton : public BaseButton { GDCLASS(ColorPresetButton, BaseButton); @@ -64,6 +71,15 @@ class ColorPicker : public BoxContainer { GDCLASS(ColorPicker, BoxContainer); public: + enum ColorModeType { + MODE_RGB, + MODE_HSV, + MODE_RAW, + MODE_OKHSL, + + MODE_MAX + }; + enum PickerShapeType { SHAPE_HSV_RECTANGLE, SHAPE_HSV_WHEEL, @@ -73,38 +89,52 @@ public: SHAPE_MAX }; + static const int SLIDER_COUNT = 4; + private: static Ref<Shader> wheel_shader; static Ref<Shader> circle_shader; static Ref<Shader> circle_ok_color_shader; static List<Color> preset_cache; + int current_slider_count = SLIDER_COUNT; + + bool slider_theme_modified = true; + + Vector<ColorMode *> modes; + Control *screen = nullptr; - Control *uv_edit = memnew(Control); - Control *w_edit = memnew(Control); - AspectRatioContainer *wheel_edit = memnew(AspectRatioContainer); - MarginContainer *wheel_margin = memnew(MarginContainer); + Control *uv_edit = nullptr; + Control *w_edit = nullptr; + AspectRatioContainer *wheel_edit = nullptr; + MarginContainer *wheel_margin = nullptr; Ref<ShaderMaterial> wheel_mat; Ref<ShaderMaterial> circle_mat; - Control *wheel = memnew(Control); - Control *wheel_uv = memnew(Control); - TextureRect *sample = memnew(TextureRect); - GridContainer *preset_container = memnew(GridContainer); - HSeparator *preset_separator = memnew(HSeparator); - Button *btn_add_preset = memnew(Button); - Button *btn_pick = memnew(Button); - CheckButton *btn_hsv = memnew(CheckButton); - CheckButton *btn_raw = memnew(CheckButton); - HSlider *scroll[4]; - SpinBox *values[4]; - Label *labels[4]; - Button *text_type = memnew(Button); - LineEdit *c_text = memnew(LineEdit); + Control *wheel = nullptr; + Control *wheel_uv = nullptr; + TextureRect *sample = nullptr; + GridContainer *preset_container = nullptr; + HSeparator *preset_separator = nullptr; + Button *btn_add_preset = nullptr; + Button *btn_pick = nullptr; + + OptionButton *mode_option_button = nullptr; + + HSlider *sliders[SLIDER_COUNT]; + SpinBox *values[SLIDER_COUNT]; + Label *labels[SLIDER_COUNT]; + Button *text_type = nullptr; + LineEdit *c_text = nullptr; + + HSlider *alpha_slider = nullptr; + SpinBox *alpha_value = nullptr; + Label *alpha_label = nullptr; bool edit_alpha = true; Size2i ms; bool text_is_constructor = false; - PickerShapeType picker_type = SHAPE_HSV_WHEEL; + PickerShapeType current_shape = SHAPE_HSV_RECTANGLE; + ColorModeType current_mode = MODE_RGB; const int preset_column_count = 9; int prev_preset_size = 0; @@ -114,8 +144,6 @@ private: Color old_color; bool display_old_color = false; - bool raw_mode_enabled = false; - bool hsv_mode_enabled = false; bool deferred_mode_enabled = false; bool updating = true; bool changing_color = false; @@ -128,6 +156,9 @@ private: float v = 0.0; Color last_color; + PickerShapeType _get_actual_shape() const; + void create_slider(GridContainer *gc, int idx); + void _reset_theme(); void _html_submitted(const String &p_html); void _value_changed(double); void _update_controls(); @@ -152,14 +183,21 @@ private: inline int _get_preset_size(); void _add_preset_button(int p_size, const Color &p_color); + void _set_color_mode(ColorModeType p_mode); + protected: void _notification(int); static void _bind_methods(); public: + HSlider *get_slider(int idx); + Vector<float> get_active_slider_values(); + static void init_shaders(); static void finish_shaders(); + void add_mode(ColorMode *p_mode); + void set_edit_alpha(bool p_show); bool is_editing_alpha() const; @@ -173,7 +211,7 @@ public: void set_display_old_color(bool p_enabled); bool is_displaying_old_color() const; - void set_picker_shape(PickerShapeType p_picker_type); + void set_picker_shape(PickerShapeType p_shape); PickerShapeType get_picker_shape() const; void add_preset(const Color &p_color); @@ -181,11 +219,8 @@ public: PackedColorArray get_presets() const; void _update_presets(); - void set_hsv_mode(bool p_enabled); - bool is_hsv_mode() const; - - void set_raw_mode(bool p_enabled); - bool is_raw_mode() const; + void set_color_mode(ColorModeType p_mode); + ColorModeType get_color_mode() const; void set_deferred_mode(bool p_enabled); bool is_deferred_mode() const; @@ -199,6 +234,7 @@ public: void set_focus_on_line_edit(); ColorPicker(); + ~ColorPicker(); }; class ColorPickerButton : public Button { @@ -239,4 +275,5 @@ public: }; VARIANT_ENUM_CAST(ColorPicker::PickerShapeType); +VARIANT_ENUM_CAST(ColorPicker::ColorModeType); #endif // COLOR_PICKER_H |