diff --git a/core/input/input_map.cpp b/core/input/input_map.cpp index bcd3b63a0352..b86fef5f9aa9 100644 --- a/core/input/input_map.cpp +++ b/core/input/input_map.cpp @@ -402,6 +402,7 @@ static const _BuiltinActionDisplayName _builtin_action_display_names[] = { { "ui_filedialog_show_hidden", TTRC("Show Hidden") }, { "ui_swap_input_direction ", TTRC("Swap Input Direction") }, { "ui_unicode_start", TTRC("Start Unicode Character Input") }, + { "ui_colorpicker_delete_preset", TTRC("Delete ColorPicker Preset") }, { "", ""} /* clang-format on */ }; @@ -425,6 +426,7 @@ const HashMap>> &InputMap::get_builtins() { } List> inputs; + inputs.push_back(InputEventJoypadButton::create_reference(JoyButton::A)); inputs.push_back(InputEventKey::create_reference(Key::ENTER)); inputs.push_back(InputEventKey::create_reference(Key::KP_ENTER)); inputs.push_back(InputEventKey::create_reference(Key::SPACE)); @@ -436,14 +438,17 @@ const HashMap>> &InputMap::get_builtins() { default_builtin_cache.insert("ui_select", inputs); inputs = List>(); + inputs.push_back(InputEventJoypadButton::create_reference(JoyButton::B)); inputs.push_back(InputEventKey::create_reference(Key::ESCAPE)); default_builtin_cache.insert("ui_cancel", inputs); inputs = List>(); + inputs.push_back(InputEventJoypadButton::create_reference(JoyButton::RIGHT_SHOULDER)); inputs.push_back(InputEventKey::create_reference(Key::TAB)); default_builtin_cache.insert("ui_focus_next", inputs); inputs = List>(); + inputs.push_back(InputEventJoypadButton::create_reference(JoyButton::LEFT_SHOULDER)); inputs.push_back(InputEventKey::create_reference(Key::TAB | KeyModifierMask::SHIFT)); default_builtin_cache.insert("ui_focus_prev", inputs); @@ -789,6 +794,12 @@ const HashMap>> &InputMap::get_builtins() { inputs.push_back(InputEventKey::create_reference(Key::QUOTELEFT | KeyModifierMask::CMD_OR_CTRL)); default_builtin_cache.insert("ui_swap_input_direction", inputs); + // ///// UI ColorPicker Shortcuts ///// + inputs = List>(); + inputs.push_back(InputEventJoypadButton::create_reference(JoyButton::X)); + inputs.push_back(InputEventKey::create_reference(Key::KEY_DELETE)); + default_builtin_cache.insert("ui_colorpicker_delete_preset", inputs); + return default_builtin_cache; } diff --git a/doc/classes/ColorPicker.xml b/doc/classes/ColorPicker.xml index 81624b1d740f..ce046e44a6af 100644 --- a/doc/classes/ColorPicker.xml +++ b/doc/classes/ColorPicker.xml @@ -141,6 +141,9 @@ + + Color of rectangle or circle drawn when a picker shape part is focused but not editable via keyboard or joypad. Displayed [i]over[/i] the picker shape, so a partially transparent color should be used to ensure the picker shape remains visible. + Overrides the [theme_item Slider.center_grabber] theme property of the sliders. @@ -204,5 +207,14 @@ The icon for rectangular wheel picker shapes. + + The [StyleBox] used when the circle-shaped part of the picker is focused. Displayed [i]over[/i] the picker shape, so a partially transparent [StyleBox] should be used to ensure the picker shape remains visible. A [StyleBox] that represents an outline or an underline works well for this purpose. To disable the focus visual effect, assign a [StyleBoxEmpty] resource. Note that disabling the focus visual effect will harm keyboard/controller navigation usability, so this is not recommended for accessibility reasons. + + + The [StyleBox] used when the rectangle-shaped part of the picker is focused. Displayed [i]over[/i] the picker shape, so a partially transparent [StyleBox] should be used to ensure the picker shape remains visible. A [StyleBox] that represents an outline or an underline works well for this purpose. To disable the focus visual effect, assign a [StyleBoxEmpty] resource. Note that disabling the focus visual effect will harm keyboard/controller navigation usability, so this is not recommended for accessibility reasons. + + + The [StyleBox] used for the old color sample part when it is focused. Displayed [i]over[/i] the sample, so a partially transparent [StyleBox] should be used to ensure the picker shape remains visible. A [StyleBox] that represents an outline or an underline works well for this purpose. To disable the focus visual effect, assign a [StyleBoxEmpty] resource. Note that disabling the focus visual effect will harm keyboard/controller navigation usability, so this is not recommended for accessibility reasons. + diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml index 6bdd24ecb83f..e8e2748165aa 100644 --- a/doc/classes/ProjectSettings.xml +++ b/doc/classes/ProjectSettings.xml @@ -1121,6 +1121,10 @@ Default [InputEventAction] to discard a modal or pending input. [b]Note:[/b] Default [code]ui_*[/code] actions cannot be removed as they are necessary for the internal logic of several [Control]s. The events assigned to the action can however be modified. + + Default [InputEventAction] to delete a color preset in a [ColorPicker]. + [b]Note:[/b] Default [code]ui_*[/code] actions cannot be removed as they are necessary for the internal logic of several [Control]s. The events assigned to the action can however be modified. + Default [InputEventAction] to copy a selection to the clipboard. [b]Note:[/b] Default [code]ui_*[/code] actions cannot be removed as they are necessary for the internal logic of several [Control]s. The events assigned to the action can however be modified. diff --git a/editor/themes/editor_theme_manager.cpp b/editor/themes/editor_theme_manager.cpp index fb7dab8d76e7..2a5ecb1ddf42 100644 --- a/editor/themes/editor_theme_manager.cpp +++ b/editor/themes/editor_theme_manager.cpp @@ -1749,6 +1749,9 @@ void EditorThemeManager::_populate_standard_styles(const Ref &p_the // ColorPicker and related nodes. { // ColorPicker. + p_config.circle_style_focus = p_config.button_style_focus->duplicate(); + p_config.circle_style_focus->set_corner_radius_all(256 * EDSCALE); + p_config.circle_style_focus->set_corner_detail(32 * EDSCALE); p_theme->set_constant("margin", "ColorPicker", p_config.base_margin); p_theme->set_constant("sv_width", "ColorPicker", 256 * EDSCALE); @@ -1757,6 +1760,11 @@ void EditorThemeManager::_populate_standard_styles(const Ref &p_the p_theme->set_constant("label_width", "ColorPicker", 10 * EDSCALE); p_theme->set_constant("center_slider_grabbers", "ColorPicker", 1); + p_theme->set_stylebox("sample_focus", "ColorPicker", p_config.button_style_focus); + p_theme->set_stylebox("picker_focus_rectangle", "ColorPicker", p_config.button_style_focus); + p_theme->set_stylebox("picker_focus_circle", "ColorPicker", p_config.circle_style_focus); + p_theme->set_color("focused_not_editing_cursor_color", "ColorPicker", p_config.highlight_color); + p_theme->set_icon("screen_picker", "ColorPicker", p_theme->get_icon(SNAME("ColorPick"), EditorStringName(EditorIcons))); p_theme->set_icon("shape_circle", "ColorPicker", p_theme->get_icon(SNAME("PickerShapeCircle"), EditorStringName(EditorIcons))); p_theme->set_icon("shape_rect", "ColorPicker", p_theme->get_icon(SNAME("PickerShapeRectangle"), EditorStringName(EditorIcons))); diff --git a/editor/themes/editor_theme_manager.h b/editor/themes/editor_theme_manager.h index ca5e1a4e2d94..78d606546f64 100644 --- a/editor/themes/editor_theme_manager.h +++ b/editor/themes/editor_theme_manager.h @@ -134,6 +134,8 @@ class EditorThemeManager { Ref button_style_pressed; Ref button_style_hover; + Ref circle_style_focus; + Ref popup_style; Ref popup_border_style; Ref window_style; diff --git a/scene/gui/color_picker.cpp b/scene/gui/color_picker.cpp index ebefa7ef4762..7b60db0a9031 100644 --- a/scene/gui/color_picker.cpp +++ b/scene/gui/color_picker.cpp @@ -69,6 +69,12 @@ void ColorPicker::_notification(int p_what) { btn_pick->set_tooltip_text(ETR("Pick a color from the application window.")); btn_pick->connect(SceneStringName(pressed), callable_mp(this, &ColorPicker::_pick_button_pressed_legacy)); } + + // In HSV Wheel shape the wheel is around the rectangle and the engine cannot automatically select + // the square while pressing ui_up to change focused control from the wheel. + wheel->set_focus_neighbor(SIDE_TOP, wheel_uv->get_path()); + wheel_uv->set_focus_neighbor(SIDE_BOTTOM, wheel->get_path()); + } break; case NOTIFICATION_TRANSLATION_CHANGED: { @@ -153,8 +159,40 @@ void ColorPicker::_notification(int p_what) { } } break; + case NOTIFICATION_FOCUS_ENTER: + case NOTIFICATION_FOCUS_EXIT: { + cursor_editing = false; + } break; + case NOTIFICATION_INTERNAL_PROCESS: { if (!is_picking_color) { + Input *input = Input::get_singleton(); + bool is_picker_focused = uv_edit->has_focus() || wheel_uv->has_focus() || wheel->has_focus(); + + if (input->is_action_just_released("ui_left") || + input->is_action_just_released("ui_right") || + input->is_action_just_released("ui_up") || + input->is_action_just_released("ui_down")) { + gamepad_event_delay_ms = DEFAULT_GAMEPAD_EVENT_DELAY_MS; + echo_multiplier = 1; + accept_event(); + set_process_internal(false); + return; + } + + gamepad_event_delay_ms -= get_process_delta_time(); + if (gamepad_event_delay_ms <= 0) { + gamepad_event_delay_ms = GAMEPAD_EVENT_REPEAT_RATE_MS + gamepad_event_delay_ms; + // Treat any input from joypad axis as -1, 0, or 1, as the value is added to Vector2i and would be lost. + Vector2 color_change_vector = Vector2( + input->is_action_pressed("ui_right") - input->is_action_pressed("ui_left"), + input->is_action_pressed("ui_down") - input->is_action_pressed("ui_up")); + if (is_picker_focused) { + _update_uv_cursor(color_change_vector, true); + } else if (w_edit->has_focus()) { + _update_w_cursor(color_change_vector.y, true); + } + } return; } DisplayServer *ds = DisplayServer::get_singleton(); @@ -180,7 +218,7 @@ void ColorPicker::_notification(int p_what) { } set_pick_color(c); - } + } break; } } @@ -277,6 +315,42 @@ void ColorPicker::set_focus_on_line_edit() { callable_mp((Control *)c_text, &Control::grab_focus).call_deferred(); } +void ColorPicker::set_focus_on_picker_shape() { + switch (_get_actual_shape()) { + case SHAPE_HSV_RECTANGLE: + callable_mp(w_edit, &Control::grab_focus).call_deferred(); + break; + case SHAPE_HSV_WHEEL: + callable_mp(wheel, &Control::grab_focus).call_deferred(); + break; + case SHAPE_VHS_CIRCLE: + case SHAPE_OKHSL_CIRCLE: + callable_mp(wheel_uv, &Control::grab_focus).call_deferred(); + break; + default: { + } + } +} + +void ColorPicker::_picker_shape_focus_entered() { + Input *input = Input::get_singleton(); + if (!(input->is_action_pressed("ui_up") || input->is_action_pressed("ui_down") || input->is_action_pressed("ui_left") || input->is_action_pressed("ui_right"))) { + cursor_editing = true; + } + + if (_get_actual_shape() == SHAPE_HSV_WHEEL) { + wheel_focus_mode = wheel->has_focus() ? 2 : 1; + } +} + +void ColorPicker::_picker_shape_focus_exited() { + cursor_editing = false; + if (wheel_focus_mode == 2) { + wheel_uv->queue_redraw(); + } + wheel_focus_mode = 0; +} + void ColorPicker::_update_controls() { int mode_sliders_count = modes[current_mode]->get_slider_count(); @@ -309,15 +383,33 @@ void ColorPicker::_update_controls() { alpha_label->hide(); } + bool pre_update_cursor_editing = cursor_editing; switch (_get_actual_shape()) { case SHAPE_HSV_RECTANGLE: - wheel_edit->hide(); w_edit->show(); uv_edit->show(); btn_shape->show(); + + if (wheel_focus_mode == 1) { + uv_edit->grab_focus(); + } else if (wheel_focus_mode == 2) { + w_edit->grab_focus(); + } + + wheel_edit->hide(); + wheel->set_focus_mode(FOCUS_NONE); break; case SHAPE_HSV_WHEEL: wheel_edit->show(); + wheel->set_focus_mode(FOCUS_ALL); + + if (w_edit->has_focus()) { + wheel_focus_mode = 2; + wheel->grab_focus(); + } else if (uv_edit->has_focus()) { + wheel_uv->grab_focus(); + } + w_edit->hide(); uv_edit->hide(); btn_shape->show(); @@ -326,20 +418,37 @@ void ColorPicker::_update_controls() { case SHAPE_VHS_CIRCLE: wheel_edit->show(); w_edit->show(); + + if (uv_edit->has_focus()) { + wheel_uv->grab_focus(); + } else if (wheel->has_focus()) { + w_edit->grab_focus(); + } + uv_edit->hide(); btn_shape->show(); wheel->set_material(circle_mat); circle_mat->set_shader(circle_shader); + wheel->set_focus_mode(FOCUS_NONE); break; case SHAPE_OKHSL_CIRCLE: wheel_edit->show(); w_edit->show(); + + if (uv_edit->has_focus()) { + wheel_uv->grab_focus(); + } else if (wheel->has_focus()) { + w_edit->grab_focus(); + } + uv_edit->hide(); btn_shape->show(); wheel->set_material(circle_mat); circle_mat->set_shader(circle_ok_color_shader); + wheel->set_focus_mode(FOCUS_NONE); break; case SHAPE_NONE: + wheel->set_focus_mode(FOCUS_NONE); wheel_edit->hide(); w_edit->hide(); uv_edit->hide(); @@ -348,6 +457,8 @@ void ColorPicker::_update_controls() { default: { } } + + cursor_editing = pre_update_cursor_editing; } void ColorPicker::_set_pick_color(const Color &p_color, bool p_update_sliders) { @@ -423,6 +534,8 @@ void ColorPicker::_slider_value_changed() { ok_hsl_h = color.get_ok_hsl_h(); ok_hsl_s = color.get_ok_hsl_s(); ok_hsl_l = color.get_ok_hsl_l(); + + circle_keyboard_joypad_picker_cursor_position = Vector2i(); last_color = color; } else if (current_mode == MODE_OKHSL) { ok_hsl_h = sliders[0]->get_value() / 360.0; @@ -431,6 +544,8 @@ void ColorPicker::_slider_value_changed() { h = color.get_h(); s = color.get_s(); v = color.get_v(); + + circle_keyboard_joypad_picker_cursor_position = Vector2i(); last_color = color; } @@ -805,6 +920,7 @@ void ColorPicker::set_picker_shape(PickerShapeType p_shape) { btn_shape->set_button_icon(shape_popup->get_item_icon(p_shape)); } + circle_keyboard_joypad_picker_cursor_position = Vector2i(); current_shape = p_shape; #ifdef TOOLS_ENABLED @@ -978,6 +1094,7 @@ void ColorPicker::_set_mode_popup_value(ColorModeType p_mode) { } else { set_color_mode(p_mode); } + circle_keyboard_joypad_picker_cursor_position = Vector2i(); } Variant ColorPicker::_get_drag_data_fw(const Point2 &p_point, Control *p_from_control) { @@ -1083,6 +1200,9 @@ void ColorPicker::erase_preset(const Color &p_color) { ColorPresetButton *current_btn = Object::cast_to(preset_container->get_child(i)); if (current_btn && p_color == current_btn->get_preset_color()) { current_btn->queue_free(); + // Removing focused control loose the focus totally. We focus on previous button to keep it possible to navigate with keyboard/joypad. + Control *focus_target = Object::cast_to(preset_container->get_child(i - 1)); + focus_target->grab_focus(); break; } } @@ -1268,21 +1388,29 @@ void ColorPicker::_sample_input(const Ref &p_event) { if (rect_old.has_point(mb->get_position())) { // Revert to the old color when left-clicking the old color sample. set_pick_color(old_color); + + sample->set_focus_mode(FOCUS_NONE); emit_signal(SNAME("color_changed"), color); } } + + if (p_event->is_action_pressed(SNAME("ui_accept"), false, true)) { + set_pick_color(old_color); + emit_signal(SNAME("color_changed"), color); + } } void ColorPicker::_sample_draw() { // Covers the right half of the sample if the old color is being displayed, // or the whole sample if it's not being displayed. Rect2 rect_new; + Rect2 rect_old; if (display_old_color) { rect_new = Rect2(Point2(sample->get_size().width * 0.5, 0), Size2(sample->get_size().width * 0.5, sample->get_size().height * 0.95)); // Draw both old and new colors for easier comparison (only if spawned from a ColorPickerButton). - const Rect2 rect_old = Rect2(Point2(), Size2(sample->get_size().width * 0.5, sample->get_size().height * 0.95)); + rect_old = Rect2(Point2(), Size2(sample->get_size().width * 0.5, sample->get_size().height * 0.95)); if (old_color.a < 1.0) { sample->draw_texture_rect(theme_cache.sample_bg, rect_old, true); @@ -1296,6 +1424,10 @@ void ColorPicker::_sample_draw() { sample->draw_texture(theme_cache.sample_revert, rect_old.size * 0.5 - theme_cache.sample_revert->get_size() * 0.5, Math::lerp(0.75f, old_color.get_luminance(), old_color.a) < 0.455 ? Color(1, 1, 1) : (Color(0.01, 0.01, 0.01))); + + sample->set_focus_mode(FOCUS_ALL); + } else { + sample->set_focus_mode(FOCUS_NONE); } if (old_color.r > 1 || old_color.g > 1 || old_color.b > 1) { @@ -1312,16 +1444,43 @@ void ColorPicker::_sample_draw() { sample->draw_rect(rect_new, color); + if (display_old_color && !old_color.is_equal_approx(color) && sample->has_focus()) { + RID ci = sample->get_canvas_item(); + theme_cache.sample_focus->draw(ci, rect_old); + } + if (color.r > 1 || color.g > 1 || color.b > 1) { // Draw an indicator to denote that the new color is "overbright" and can't be displayed accurately in the preview. sample->draw_texture(theme_cache.overbright_indicator, Point2(display_old_color ? sample->get_size().width * 0.5 : 0, 0)); } } +void ColorPicker::_draw_focus_stylebox(Control *p_c, Rect2 p_focus_rect, Ref &p_focus_stylebox) { + if (p_c->has_focus()) { + RID ci = p_c->get_canvas_item(); + if (wheel_focus_mode == 2) { + ci = wheel_uv->get_canvas_item(); + p_focus_stylebox = theme_cache.picker_focus_circle; + } + + if (!cursor_editing) { + Color not_editing_color = theme_cache.focused_not_editing_cursor_color; + if (p_focus_stylebox == theme_cache.picker_focus_circle) { + RenderingServer::get_singleton()->canvas_item_add_circle(ci, p_focus_rect.get_center(), p_focus_rect.size.y / 2, not_editing_color); + } else { + RenderingServer::get_singleton()->canvas_item_add_rect(ci, p_focus_rect, not_editing_color); + } + } + p_focus_stylebox->draw(ci, p_focus_rect); + } +} + void ColorPicker::_hsv_draw(int p_which, Control *c) { if (!c) { return; } + Rect2 focus_rect = Rect2(Point2(), c->get_size()); + Ref focus_stylebox = theme_cache.picker_focus_rectangle; PickerShapeType actual_shape = _get_actual_shape(); if (p_which == 0) { @@ -1378,6 +1537,8 @@ void ColorPicker::_hsv_draw(int p_which, Control *c) { } x = center.x + hue_offset.x - (theme_cache.picker_cursor->get_width() / 2); y = center.y + hue_offset.y - (theme_cache.picker_cursor->get_height() / 2); + + focus_stylebox = theme_cache.picker_focus_circle; } else { real_t corner_x = (c == wheel_uv) ? center.x - Math_SQRT12 * c->get_size().width * WHEEL_RADIUS : 0; real_t corner_y = (c == wheel_uv) ? center.y - Math_SQRT12 * c->get_size().height * WHEEL_RADIUS : 0; @@ -1385,7 +1546,11 @@ void ColorPicker::_hsv_draw(int p_which, Control *c) { Size2 real_size(c->get_size().x - corner_x * 2, c->get_size().y - corner_y * 2); x = CLAMP(real_size.x * s, 0, real_size.x) + corner_x - (theme_cache.picker_cursor->get_width() / 2); y = CLAMP(real_size.y - real_size.y * v, 0, real_size.y) + corner_y - (theme_cache.picker_cursor->get_height() / 2); + if (c == wheel_uv) { + focus_rect = Rect2(Point2(corner_x, corner_y), real_size); + } } + _draw_focus_stylebox(c, focus_rect, focus_stylebox); Color _col = color; _col.a = 1.0; c->draw_texture(theme_cache.picker_cursor_bg, Point2(x, y), _col); @@ -1406,6 +1571,7 @@ void ColorPicker::_hsv_draw(int p_which, Control *c) { int y = c->get_size().y - c->get_size().y * (1.0 - h); Color col; col.set_hsv(h, 1, 1); + _draw_focus_stylebox(c, focus_rect, focus_stylebox); c->draw_line(Point2(0, y), Point2(c->get_size().x, y), col.inverted()); } else if (actual_shape == SHAPE_OKHSL_CIRCLE) { Vector points; @@ -1433,6 +1599,7 @@ void ColorPicker::_hsv_draw(int p_which, Control *c) { c->draw_polygon(points, colors); int y = c->get_size().y - c->get_size().y * CLAMP(ok_hsl_l, 0, 1); col.set_ok_hsl(ok_hsl_h, 1, ok_hsl_l); + _draw_focus_stylebox(c, focus_rect, focus_stylebox); c->draw_line(Point2(0, y), Point2(c->get_size().x, y), col.inverted()); } else if (actual_shape == SHAPE_VHS_CIRCLE) { Vector points; @@ -1452,6 +1619,7 @@ void ColorPicker::_hsv_draw(int p_which, Control *c) { c->draw_polygon(points, colors); int y = c->get_size().y - c->get_size().y * CLAMP(v, 0, 1); col.set_hsv(h, 1, v); + _draw_focus_stylebox(c, focus_rect, focus_stylebox); c->draw_line(Point2(0, y), Point2(c->get_size().x, y), col.inverted()); } } else if (p_which == 2) { @@ -1461,6 +1629,10 @@ void ColorPicker::_hsv_draw(int p_which, Control *c) { } else if (actual_shape == SHAPE_OKHSL_CIRCLE) { circle_mat->set_shader_parameter("ok_hsl_l", ok_hsl_l); } + + if (wheel_focus_mode == 2) { + _draw_focus_stylebox(c, focus_rect, focus_stylebox); + } } } @@ -1470,7 +1642,154 @@ void ColorPicker::_slider_draw(int p_which) { } } +int ColorPicker::_get_edge_h_change(const Vector2 &p_color_change_vector) { + int h_change = 0; + + if (h > 0 && h < 0.5) { + h_change -= p_color_change_vector.x; + } else if (h > 0.5 && h < 1) { + h_change += p_color_change_vector.x; + } + + if (h > 0.25 && h < 0.75) { + h_change -= p_color_change_vector.y; + } else if (h < 0.25 || h > 0.75) { + h_change += p_color_change_vector.y; + } + + return h_change; +} + +float ColorPicker::_get_h_on_circle_edge(const Vector2 &p_color_change_vector) { + int h_change = _get_edge_h_change(p_color_change_vector); + + float target_h = Math::wrapf(h + h_change / 360.0, 0, 1); + int current_quarter = h * 4; + int future_quarter = target_h * 4; + if (p_color_change_vector.y > 0 && ((future_quarter == 0 && current_quarter == 1) || (future_quarter == 1 && current_quarter == 0))) { + target_h = 0.25f; + } else if (p_color_change_vector.y < 0 && ((future_quarter == 2 && current_quarter == 3) || (future_quarter == 3 && current_quarter == 2))) { + target_h = 0.75f; + } else if (p_color_change_vector.x < 0 && ((future_quarter == 1 && current_quarter == 2) || (future_quarter == 2 && current_quarter == 1))) { + target_h = 0.5f; + } else if (p_color_change_vector.x > 0 && ((future_quarter == 3 && current_quarter == 0) || (future_quarter == 0 && current_quarter == 3))) { + target_h = 0; + } + return target_h; +} + +float ColorPicker::_get_h_on_wheel(const Vector2 &p_color_change_vector) { + int h_change = _get_edge_h_change(p_color_change_vector); + + float target_h = Math::wrapf(h + h_change / 360.0, 0, 1); + int current_quarter = h * 4; + int future_quarter = target_h * 4; + + if (p_color_change_vector.y > 0 && ((future_quarter == 0 && current_quarter == 1) || (future_quarter == 1 && current_quarter == 0))) { + rotate_next_echo_event = !rotate_next_echo_event; + } else if (p_color_change_vector.y < 0 && ((future_quarter == 2 && current_quarter == 3) || (future_quarter == 3 && current_quarter == 2))) { + rotate_next_echo_event = !rotate_next_echo_event; + } else if (p_color_change_vector.x < 0 && ((future_quarter == 1 && current_quarter == 2) || (future_quarter == 2 && current_quarter == 1))) { + rotate_next_echo_event = !rotate_next_echo_event; + } else if (p_color_change_vector.x > 0 && ((future_quarter == 3 && current_quarter == 0) || (future_quarter == 0 && current_quarter == 3))) { + rotate_next_echo_event = !rotate_next_echo_event; + } + + return target_h; +} + +void ColorPicker::_update_uv_cursor(Vector2 &p_color_change_vector, bool p_is_echo) { + PickerShapeType actual_shape = _get_actual_shape(); + echo_multiplier = p_is_echo ? CLAMP(echo_multiplier * echo_multiplier_step, 1, 25) : 1; + + if (!p_color_change_vector.is_zero_approx()) { + p_color_change_vector *= echo_multiplier; + + if (actual_shape == SHAPE_HSV_RECTANGLE) { + s = CLAMP(s + p_color_change_vector.x / 100.0, 0, 1); + v = CLAMP(v - p_color_change_vector.y / 100.0, 0, 1); + } else if (actual_shape == SHAPE_VHS_CIRCLE || actual_shape == SHAPE_OKHSL_CIRCLE) { + Vector2 center = wheel_uv->get_size() / 2.0; + + if (circle_keyboard_joypad_picker_cursor_position == Vector2i()) { + Vector2 hue_offset; + if (actual_shape == SHAPE_OKHSL_CIRCLE) { + hue_offset = center * Vector2(Math::cos(ok_hsl_h * Math_TAU), Math::sin(ok_hsl_h * Math_TAU)) * ok_hsl_s; + } else { + hue_offset = center * Vector2(Math::cos(h * Math_TAU), Math::sin(h * Math_TAU)) * s; + } + circle_keyboard_joypad_picker_cursor_position = center + hue_offset; + } + + Vector2i potential_cursor_position = circle_keyboard_joypad_picker_cursor_position + p_color_change_vector; + real_t potential_new_cursor_distance = center.distance_to(potential_cursor_position); + real_t dist_pre = center.distance_to(circle_keyboard_joypad_picker_cursor_position); + if (s < 1 || potential_new_cursor_distance < dist_pre) { + circle_keyboard_joypad_picker_cursor_position += p_color_change_vector; + real_t dist = center.distance_to(circle_keyboard_joypad_picker_cursor_position); + real_t rad = center.angle_to_point(circle_keyboard_joypad_picker_cursor_position); + h = ((rad >= 0) ? rad : (Math_TAU + rad)) / Math_TAU; + s = CLAMP(dist / center.x, 0, 1); + } else { + h = _get_h_on_circle_edge(p_color_change_vector); + circle_keyboard_joypad_picker_cursor_position = Vector2i(); + } + + ok_hsl_h = h; + ok_hsl_s = s; + } else if (actual_shape == SHAPE_HSV_WHEEL) { + if (wheel_focus_mode == 1) { + s = CLAMP(s + p_color_change_vector.x / 100.0, 0, 1); + v = CLAMP(v - p_color_change_vector.y / 100.0, 0, 1); + } else if (wheel_focus_mode == 2) { + if (p_is_echo && rotate_next_echo_event) { + p_color_change_vector *= -1; + } else { + rotate_next_echo_event = false; + } + + h = _get_h_on_wheel(p_color_change_vector); + wheel_uv->queue_redraw(); + } + } + + _copy_hsv_to_color(); + last_color = color; + set_pick_color(color); + + emit_signal(SNAME("color_changed"), color); + } else { + echo_multiplier = 1; + } + + accept_event(); +} + +void ColorPicker::_update_cursor_editing(const Ref &p_event, Control *p_c) { + if (p_event->is_action_pressed("ui_accept", false, true)) { + cursor_editing = !cursor_editing; + accept_event(); + + if (wheel_focus_mode == 2) { + wheel_uv->queue_redraw(); + } + p_c->queue_redraw(); + } + + if (cursor_editing && p_event->is_action_pressed("ui_cancel", false, true)) { + cursor_editing = false; + accept_event(); + + if (wheel_focus_mode == 2) { + wheel_uv->queue_redraw(); + } + p_c->queue_redraw(); + } +} + void ColorPicker::_uv_input(const Ref &p_event, Control *c) { + _update_cursor_editing(p_event, c); + Ref bev = p_event; PickerShapeType actual_shape = _get_actual_shape(); @@ -1485,6 +1804,7 @@ void ColorPicker::_uv_input(const Ref &p_event, Control *c) { s = CLAMP(dist / center.x, 0, 1); ok_hsl_h = h; ok_hsl_s = s; + circle_keyboard_joypad_picker_cursor_position = Vector2i(); } else { return; } @@ -1497,11 +1817,12 @@ void ColorPicker::_uv_input(const Ref &p_event, Control *c) { bev->get_position().y < corner_y || bev->get_position().y > c->get_size().y - corner_y) { { real_t dist = center.distance_to(bev->get_position()); - if (dist >= center.x * 0.84 && dist <= center.x) { real_t rad = center.angle_to_point(bev->get_position()); h = ((rad >= 0) ? rad : (Math_TAU + rad)) / Math_TAU; spinning = true; + wheel->grab_focus(); + wheel_uv->queue_redraw(); } else { return; } @@ -1514,6 +1835,7 @@ void ColorPicker::_uv_input(const Ref &p_event, Control *c) { s = x / real_size.x; v = 1.0 - y / real_size.y; + wheel_focus_mode = 1; } } @@ -1554,10 +1876,12 @@ void ColorPicker::_uv_input(const Ref &p_event, Control *c) { s = CLAMP(dist / center.x, 0, 1); ok_hsl_h = h; ok_hsl_s = s; + circle_keyboard_joypad_picker_cursor_position = Vector2i(); } else { if (spinning) { real_t rad = center.angle_to_point(mev->get_position()); h = ((rad >= 0) ? rad : (Math_TAU + rad)) / Math_TAU; + wheel_uv->queue_redraw(); } else { real_t corner_x = (c == wheel_uv) ? center.x - Math_SQRT12 * c->get_size().width * 0.42 : 0; real_t corner_y = (c == wheel_uv) ? center.y - Math_SQRT12 * c->get_size().height * 0.42 : 0; @@ -1579,9 +1903,65 @@ void ColorPicker::_uv_input(const Ref &p_event, Control *c) { emit_signal(SNAME("color_changed"), color); } } + + if (!cursor_editing) { + return; + } + + Ref joypadmotion_event = p_event; + Ref joypadbutton_event = p_event; + bool is_joypad_event = (joypadmotion_event.is_valid() || joypadbutton_event.is_valid()); + bool is_echo = p_event->is_echo(); + + if (p_event->is_action_pressed("ui_left", true) || + p_event->is_action_pressed("ui_right", true) || + p_event->is_action_pressed("ui_up", true) || + p_event->is_action_pressed("ui_down", true)) { + if (is_joypad_event) { + // Make sure moving joypad axis further in the same direction is not handled here, as NOTIFICATION_INTERNAL_PROCESS will handle it. + if (is_processing_internal()) { + accept_event(); + return; + } + set_process_internal(true); + } + + // Treat any input from joypad axis as -1, 0, or 1, as the value is added to Vector2i and would be lost. + Vector2 color_change_vector = Vector2( + p_event->is_action_pressed("ui_right", true) - p_event->is_action_pressed("ui_left", true), + p_event->is_action_pressed("ui_down", true) - p_event->is_action_pressed("ui_up", true)); + _update_uv_cursor(color_change_vector, is_echo); + } +} + +void ColorPicker::_update_w_cursor(float p_color_change, bool p_is_echo) { + PickerShapeType actual_shape = _get_actual_shape(); + echo_multiplier = p_is_echo ? CLAMP(echo_multiplier * echo_multiplier_step, 1, 25) : 1; + + if (!Math::is_zero_approx(p_color_change)) { + p_color_change *= echo_multiplier; + if (actual_shape == SHAPE_HSV_RECTANGLE) { + h = CLAMP(h + p_color_change / 360.0, 0, 1); + } else if (actual_shape == SHAPE_VHS_CIRCLE || actual_shape == SHAPE_OKHSL_CIRCLE) { + v = CLAMP(v - p_color_change / 100.0, 0, 1); + ok_hsl_l = CLAMP(ok_hsl_l - p_color_change / 100.0, 0, 1); + } + + _copy_hsv_to_color(); + last_color = color; + set_pick_color(color); + + emit_signal(SNAME("color_changed"), color); + } else { + echo_multiplier = 1; + } + + accept_event(); } void ColorPicker::_w_input(const Ref &p_event) { + _update_cursor_editing(p_event, w_edit); + Ref bev = p_event; PickerShapeType actual_shape = _get_actual_shape(); @@ -1633,6 +2013,27 @@ void ColorPicker::_w_input(const Ref &p_event) { emit_signal(SNAME("color_changed"), color); } } + + if (!cursor_editing) { + return; + } + + Ref joypadmotion_event = p_event; + Ref joypadbutton_event = p_event; + bool is_joypad_event = (joypadmotion_event.is_valid() || joypadbutton_event.is_valid()); + bool is_echo = p_event->is_echo(); + + if (p_event->is_action_pressed("ui_left", true) || + p_event->is_action_pressed("ui_right", true) || + p_event->is_action_pressed("ui_up", true) || + p_event->is_action_pressed("ui_down", true)) { + if (is_joypad_event) { + set_process_internal(true); + } + + float color_change = Input::get_singleton()->get_axis("ui_up", "ui_down"); + _update_w_cursor(color_change, is_echo); + } } void ColorPicker::_slider_or_spin_input(const Ref &p_event) { @@ -1666,6 +2067,15 @@ void ColorPicker::_preset_input(const Ref &p_event, const Color &p_c emit_signal(SNAME("preset_removed"), p_color); } } + + if (p_event->is_action_pressed(SNAME("ui_accept"), false, true)) { + set_pick_color(p_color); + add_recent_preset(color); + emit_signal(SNAME("color_changed"), p_color); + } else if (p_event->is_action_pressed(SNAME("ui_colorpicker_delete_preset"), false, true) && can_add_swatches) { + erase_preset(p_color); + emit_signal(SNAME("preset_removed"), p_color); + } } void ColorPicker::_recent_preset_pressed(const bool p_pressed, ColorPresetButton *p_preset) { @@ -1996,6 +2406,7 @@ void ColorPicker::_html_focus_exit() { } else { _update_text_value(); } + circle_keyboard_joypad_picker_cursor_position = Vector2i(); } void ColorPicker::set_can_add_swatches(bool p_enabled) { @@ -2142,6 +2553,10 @@ void ColorPicker::_bind_methods() { BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, ColorPicker, h_width); BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, ColorPicker, center_slider_grabbers); + BIND_THEME_ITEM(Theme::DATA_TYPE_STYLEBOX, ColorPicker, sample_focus); + BIND_THEME_ITEM(Theme::DATA_TYPE_STYLEBOX, ColorPicker, picker_focus_rectangle); + BIND_THEME_ITEM(Theme::DATA_TYPE_STYLEBOX, ColorPicker, picker_focus_circle); + BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, ColorPicker, focused_not_editing_cursor_color); BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, ColorPicker, menu_option); BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, ColorPicker, screen_picker); @@ -2181,9 +2596,12 @@ ColorPicker::ColorPicker() { hb_edit->add_child(uv_edit); uv_edit->connect(SceneStringName(gui_input), callable_mp(this, &ColorPicker::_uv_input).bind(uv_edit)); uv_edit->set_mouse_filter(MOUSE_FILTER_PASS); + uv_edit->set_focus_mode(FOCUS_ALL); uv_edit->set_h_size_flags(SIZE_EXPAND_FILL); uv_edit->set_v_size_flags(SIZE_EXPAND_FILL); uv_edit->connect(SceneStringName(draw), callable_mp(this, &ColorPicker::_hsv_draw).bind(0, uv_edit)); + uv_edit->connect(SceneStringName(focus_entered), callable_mp(this, &ColorPicker::_picker_shape_focus_entered)); + uv_edit->connect(SceneStringName(focus_exited), callable_mp(this, &ColorPicker::_picker_shape_focus_exited)); sample_hbc = memnew(HBoxContainer); real_vbox->add_child(sample_hbc); @@ -2204,6 +2622,7 @@ ColorPicker::ColorPicker() { btn_shape->set_toggle_mode(true); btn_shape->set_tooltip_text(ETR("Select a picker shape.")); btn_shape->set_icon_alignment(HORIZONTAL_ALIGNMENT_CENTER); + btn_shape->set_focus_mode(FOCUS_ALL); current_shape = SHAPE_HSV_RECTANGLE; @@ -2228,7 +2647,7 @@ ColorPicker::ColorPicker() { for (int i = 0; i < MODE_BUTTON_COUNT; i++) { mode_btns[i] = memnew(Button); mode_hbc->add_child(mode_btns[i]); - mode_btns[i]->set_focus_mode(FOCUS_NONE); + mode_btns[i]->set_focus_mode(FOCUS_ALL); mode_btns[i]->set_h_size_flags(SIZE_EXPAND_FILL); mode_btns[i]->set_toggle_mode(true); mode_btns[i]->set_text(modes[i]->get_name()); @@ -2243,6 +2662,7 @@ ColorPicker::ColorPicker() { mode_hbc->add_child(btn_mode); btn_mode->set_toggle_mode(true); btn_mode->set_tooltip_text(ETR("Select a picker mode.")); + btn_mode->set_focus_mode(FOCUS_ALL); current_mode = MODE_RGB; @@ -2282,6 +2702,7 @@ ColorPicker::ColorPicker() { text_type->connect(SceneStringName(pressed), callable_mp(this, &ColorPicker::_text_type_toggled)); } else { text_type->set_flat(true); + text_type->set_focus_mode(FOCUS_NONE); text_type->set_mouse_filter(MOUSE_FILTER_IGNORE); } @@ -2314,18 +2735,27 @@ ColorPicker::ColorPicker() { wheel_margin->add_child(wheel); wheel->set_mouse_filter(MOUSE_FILTER_PASS); wheel->connect(SceneStringName(draw), callable_mp(this, &ColorPicker::_hsv_draw).bind(2, wheel)); + wheel->connect(SceneStringName(gui_input), callable_mp(this, &ColorPicker::_uv_input).bind(wheel)); + wheel->connect(SceneStringName(focus_entered), callable_mp(this, &ColorPicker::_picker_shape_focus_entered)); + wheel->connect(SceneStringName(focus_exited), callable_mp(this, &ColorPicker::_picker_shape_focus_exited)); wheel_uv = memnew(Control); wheel_margin->add_child(wheel_uv); + wheel_uv->set_focus_mode(FOCUS_ALL); wheel_uv->connect(SceneStringName(gui_input), callable_mp(this, &ColorPicker::_uv_input).bind(wheel_uv)); wheel_uv->connect(SceneStringName(draw), callable_mp(this, &ColorPicker::_hsv_draw).bind(0, wheel_uv)); + wheel_uv->connect(SceneStringName(focus_entered), callable_mp(this, &ColorPicker::_picker_shape_focus_entered)); + wheel_uv->connect(SceneStringName(focus_exited), callable_mp(this, &ColorPicker::_picker_shape_focus_exited)); w_edit = memnew(Control); hb_edit->add_child(w_edit); + w_edit->set_focus_mode(FOCUS_ALL); w_edit->set_h_size_flags(SIZE_FILL); w_edit->set_v_size_flags(SIZE_EXPAND_FILL); w_edit->connect(SceneStringName(gui_input), callable_mp(this, &ColorPicker::_w_input)); w_edit->connect(SceneStringName(draw), callable_mp(this, &ColorPicker::_hsv_draw).bind(1, w_edit)); + w_edit->connect(SceneStringName(focus_entered), callable_mp(this, &ColorPicker::_picker_shape_focus_entered)); + w_edit->connect(SceneStringName(focus_exited), callable_mp(this, &ColorPicker::_picker_shape_focus_exited)); _update_controls(); updating = false; @@ -2348,7 +2778,7 @@ ColorPicker::ColorPicker() { btn_preset->set_text("Swatches"); btn_preset->set_flat(true); btn_preset->set_toggle_mode(true); - btn_preset->set_focus_mode(FOCUS_NONE); + btn_preset->set_focus_mode(FOCUS_ALL); btn_preset->set_text_alignment(HORIZONTAL_ALIGNMENT_LEFT); btn_preset->set_h_size_flags(SIZE_EXPAND_FILL); btn_preset->connect(SceneStringName(toggled), callable_mp(this, &ColorPicker::_show_hide_preset).bind(btn_preset, preset_container)); @@ -2356,6 +2786,7 @@ ColorPicker::ColorPicker() { menu_btn = memnew(MenuButton); menu_btn->set_flat(true); + menu_btn->set_focus_mode(FOCUS_ALL); menu_btn->set_tooltip_text(ETR("Show all options available.")); menu_btn->connect("about_to_popup", callable_mp(this, &ColorPicker::_update_menu_items)); palette_box->add_child(menu_btn); @@ -2379,7 +2810,7 @@ ColorPicker::ColorPicker() { btn_recent_preset = memnew(Button(ETR("Recent Colors"))); btn_recent_preset->set_flat(true); btn_recent_preset->set_toggle_mode(true); - btn_recent_preset->set_focus_mode(FOCUS_NONE); + btn_recent_preset->set_focus_mode(FOCUS_ALL); btn_recent_preset->set_text_alignment(HORIZONTAL_ALIGNMENT_LEFT); btn_recent_preset->connect(SceneStringName(toggled), callable_mp(this, &ColorPicker::_show_hide_preset).bind(btn_recent_preset, recent_preset_hbc)); swatches_vbc->add_child(btn_recent_preset); @@ -2455,7 +2886,9 @@ void ColorPickerButton::pressed() { float v_offset = show_above ? -minsize.y : get_size().y; popup->set_position(get_screen_position() + Vector2(h_offset, v_offset)); popup->popup(); - if (DisplayServer::get_singleton()->has_hardware_keyboard()) { + if (!picker->is_hex_visible() && picker->get_picker_shape() != ColorPicker::SHAPE_NONE) { + callable_mp(picker, &ColorPicker::set_focus_on_picker_shape).call_deferred(); + } else if (DisplayServer::get_singleton()->has_hardware_keyboard()) { picker->set_focus_on_line_edit(); } } @@ -2615,6 +3048,12 @@ void ColorPresetButton::_notification(int p_what) { } else { WARN_PRINT("Unsupported StyleBox used for ColorPresetButton. Use StyleBoxFlat or StyleBoxTexture instead."); } + + if (has_focus()) { + RID ci = get_canvas_item(); + theme_cache.focus_style->draw(ci, Rect2(Point2(), get_size())); + } + 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(theme_cache.overbright_indicator, Vector2(0, 0)); @@ -2634,6 +3073,7 @@ Color ColorPresetButton::get_preset_color() const { void ColorPresetButton::_bind_methods() { BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_STYLEBOX, ColorPresetButton, foreground_style, "preset_fg"); + BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_STYLEBOX, ColorPresetButton, focus_style, "preset_focus"); BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_ICON, ColorPresetButton, background_icon, "preset_bg"); BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, ColorPresetButton, overbright_indicator); } diff --git a/scene/gui/color_picker.h b/scene/gui/color_picker.h index 9266a280eb48..2428b8d6fa93 100644 --- a/scene/gui/color_picker.h +++ b/scene/gui/color_picker.h @@ -58,6 +58,7 @@ class ColorPresetButton : public BaseButton { struct ThemeCache { Ref foreground_style; + Ref focus_style; Ref background_icon; Ref overbright_indicator; @@ -126,6 +127,16 @@ class ColorPicker : public VBoxContainer { #endif int current_slider_count = SLIDER_COUNT; + Vector2i circle_keyboard_joypad_picker_cursor_position; + float echo_multiplier = 1; + float echo_multiplier_step = 1.1; + bool rotate_next_echo_event = false; + + const float DEFAULT_GAMEPAD_EVENT_DELAY_MS = 1.0 / 2; + const float GAMEPAD_EVENT_REPEAT_RATE_MS = 1.0 / 30; + float gamepad_event_delay_ms = DEFAULT_GAMEPAD_EVENT_DELAY_MS; + bool cursor_editing = false; + int wheel_focus_mode = 0; static const int MODE_BUTTON_COUNT = 3; const float WHEEL_RADIUS = 0.42; @@ -250,6 +261,9 @@ class ColorPicker : public VBoxContainer { bool center_slider_grabbers = true; + Ref picker_focus_rectangle; + Ref picker_focus_circle; + Color focused_not_editing_cursor_color; Ref menu_option; Ref screen_picker; Ref expanded_arrow; @@ -263,6 +277,7 @@ class ColorPicker : public VBoxContainer { Ref bar_arrow; Ref sample_bg; Ref sample_revert; + Ref sample_focus; Ref overbright_indicator; Ref picker_cursor; Ref picker_cursor_bg; @@ -290,10 +305,17 @@ class ColorPicker : public VBoxContainer { void _text_type_toggled(); void _sample_input(const Ref &p_event); void _sample_draw(); + void _draw_focus_stylebox(Control *p_c, Rect2 p_focus_rect, Ref &p_focus_stylebox); void _hsv_draw(int p_which, Control *c); void _slider_draw(int p_which); + int _get_edge_h_change(const Vector2 &p_color_change_vector); + float _get_h_on_circle_edge(const Vector2 &p_color_change_vector); + float _get_h_on_wheel(const Vector2 &p_color_change_vector); + void _update_uv_cursor(Vector2 &p_color_change_vector, bool p_is_echo); + void _update_cursor_editing(const Ref &p_event, Control *p_c); void _uv_input(const Ref &p_event, Control *c); + void _update_w_cursor(float p_color_change, bool p_is_echo); void _w_input(const Ref &p_event); void _slider_or_spin_input(const Ref &p_event); void _line_edit_input(const Ref &p_event); @@ -404,7 +426,10 @@ class ColorPicker : public VBoxContainer { bool is_hex_visible() const; void set_focus_on_line_edit(); + void set_focus_on_picker_shape(); + void _picker_shape_focus_entered(); + void _picker_shape_focus_exited(); ColorPicker(); ~ColorPicker(); }; diff --git a/scene/theme/default_theme.cpp b/scene/theme/default_theme.cpp index 5ae1e9baa37d..ee4514e03b35 100644 --- a/scene/theme/default_theme.cpp +++ b/scene/theme/default_theme.cpp @@ -1032,6 +1032,9 @@ void fill_default_theme(Ref &theme, const Ref &default_font, const theme->set_constant("separation", "VSeparator", Math::round(4 * scale)); // ColorPicker + Ref focus_circle = make_flat_stylebox(style_focus_color, default_margin, default_margin, default_margin, default_margin, default_corner_radius, false, 2); + focus_circle->set_corner_radius_all(Math::round(256 * scale)); + focus_circle->set_corner_detail(Math::round(32 * scale)); theme->set_constant("margin", "ColorPicker", Math::round(4 * scale)); theme->set_constant("sv_width", "ColorPicker", Math::round(256 * scale)); @@ -1040,6 +1043,11 @@ void fill_default_theme(Ref &theme, const Ref &default_font, const theme->set_constant("label_width", "ColorPicker", Math::round(10 * scale)); theme->set_constant("center_slider_grabbers", "ColorPicker", 1); + theme->set_stylebox("sample_focus", "ColorPicker", focus); + theme->set_stylebox("picker_focus_rectangle", "ColorPicker", focus); + theme->set_stylebox("picker_focus_circle", "ColorPicker", focus_circle); + theme->set_color("focused_not_editing_cursor_color", "ColorPicker", Color(1, 1, 1, 0.275f)); + theme->set_icon("menu_option", "ColorPicker", icons["tabs_menu_hl"]); theme->set_icon("folded_arrow", "ColorPicker", icons["arrow_right"]); theme->set_icon("expanded_arrow", "ColorPicker", icons["arrow_down"]); @@ -1112,6 +1120,7 @@ void fill_default_theme(Ref &theme, const Ref &default_font, const preset_sb->set_anti_aliased(false); theme->set_stylebox("preset_fg", "ColorPresetButton", preset_sb); + theme->set_stylebox("preset_focus", "ColorPicker", focus); theme->set_icon("preset_bg", "ColorPresetButton", icons["mini_checkerboard"]); theme->set_icon("overbright_indicator", "ColorPresetButton", icons["color_picker_overbright"]);