From 365486543d2395ec9c87b72e62fb649fd3be1f92 Mon Sep 17 00:00:00 2001 From: Hendrik Brucker Date: Mon, 17 Jan 2022 15:21:47 +0100 Subject: [PATCH] Improve Colorpicker presets --- editor/editor_themes.cpp | 8 + scene/gui/color_picker.cpp | 186 ++++++++++++------ scene/gui/color_picker.h | 37 +++- .../resources/default_theme/default_theme.cpp | 44 +++-- 4 files changed, 184 insertions(+), 91 deletions(-) diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp index bd2de0fc504e..5f9dc3eeab70 100644 --- a/editor/editor_themes.cpp +++ b/editor/editor_themes.cpp @@ -1279,6 +1279,14 @@ Ref create_editor_theme(const Ref p_theme) { theme->set_icon("bg", "ColorPickerButton", theme->get_icon("GuiMiniCheckerboard", "EditorIcons")); + // ColorPresetButton + Ref preset_sb = make_flat_stylebox(Color(1, 1, 1), 2, 2, 2, 2); + + preset_sb->set_anti_aliased(false); + theme->set_stylebox("preset_fg", "ColorPresetButton", preset_sb); + theme->set_icon("preset_bg_icon", "ColorPresetButton", theme->get_icon("GuiMiniCheckerboard", "EditorIcons")); + theme->set_icon("overbright_indicator", "ColorPresetButton", theme->get_icon("OverbrightIndicator", "EditorIcons")); + // Information on 3D viewport Ref style_info_3d_viewport = style_default->duplicate(); style_info_3d_viewport->set_bg_color(style_info_3d_viewport->get_bg_color() * Color(1, 1, 1, 0.5)); diff --git a/scene/gui/color_picker.cpp b/scene/gui/color_picker.cpp index 97a3c1fb89c3..00458a79c170 100644 --- a/scene/gui/color_picker.cpp +++ b/scene/gui/color_picker.cpp @@ -46,13 +46,13 @@ void ColorPicker::_notification(int p_what) { switch (p_what) { case NOTIFICATION_THEME_CHANGED: { btn_pick->set_icon(get_icon("screen_picker", "ColorPicker")); - bt_add_preset->set_icon(get_icon("add_preset")); - + btn_add_preset->set_icon(get_icon("add_preset")); + _update_presets(); _update_controls(); } break; case NOTIFICATION_ENTER_TREE: { btn_pick->set_icon(get_icon("screen_picker", "ColorPicker")); - bt_add_preset->set_icon(get_icon("add_preset")); + btn_add_preset->set_icon(get_icon("add_preset")); _update_controls(); _update_color(); @@ -69,7 +69,6 @@ void ColorPicker::_notification(int p_what) { for (int i = 0; i < preset_cache.size(); i++) { presets.push_back(preset_cache[i]); } - preset->update(); } #endif } break; @@ -255,19 +254,15 @@ void ColorPicker::_update_color(bool p_update_sliders) { } void ColorPicker::_update_presets() { - presets_per_row = 10; - Size2 size = bt_add_preset->get_size(); - Size2 preset_size = Size2(MIN(size.width * presets.size(), presets_per_row * size.width), size.height * (Math::ceil((float)presets.size() / presets_per_row))); - preset->set_custom_minimum_size(preset_size); - preset_container->set_custom_minimum_size(preset_size); - preset->draw_rect(Rect2(Point2(), preset_size), Color(1, 1, 1, 0)); - - for (int i = 0; i < presets.size(); i++) { - int x = (i % presets_per_row) * size.width; - int y = (Math::floor((float)i / presets_per_row)) * size.height; - preset->draw_rect(Rect2(Point2(x, y), size), presets[i]); + // Only load preset buttons when the only child is the add-preset button. + int preset_size = _get_preset_size(); + btn_add_preset->set_custom_minimum_size(Size2(preset_size, preset_size)); + if (preset_container->get_child_count() == 1) { + for (int i = 0; i < preset_cache.size(); i++) { + _add_preset_button(preset_size, preset_cache[i]); + } + _notification(NOTIFICATION_VISIBILITY_CHANGED); } - _notification(NOTIFICATION_VISIBILITY_CHANGED); } void ColorPicker::_text_type_toggled() { @@ -290,14 +285,38 @@ Color ColorPicker::get_pick_color() const { return color; } +inline int ColorPicker::_get_preset_size() { + return (int(get_size().width) - (preset_container->get_constant("hseparation") * (preset_column_count - 1))) / preset_column_count; +} + +void ColorPicker::_add_preset_button(int p_size, const Color &p_color) { + ColorPresetButton *btn_preset = memnew(ColorPresetButton(p_color)); + btn_preset->set_preset_color(p_color); + btn_preset->set_custom_minimum_size(Size2(p_size, p_size)); + btn_preset->connect("gui_input", this, "_preset_input", varray(p_color)); + btn_preset->set_tooltip(vformat(RTR("Color: #%s\nLMB: Apply color\nRMB: Remove preset"), p_color.to_html(p_color.a < 1))); + preset_container->add_child(btn_preset); +} + void ColorPicker::add_preset(const Color &p_color) { if (presets.find(p_color)) { presets.move_to_back(presets.find(p_color)); + + // Find button to move to the end. + for (int i = 1; i < preset_container->get_child_count(); i++) { + ColorPresetButton *current_btn = Object::cast_to(preset_container->get_child(i)); + if (current_btn && p_color == current_btn->get_preset_color()) { + preset_container->move_child(current_btn, preset_container->get_child_count() - 1); + break; + } + } } else { presets.push_back(p_color); preset_cache.push_back(p_color); + + _add_preset_button(_get_preset_size(), p_color); + _notification(NOTIFICATION_VISIBILITY_CHANGED); } - preset->update(); #ifdef TOOLS_ENABLED if (Engine::get_singleton()->is_editor_hint()) { @@ -311,7 +330,15 @@ void ColorPicker::erase_preset(const Color &p_color) { if (presets.find(p_color)) { presets.erase(presets.find(p_color)); preset_cache.erase(preset_cache.find(p_color)); - preset->update(); + + // Find preset button to remove. + for (int i = 1; i < preset_container->get_child_count(); i++) { + ColorPresetButton *current_btn = Object::cast_to(preset_container->get_child(i)); + if (current_btn && p_color == current_btn->get_preset_color()) { + current_btn->queue_delete(); + break; + } + } #ifdef TOOLS_ENABLED if (Engine::get_singleton()->is_editor_hint()) { @@ -585,42 +612,18 @@ void ColorPicker::_w_input(const Ref &p_event) { } } -void ColorPicker::_preset_input(const Ref &p_event) { +void ColorPicker::_preset_input(const Ref &p_event, const Color &p_color) { Ref bev = p_event; if (bev.is_valid()) { - int index = 0; if (bev->is_pressed() && bev->get_button_index() == BUTTON_LEFT) { - for (int i = 0; i < presets.size(); i++) { - int x = (i % presets_per_row) * bt_add_preset->get_size().x; - int y = (Math::floor((float)i / presets_per_row)) * bt_add_preset->get_size().y; - if (bev->get_position().x > x && bev->get_position().x < x + preset->get_size().x && bev->get_position().y > y && bev->get_position().y < y + preset->get_size().y) { - index = i; - } - } - set_pick_color(presets[index]); + set_pick_color(p_color); _update_color(); - emit_signal("color_changed", color); + emit_signal("color_changed", p_color); } else if (bev->is_pressed() && bev->get_button_index() == BUTTON_RIGHT && presets_enabled) { - index = bev->get_position().x / (preset->get_size().x / presets.size()); - Color clicked_preset = presets[index]; - erase_preset(clicked_preset); - emit_signal("preset_removed", clicked_preset); - bt_add_preset->show(); - } - } - - Ref mev = p_event; - - if (mev.is_valid()) { - int index = mev->get_position().x * presets.size(); - if (preset->get_size().x != 0) { - index /= preset->get_size().x; + erase_preset(p_color); + emit_signal("preset_removed", p_color); } - if (index < 0 || index >= presets.size()) { - return; - } - preset->set_tooltip(vformat(RTR("Color: #%s\nLMB: Set color\nRMB: Remove preset"), presets[index].to_html(presets[index].a < 1))); } } @@ -715,11 +718,11 @@ void ColorPicker::_html_focus_exit() { void ColorPicker::set_presets_enabled(bool p_enabled) { presets_enabled = p_enabled; if (!p_enabled) { - bt_add_preset->set_disabled(true); - bt_add_preset->set_focus_mode(FOCUS_NONE); + btn_add_preset->set_disabled(true); + btn_add_preset->set_focus_mode(FOCUS_NONE); } else { - bt_add_preset->set_disabled(false); - bt_add_preset->set_focus_mode(FOCUS_ALL); + btn_add_preset->set_disabled(false); + btn_add_preset->set_focus_mode(FOCUS_ALL); } } @@ -731,7 +734,6 @@ void ColorPicker::set_presets_visible(bool p_visible) { presets_visible = p_visible; preset_separator->set_visible(p_visible); preset_container->set_visible(p_visible); - preset_container2->set_visible(p_visible); } bool ColorPicker::are_presets_visible() const { @@ -915,22 +917,14 @@ ColorPicker::ColorPicker() : preset_separator = memnew(HSeparator); add_child(preset_separator); - preset_container = memnew(HBoxContainer); preset_container->set_h_size_flags(SIZE_EXPAND_FILL); + preset_container->set_columns(preset_column_count); add_child(preset_container); - preset = memnew(TextureRect); - preset_container->add_child(preset); - preset->connect("gui_input", this, "_preset_input"); - preset->connect("draw", this, "_update_presets"); - - preset_container2 = memnew(HBoxContainer); - preset_container2->set_h_size_flags(SIZE_EXPAND_FILL); - add_child(preset_container2); - bt_add_preset = memnew(Button); - preset_container2->add_child(bt_add_preset); - bt_add_preset->set_tooltip(RTR("Add current color as a preset.")); - bt_add_preset->connect("pressed", this, "_add_preset_pressed"); + btn_add_preset = memnew(Button); + btn_add_preset->connect("pressed", this, "_add_preset_pressed"); + btn_add_preset->set_tooltip(RTR("Add current color as a preset.")); + preset_container->add_child(btn_add_preset); } ///////////////// @@ -954,6 +948,7 @@ void ColorPickerButton::_modal_closed() { void ColorPickerButton::pressed() { _update_picker(); + picker->_update_presets(); popup->set_position(get_global_position() - picker->get_combined_minimum_size() * get_global_transform().get_scale()); popup->set_scale(get_global_transform().get_scale()); popup->popup(); @@ -1077,3 +1072,64 @@ ColorPickerButton::ColorPickerButton() { set_toggle_mode(true); } + +///////////////// + +void ColorPresetButton::_notification(int p_what) { + switch (p_what) { + case NOTIFICATION_DRAW: { + const Rect2 r = Rect2(Point2(0, 0), get_size()); + Ref sb_raw = get_stylebox("preset_fg", "ColorPresetButton")->duplicate(); + Ref sb_flat = sb_raw; + Ref sb_texture = sb_raw; + + if (sb_raw->get_class_name() == "StyleBoxFlat") { + if (preset_color.a < 1) { + // Draw a background pattern when the color is transparent. + sb_flat->set_bg_color(Color(1, 1, 1)); + sb_flat->draw(get_canvas_item(), r); + + Rect2 bg_texture_rect = r.grow_margin(MARGIN_LEFT, -sb_flat->get_margin(MARGIN_LEFT)); + bg_texture_rect = bg_texture_rect.grow_margin(MARGIN_RIGHT, -sb_flat->get_margin(MARGIN_RIGHT)); + bg_texture_rect = bg_texture_rect.grow_margin(MARGIN_TOP, -sb_flat->get_margin(MARGIN_TOP)); + bg_texture_rect = bg_texture_rect.grow_margin(MARGIN_BOTTOM, -sb_flat->get_margin(MARGIN_BOTTOM)); + + draw_texture_rect(get_icon("preset_bg_icon", "ColorPresetButton"), bg_texture_rect, true); + sb_flat->set_bg_color(preset_color); + } + sb_flat->set_bg_color(preset_color); + sb_flat->draw(get_canvas_item(), r); + } else if (sb_raw->get_class_name() == "StyleBoxTexture") { + if (preset_color.a < 1) { + // Draw a background pattern when the color is transparent. + bool use_tile_texture = (sb_texture->get_h_axis_stretch_mode() == StyleBoxTexture::AxisStretchMode::AXIS_STRETCH_MODE_TILE) || (sb_texture->get_h_axis_stretch_mode() == StyleBoxTexture::AxisStretchMode::AXIS_STRETCH_MODE_TILE_FIT); + draw_texture_rect(get_icon("preset_bg_icon", "ColorPresetButton"), r, use_tile_texture); + } + sb_texture->set_modulate(preset_color); + sb_texture->draw(get_canvas_item(), r); + } else { + WARN_PRINT("Unsupported StyleBox used for ColorPresetButton. Use StyleBoxFlat and StyleBoxTexture instead."); + } + if (preset_color.r > 1 || preset_color.g > 1 || preset_color.b > 1) { + // Draw an indicator to denote that the color is "overbright" and can't be displayed accurately in the preview. + draw_texture(Control::get_icon("overbright_indicator", "ColorPresetButton"), Vector2(0, 0)); + } + + } break; + } +} + +void ColorPresetButton::set_preset_color(const Color &p_color) { + preset_color = p_color; +} + +Color ColorPresetButton::get_preset_color() const { + return preset_color; +} + +ColorPresetButton::ColorPresetButton(Color p_color) { + preset_color = p_color; +} + +ColorPresetButton::~ColorPresetButton() { +} diff --git a/scene/gui/color_picker.h b/scene/gui/color_picker.h index b153bf987584..7424c9f9bd71 100644 --- a/scene/gui/color_picker.h +++ b/scene/gui/color_picker.h @@ -34,6 +34,7 @@ #include "scene/gui/box_container.h" #include "scene/gui/button.h" #include "scene/gui/check_button.h" +#include "scene/gui/grid_container.h" #include "scene/gui/label.h" #include "scene/gui/line_edit.h" #include "scene/gui/popup.h" @@ -43,6 +44,22 @@ #include "scene/gui/texture_rect.h" #include "scene/gui/tool_button.h" +class ColorPresetButton : public BaseButton { + GDCLASS(ColorPresetButton, BaseButton); + + Color preset_color; + +protected: + void _notification(int); + +public: + void set_preset_color(const Color &p_color); + Color get_preset_color() const; + + ColorPresetButton(Color p_color); + ~ColorPresetButton(); +}; + class ColorPicker : public BoxContainer { GDCLASS(ColorPicker, BoxContainer); @@ -52,12 +69,9 @@ class ColorPicker : public BoxContainer { Control *uv_edit; Control *w_edit; TextureRect *sample; - TextureRect *preset; - HBoxContainer *preset_container; - HBoxContainer *preset_container2; + GridContainer *preset_container = memnew(GridContainer); HSeparator *preset_separator; - Button *bt_add_preset; - List presets; + Button *btn_add_preset; ToolButton *btn_pick; CheckButton *btn_hsv; CheckButton *btn_raw; @@ -69,10 +83,13 @@ class ColorPicker : public BoxContainer { bool edit_alpha; Size2i ms; bool text_is_constructor; - int presets_per_row; + + const int preset_column_count = 10; + List presets; Color color; Color old_color; + bool display_old_color = false; bool raw_mode_enabled; bool hsv_mode_enabled; @@ -81,6 +98,7 @@ class ColorPicker : public BoxContainer { bool changing_color; bool presets_enabled; bool presets_visible; + float h, s, v; Color last_hsv; @@ -88,7 +106,6 @@ class ColorPicker : public BoxContainer { void _value_changed(double); void _update_controls(); void _update_color(bool p_update_sliders = true); - void _update_presets(); void _update_text_value(); void _text_type_toggled(); void _sample_input(const Ref &p_event); @@ -97,7 +114,7 @@ class ColorPicker : public BoxContainer { void _uv_input(const Ref &p_event); void _w_input(const Ref &p_event); - void _preset_input(const Ref &p_event); + void _preset_input(const Ref &p_event, const Color &p_color); void _screen_input(const Ref &p_event); void _add_preset_pressed(); void _screen_pick_pressed(); @@ -105,6 +122,9 @@ class ColorPicker : public BoxContainer { void _focus_exit(); void _html_focus_exit(); + inline int _get_preset_size(); + void _add_preset_button(int p_size, const Color &p_color); + protected: void _notification(int); static void _bind_methods(); @@ -124,6 +144,7 @@ class ColorPicker : public BoxContainer { void add_preset(const Color &p_color); void erase_preset(const Color &p_color); PoolColorArray get_presets() const; + void _update_presets(); void set_hsv_mode(bool p_enabled); bool is_hsv_mode() const; diff --git a/scene/resources/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp index 3f4511f457ee..7435efa58580 100644 --- a/scene/resources/default_theme/default_theme.cpp +++ b/scene/resources/default_theme/default_theme.cpp @@ -256,24 +256,6 @@ void fill_default_theme(Ref &theme, const Ref &default_font, const theme->set_constant("underline_spacing", "LinkButton", 2 * scale); - // ColorPickerButton - - theme->set_stylebox("normal", "ColorPickerButton", sb_button_normal); - theme->set_stylebox("pressed", "ColorPickerButton", sb_button_pressed); - theme->set_stylebox("hover", "ColorPickerButton", sb_button_hover); - theme->set_stylebox("disabled", "ColorPickerButton", sb_button_disabled); - theme->set_stylebox("focus", "ColorPickerButton", sb_button_focus); - - theme->set_font("font", "ColorPickerButton", default_font); - - theme->set_color("font_color", "ColorPickerButton", Color(1, 1, 1, 1)); - theme->set_color("font_color_pressed", "ColorPickerButton", Color(0.8, 0.8, 0.8, 1)); - theme->set_color("font_color_hover", "ColorPickerButton", Color(1, 1, 1, 1)); - theme->set_color("font_color_focus", "ColorPickerButton", Color(1, 1, 1, 1)); - theme->set_color("font_color_disabled", "ColorPickerButton", Color(0.9, 0.9, 0.9, 0.3)); - - theme->set_constant("hseparation", "ColorPickerButton", 2 * scale); - // ToolButton theme->set_stylebox("normal", "ToolButton", make_empty_stylebox(6, 4, 6, 4)); @@ -818,7 +800,33 @@ void fill_default_theme(Ref &theme, const Ref &default_font, const theme->set_icon("preset_bg", "ColorPicker", make_icon(mini_checkerboard_png)); theme->set_icon("overbright_indicator", "ColorPicker", make_icon(overbright_indicator_png)); + // ColorPickerButton + theme->set_icon("bg", "ColorPickerButton", make_icon(mini_checkerboard_png)); + theme->set_stylebox("normal", "ColorPickerButton", sb_button_normal); + theme->set_stylebox("pressed", "ColorPickerButton", sb_button_pressed); + theme->set_stylebox("hover", "ColorPickerButton", sb_button_hover); + theme->set_stylebox("disabled", "ColorPickerButton", sb_button_disabled); + theme->set_stylebox("focus", "ColorPickerButton", sb_button_focus); + + theme->set_font("font", "ColorPickerButton", default_font); + + theme->set_color("font_color", "ColorPickerButton", Color(1, 1, 1, 1)); + theme->set_color("font_color_pressed", "ColorPickerButton", Color(0.8, 0.8, 0.8, 1)); + theme->set_color("font_color_hover", "ColorPickerButton", Color(1, 1, 1, 1)); + theme->set_color("font_color_focus", "ColorPickerButton", Color(1, 1, 1, 1)); + theme->set_color("font_color_disabled", "ColorPickerButton", Color(0.9, 0.9, 0.9, 0.3)); + + theme->set_constant("hseparation", "ColorPickerButton", 2 * scale); + + // ColorPresetButton + + Ref preset_sb = make_flat_stylebox(Color(1, 1, 1), 2, 2, 2, 2); + preset_sb->set_anti_aliased(false); + + theme->set_stylebox("preset_fg", "ColorPresetButton", preset_sb); + theme->set_icon("preset_bg_icon", "ColorPresetButton", make_icon(mini_checkerboard_png)); + theme->set_icon("overbright_indicator", "ColorPicker", make_icon(overbright_indicator_png)); // TooltipPanel