diff options
Diffstat (limited to 'scene/gui')
-rw-r--r-- | scene/gui/base_button.cpp | 19 | ||||
-rw-r--r-- | scene/gui/base_button.h | 5 | ||||
-rw-r--r-- | scene/gui/code_edit.cpp | 19 | ||||
-rw-r--r-- | scene/gui/code_edit.h | 1 | ||||
-rw-r--r-- | scene/gui/color_mode.cpp | 8 | ||||
-rw-r--r-- | scene/gui/color_picker.cpp | 141 | ||||
-rw-r--r-- | scene/gui/color_picker.h | 27 | ||||
-rw-r--r-- | scene/gui/flow_container.cpp | 41 | ||||
-rw-r--r-- | scene/gui/flow_container.h | 13 | ||||
-rw-r--r-- | scene/gui/scroll_container.cpp | 107 | ||||
-rw-r--r-- | scene/gui/tab_container.cpp | 8 | ||||
-rw-r--r-- | scene/gui/tab_container.h | 2 | ||||
-rw-r--r-- | scene/gui/text_edit.cpp | 30 | ||||
-rw-r--r-- | scene/gui/text_edit.h | 1 |
14 files changed, 330 insertions, 92 deletions
diff --git a/scene/gui/base_button.cpp b/scene/gui/base_button.cpp index ca2ab8bd2b..ac9034c6fd 100644 --- a/scene/gui/base_button.cpp +++ b/scene/gui/base_button.cpp @@ -127,6 +127,7 @@ void BaseButton::_notification(int p_what) { status.hovering = false; status.press_attempt = false; status.pressing_inside = false; + status.shortcut_press = false; } break; } } @@ -160,6 +161,7 @@ void BaseButton::on_action_event(Ref<InputEvent> p_event) { if (action_mode == ACTION_MODE_BUTTON_PRESS) { status.press_attempt = false; status.pressing_inside = false; + status.shortcut_press = false; } status.pressed = !status.pressed; _unpress_group(); @@ -185,6 +187,7 @@ void BaseButton::on_action_event(Ref<InputEvent> p_event) { } status.press_attempt = false; status.pressing_inside = false; + status.shortcut_press = false; emit_signal(SNAME("button_up")); } @@ -209,6 +212,7 @@ void BaseButton::set_disabled(bool p_disabled) { } status.press_attempt = false; status.pressing_inside = false; + status.shortcut_press = false; } queue_redraw(); } @@ -281,7 +285,7 @@ BaseButton::DrawMode BaseButton::get_draw_mode() const { pressing = status.pressed; } - if (pressing) { + if ((shortcut_feedback || !status.shortcut_press) && pressing) { return DRAW_PRESSED; } else { return DRAW_NORMAL; @@ -347,6 +351,7 @@ void BaseButton::shortcut_input(const Ref<InputEvent> &p_event) { ERR_FAIL_COND(p_event.is_null()); if (!is_disabled() && is_visible_in_tree() && !p_event->is_echo() && shortcut.is_valid() && shortcut->matches_event(p_event)) { + status.shortcut_press = true; on_action_event(p_event); accept_event(); } @@ -386,6 +391,14 @@ bool BaseButton::_was_pressed_by_mouse() const { return was_mouse_pressed; } +void BaseButton::set_shortcut_feedback(bool p_feedback) { + shortcut_feedback = p_feedback; +} + +bool BaseButton::is_shortcut_feedback() const { + return shortcut_feedback; +} + void BaseButton::_bind_methods() { ClassDB::bind_method(D_METHOD("set_pressed", "pressed"), &BaseButton::set_pressed); ClassDB::bind_method(D_METHOD("is_pressed"), &BaseButton::is_pressed); @@ -411,6 +424,9 @@ void BaseButton::_bind_methods() { ClassDB::bind_method(D_METHOD("set_button_group", "button_group"), &BaseButton::set_button_group); ClassDB::bind_method(D_METHOD("get_button_group"), &BaseButton::get_button_group); + ClassDB::bind_method(D_METHOD("set_shortcut_feedback", "enabled"), &BaseButton::set_shortcut_feedback); + ClassDB::bind_method(D_METHOD("is_shortcut_feedback"), &BaseButton::is_shortcut_feedback); + GDVIRTUAL_BIND(_pressed); GDVIRTUAL_BIND(_toggled, "button_pressed"); @@ -427,6 +443,7 @@ void BaseButton::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "button_mask", PROPERTY_HINT_FLAGS, "Mouse Left, Mouse Right, Mouse Middle"), "set_button_mask", "get_button_mask"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "keep_pressed_outside"), "set_keep_pressed_outside", "is_keep_pressed_outside"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "shortcut", PROPERTY_HINT_RESOURCE_TYPE, "Shortcut"), "set_shortcut", "get_shortcut"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "shortcut_feedback"), "set_shortcut_feedback", "is_shortcut_feedback"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "button_group", PROPERTY_HINT_RESOURCE_TYPE, "ButtonGroup"), "set_button_group", "get_button_group"); BIND_ENUM_CONSTANT(DRAW_NORMAL); diff --git a/scene/gui/base_button.h b/scene/gui/base_button.h index 7839239800..3acf535f54 100644 --- a/scene/gui/base_button.h +++ b/scene/gui/base_button.h @@ -53,6 +53,7 @@ private: bool keep_pressed_outside = false; Ref<Shortcut> shortcut; ObjectID shortcut_context; + bool shortcut_feedback = true; ActionMode action_mode = ACTION_MODE_BUTTON_RELEASE; struct Status { @@ -60,6 +61,7 @@ private: bool hovering = false; bool press_attempt = false; bool pressing_inside = false; + bool shortcut_press = false; bool disabled = false; @@ -131,6 +133,9 @@ public: void set_button_group(const Ref<ButtonGroup> &p_group); Ref<ButtonGroup> get_button_group() const; + void set_shortcut_feedback(bool p_feedback); + bool is_shortcut_feedback() const; + BaseButton(); ~BaseButton(); }; diff --git a/scene/gui/code_edit.cpp b/scene/gui/code_edit.cpp index f61fa29a33..5f8f25154c 100644 --- a/scene/gui/code_edit.cpp +++ b/scene/gui/code_edit.cpp @@ -138,7 +138,7 @@ void CodeEdit::_notification(int p_what) { code_completion_scroll_rect.position = code_completion_rect.position + Vector2(code_completion_rect.size.width, 0); code_completion_scroll_rect.size = Vector2(scroll_width, code_completion_rect.size.height); - code_completion_line_ofs = CLAMP(code_completion_current_selected - lines / 2, 0, code_completion_options_count - lines); + code_completion_line_ofs = CLAMP((code_completion_force_item_center < 0 ? code_completion_current_selected : code_completion_force_item_center) - lines / 2, 0, code_completion_options_count - lines); RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2(code_completion_rect.position.x, code_completion_rect.position.y + (code_completion_current_selected - code_completion_line_ofs) * row_height), Size2(code_completion_rect.size.width, row_height)), code_completion_selected_color); for (int i = 0; i < lines; i++) { @@ -281,16 +281,22 @@ void CodeEdit::gui_input(const Ref<InputEvent> &p_gui_input) { case MouseButton::WHEEL_UP: { if (code_completion_current_selected > 0) { code_completion_current_selected--; + code_completion_force_item_center = -1; queue_redraw(); } } break; case MouseButton::WHEEL_DOWN: { if (code_completion_current_selected < code_completion_options.size() - 1) { code_completion_current_selected++; + code_completion_force_item_center = -1; queue_redraw(); } } break; case MouseButton::LEFT: { + if (code_completion_force_item_center == -1) { + code_completion_force_item_center = code_completion_current_selected; + } + code_completion_current_selected = CLAMP(code_completion_line_ofs + (mb->get_position().y - code_completion_rect.position.y) / get_line_height(), 0, code_completion_options.size() - 1); if (mb->is_double_click()) { confirm_code_completion(); @@ -300,6 +306,7 @@ void CodeEdit::gui_input(const Ref<InputEvent> &p_gui_input) { default: break; } + return; } else if (code_completion_active && code_completion_scroll_rect.has_point(mb->get_position())) { if (mb->get_button_index() != MouseButton::LEFT) { @@ -448,6 +455,7 @@ void CodeEdit::gui_input(const Ref<InputEvent> &p_gui_input) { } else { code_completion_current_selected = code_completion_options.size() - 1; } + code_completion_force_item_center = -1; queue_redraw(); accept_event(); return; @@ -458,30 +466,35 @@ void CodeEdit::gui_input(const Ref<InputEvent> &p_gui_input) { } else { code_completion_current_selected = 0; } + code_completion_force_item_center = -1; queue_redraw(); accept_event(); return; } if (k->is_action("ui_page_up", true)) { code_completion_current_selected = MAX(0, code_completion_current_selected - code_completion_max_lines); + code_completion_force_item_center = -1; queue_redraw(); accept_event(); return; } if (k->is_action("ui_page_down", true)) { code_completion_current_selected = MIN(code_completion_options.size() - 1, code_completion_current_selected + code_completion_max_lines); + code_completion_force_item_center = -1; queue_redraw(); accept_event(); return; } if (k->is_action("ui_home", true)) { code_completion_current_selected = 0; + code_completion_force_item_center = -1; queue_redraw(); accept_event(); return; } if (k->is_action("ui_end", true)) { code_completion_current_selected = code_completion_options.size() - 1; + code_completion_force_item_center = -1; queue_redraw(); accept_event(); return; @@ -1978,6 +1991,7 @@ void CodeEdit::set_code_completion_selected_index(int p_index) { } ERR_FAIL_INDEX(p_index, code_completion_options.size()); code_completion_current_selected = p_index; + code_completion_force_item_center = -1; queue_redraw(); } @@ -2808,6 +2822,7 @@ void CodeEdit::_update_scroll_selected_line(float p_mouse_y) { percent = CLAMP(percent, 0.0f, 1.0f); code_completion_current_selected = (int)(percent * (code_completion_options.size() - 1)); + code_completion_force_item_center = -1; } void CodeEdit::_filter_code_completion_candidates_impl() { @@ -2867,6 +2882,7 @@ void CodeEdit::_filter_code_completion_candidates_impl() { code_completion_longest_line = MIN(max_width, code_completion_max_width * font_size); code_completion_current_selected = 0; + code_completion_force_item_center = -1; code_completion_active = true; queue_redraw(); return; @@ -3123,6 +3139,7 @@ void CodeEdit::_filter_code_completion_candidates_impl() { code_completion_longest_line = MIN(max_width, code_completion_max_width * font_size); code_completion_current_selected = 0; + code_completion_force_item_center = -1; code_completion_active = true; queue_redraw(); } diff --git a/scene/gui/code_edit.h b/scene/gui/code_edit.h index 09c7ef80bf..cbbc13480e 100644 --- a/scene/gui/code_edit.h +++ b/scene/gui/code_edit.h @@ -214,6 +214,7 @@ private: Vector<ScriptLanguage::CodeCompletionOption> code_completion_options; int code_completion_line_ofs = 0; int code_completion_current_selected = 0; + int code_completion_force_item_center = -1; int code_completion_longest_line = 0; Rect2i code_completion_rect; Rect2i code_completion_scroll_rect; diff --git a/scene/gui/color_mode.cpp b/scene/gui/color_mode.cpp index a063cd344a..308fe057c5 100644 --- a/scene/gui/color_mode.cpp +++ b/scene/gui/color_mode.cpp @@ -158,8 +158,7 @@ void ColorModeHSV::slider_draw(int p_which) { 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 * -1, 0), Vector2(margin, size.x)), false); + slider->draw_texture_rect(hue, Rect2(Vector2(), Vector2(size.x, margin)), false); return; } else { Color s_col; @@ -289,9 +288,8 @@ void ColorModeOKHSL::slider_draw(int p_which) { const real_t margin = 16 * color_picker->get_theme_default_base_scale(); if (p_which == 0) { // H - 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 * -1, 0), Vector2(margin, size.x)), false); + Ref<Texture2D> hue = color_picker->get_theme_icon(SNAME("color_okhsl_hue"), SNAME("ColorPicker")); + slider->draw_texture_rect(hue, Rect2(Vector2(), Vector2(size.x, margin)), false); return; } diff --git a/scene/gui/color_picker.cpp b/scene/gui/color_picker.cpp index 1b87c1d709..724e5bcaf6 100644 --- a/scene/gui/color_picker.cpp +++ b/scene/gui/color_picker.cpp @@ -253,18 +253,20 @@ void ColorPicker::_update_controls() { wheel_edit->hide(); w_edit->show(); uv_edit->show(); + btn_shape->show(); break; case SHAPE_HSV_WHEEL: wheel_edit->show(); w_edit->hide(); uv_edit->hide(); - + btn_shape->show(); wheel->set_material(wheel_mat); break; case SHAPE_VHS_CIRCLE: wheel_edit->show(); w_edit->show(); uv_edit->hide(); + btn_shape->show(); wheel->set_material(circle_mat); circle_mat->set_shader(circle_shader); break; @@ -272,9 +274,16 @@ void ColorPicker::_update_controls() { wheel_edit->show(); w_edit->show(); uv_edit->hide(); + btn_shape->show(); wheel->set_material(circle_mat); circle_mat->set_shader(circle_ok_color_shader); break; + case SHAPE_NONE: + wheel_edit->hide(); + w_edit->hide(); + uv_edit->hide(); + btn_shape->hide(); + break; default: { } } @@ -606,10 +615,13 @@ void ColorPicker::set_picker_shape(PickerShapeType p_shape) { if (p_shape == current_shape) { return; } - shape_popup->set_item_checked(current_shape, false); - shape_popup->set_item_checked(p_shape, true); - - btn_shape->set_icon(shape_popup->get_item_icon(p_shape)); + if (current_shape != SHAPE_NONE) { + shape_popup->set_item_checked(current_shape, false); + } + if (p_shape != SHAPE_NONE) { + shape_popup->set_item_checked(p_shape, true); + btn_shape->set_icon(shape_popup->get_item_icon(p_shape)); + } current_shape = p_shape; @@ -1331,7 +1343,7 @@ void ColorPicker::_preset_input(const Ref<InputEvent> &p_event, const Color &p_c set_pick_color(p_color); add_recent_preset(color); emit_signal(SNAME("color_changed"), p_color); - } else if (bev->is_pressed() && bev->get_button_index() == MouseButton::RIGHT && presets_enabled) { + } else if (bev->is_pressed() && bev->get_button_index() == MouseButton::RIGHT && can_add_swatches) { erase_preset(p_color); emit_signal(SNAME("preset_removed"), p_color); } @@ -1421,11 +1433,11 @@ void ColorPicker::_html_focus_exit() { _html_submitted(c_text->get_text()); } -void ColorPicker::set_presets_enabled(bool p_enabled) { - if (presets_enabled == p_enabled) { +void ColorPicker::set_can_add_swatches(bool p_enabled) { + if (can_add_swatches == p_enabled) { return; } - presets_enabled = p_enabled; + can_add_swatches = p_enabled; if (!p_enabled) { btn_add_preset->set_disabled(true); btn_add_preset->set_focus_mode(FOCUS_NONE); @@ -1435,8 +1447,8 @@ void ColorPicker::set_presets_enabled(bool p_enabled) { } } -bool ColorPicker::are_presets_enabled() const { - return presets_enabled; +bool ColorPicker::are_swatches_enabled() const { + return can_add_swatches; } void ColorPicker::set_presets_visible(bool p_visible) { @@ -1444,13 +1456,62 @@ void ColorPicker::set_presets_visible(bool p_visible) { return; } presets_visible = p_visible; - preset_container->set_visible(p_visible); + btn_preset->set_visible(p_visible); + btn_recent_preset->set_visible(p_visible); } bool ColorPicker::are_presets_visible() const { return presets_visible; } +void ColorPicker::set_modes_visible(bool p_visible) { + if (color_modes_visible == p_visible) { + return; + } + color_modes_visible = p_visible; + mode_hbc->set_visible(p_visible); +} + +bool ColorPicker::are_modes_visible() const { + return color_modes_visible; +} + +void ColorPicker::set_sampler_visible(bool p_visible) { + if (sampler_visible == p_visible) { + return; + } + sampler_visible = p_visible; + sample_hbc->set_visible(p_visible); +} + +bool ColorPicker::is_sampler_visible() const { + return sampler_visible; +} + +void ColorPicker::set_sliders_visible(bool p_visible) { + if (sliders_visible == p_visible) { + return; + } + sliders_visible = p_visible; + slider_gc->set_visible(p_visible); +} + +bool ColorPicker::are_sliders_visible() const { + return sliders_visible; +} + +void ColorPicker::set_hex_visible(bool p_visible) { + if (hex_visible == p_visible) { + return; + } + hex_visible = p_visible; + hex_hbc->set_visible(p_visible); +} + +bool ColorPicker::is_hex_visible() const { + return hex_visible; +} + 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); @@ -1460,10 +1521,18 @@ void ColorPicker::_bind_methods() { 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); - ClassDB::bind_method(D_METHOD("are_presets_enabled"), &ColorPicker::are_presets_enabled); + ClassDB::bind_method(D_METHOD("set_can_add_swatches", "enabled"), &ColorPicker::set_can_add_swatches); + ClassDB::bind_method(D_METHOD("are_swatches_enabled"), &ColorPicker::are_swatches_enabled); ClassDB::bind_method(D_METHOD("set_presets_visible", "visible"), &ColorPicker::set_presets_visible); ClassDB::bind_method(D_METHOD("are_presets_visible"), &ColorPicker::are_presets_visible); + ClassDB::bind_method(D_METHOD("set_modes_visible", "visible"), &ColorPicker::set_modes_visible); + ClassDB::bind_method(D_METHOD("are_modes_visible"), &ColorPicker::are_modes_visible); + ClassDB::bind_method(D_METHOD("set_sampler_visible", "visible"), &ColorPicker::set_sampler_visible); + ClassDB::bind_method(D_METHOD("is_sampler_visible"), &ColorPicker::is_sampler_visible); + ClassDB::bind_method(D_METHOD("set_sliders_visible", "visible"), &ColorPicker::set_sliders_visible); + ClassDB::bind_method(D_METHOD("are_sliders_visible"), &ColorPicker::are_sliders_visible); + ClassDB::bind_method(D_METHOD("set_hex_visible", "visible"), &ColorPicker::set_hex_visible); + ClassDB::bind_method(D_METHOD("is_hex_visible"), &ColorPicker::is_hex_visible); 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); @@ -1481,8 +1550,13 @@ void ColorPicker::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "edit_alpha"), "set_edit_alpha", "is_editing_alpha"); 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"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "picker_shape", PROPERTY_HINT_ENUM, "HSV Rectangle,HSV Rectangle Wheel,VHS Circle,OKHSL Circle,None"), "set_picker_shape", "get_picker_shape"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "can_add_swatches"), "set_can_add_swatches", "are_swatches_enabled"); + ADD_GROUP("Customization", ""); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sampler_visible"), "set_sampler_visible", "is_sampler_visible"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "color_modes_visible"), "set_modes_visible", "are_modes_visible"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sliders_visible"), "set_sliders_visible", "are_sliders_visible"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "hex_visible"), "set_hex_visible", "is_hex_visible"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "presets_visible"), "set_presets_visible", "are_presets_visible"); ADD_SIGNAL(MethodInfo("color_changed", PropertyInfo(Variant::COLOR, "color"))); @@ -1498,6 +1572,7 @@ void ColorPicker::_bind_methods() { BIND_ENUM_CONSTANT(SHAPE_HSV_WHEEL); BIND_ENUM_CONSTANT(SHAPE_VHS_CIRCLE); BIND_ENUM_CONSTANT(SHAPE_OKHSL_CIRCLE); + BIND_ENUM_CONSTANT(SHAPE_NONE); } ColorPicker::ColorPicker() : @@ -1514,24 +1589,24 @@ ColorPicker::ColorPicker() : uv_edit->set_v_size_flags(SIZE_EXPAND_FILL); uv_edit->connect("draw", callable_mp(this, &ColorPicker::_hsv_draw).bind(0, uv_edit)); - HBoxContainer *hb_smpl = memnew(HBoxContainer); - add_child(hb_smpl, false, INTERNAL_MODE_FRONT); + sample_hbc = memnew(HBoxContainer); + add_child(sample_hbc, false, INTERNAL_MODE_FRONT); btn_pick = memnew(Button); - hb_smpl->add_child(btn_pick); + sample_hbc->add_child(btn_pick); btn_pick->set_toggle_mode(true); btn_pick->set_tooltip_text(RTR("Pick a color from the editor window.")); btn_pick->connect("pressed", callable_mp(this, &ColorPicker::_screen_pick_pressed)); sample = memnew(TextureRect); - hb_smpl->add_child(sample); + sample_hbc->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_shape = memnew(MenuButton); btn_shape->set_flat(false); - hb_smpl->add_child(btn_shape); + sample_hbc->add_child(btn_shape); btn_shape->set_toggle_mode(true); btn_shape->set_tooltip_text(RTR("Select a picker shape.")); @@ -1552,7 +1627,7 @@ ColorPicker::ColorPicker() : add_mode(new ColorModeRAW(this)); add_mode(new ColorModeOKHSL(this)); - HBoxContainer *mode_hbc = memnew(HBoxContainer); + mode_hbc = memnew(HBoxContainer); add_child(mode_hbc, false, INTERNAL_MODE_FRONT); mode_group.instantiate(); @@ -1598,26 +1673,26 @@ ColorPicker::ColorPicker() : add_child(vbr, false, INTERNAL_MODE_FRONT); vbr->set_h_size_flags(SIZE_EXPAND_FILL); - GridContainer *gc = memnew(GridContainer); + slider_gc = memnew(GridContainer); - vbr->add_child(gc); - gc->set_h_size_flags(SIZE_EXPAND_FILL); - gc->set_columns(3); + vbr->add_child(slider_gc); + slider_gc->set_h_size_flags(SIZE_EXPAND_FILL); + slider_gc->set_columns(3); for (int i = 0; i < SLIDER_COUNT + 1; i++) { - create_slider(gc, i); + create_slider(slider_gc, i); } alpha_label->set_text("A"); - HBoxContainer *hhb = memnew(HBoxContainer); - hhb->set_alignment(ALIGNMENT_BEGIN); - vbr->add_child(hhb); + hex_hbc = memnew(HBoxContainer); + hex_hbc->set_alignment(ALIGNMENT_BEGIN); + vbr->add_child(hex_hbc); - hhb->add_child(memnew(Label("Hex"))); + hex_hbc->add_child(memnew(Label("Hex"))); text_type = memnew(Button); - hhb->add_child(text_type); + hex_hbc->add_child(text_type); text_type->set_text("#"); text_type->set_tooltip_text(RTR("Switch between hexadecimal and code values.")); if (Engine::get_singleton()->is_editor_hint()) { @@ -1628,7 +1703,7 @@ ColorPicker::ColorPicker() : } c_text = memnew(LineEdit); - hhb->add_child(c_text); + hex_hbc->add_child(c_text); c_text->set_select_all_on_focus(true); c_text->connect("text_submitted", callable_mp(this, &ColorPicker::_html_submitted)); c_text->connect("text_changed", callable_mp(this, &ColorPicker::_text_changed)); diff --git a/scene/gui/color_picker.h b/scene/gui/color_picker.h index a0843d6fa2..3208676539 100644 --- a/scene/gui/color_picker.h +++ b/scene/gui/color_picker.h @@ -86,6 +86,7 @@ public: SHAPE_HSV_WHEEL, SHAPE_VHS_CIRCLE, SHAPE_OKHSL_CIRCLE, + SHAPE_NONE, SHAPE_MAX }; @@ -125,6 +126,10 @@ private: PopupMenu *shape_popup = nullptr; PopupMenu *mode_popup = nullptr; MenuButton *btn_shape = nullptr; + HBoxContainer *mode_hbc = nullptr; + HBoxContainer *sample_hbc = nullptr; + GridContainer *slider_gc = nullptr; + HBoxContainer *hex_hbc = nullptr; MenuButton *btn_mode = nullptr; Button *mode_btns[MODE_BUTTON_COUNT]; Ref<ButtonGroup> mode_group = nullptr; @@ -165,8 +170,12 @@ private: bool updating = true; bool changing_color = false; bool spinning = false; - bool presets_enabled = true; + bool can_add_swatches = true; bool presets_visible = true; + bool color_modes_visible = true; + bool sampler_visible = true; + bool sliders_visible = true; + bool hex_visible = true; bool line_edit_mouse_release = false; bool text_changed = false; @@ -267,12 +276,24 @@ public: void set_deferred_mode(bool p_enabled); bool is_deferred_mode() const; - void set_presets_enabled(bool p_enabled); - bool are_presets_enabled() const; + void set_can_add_swatches(bool p_enabled); + bool are_swatches_enabled() const; void set_presets_visible(bool p_visible); bool are_presets_visible() const; + void set_modes_visible(bool p_visible); + bool are_modes_visible() const; + + void set_sampler_visible(bool p_visible); + bool is_sampler_visible() const; + + void set_sliders_visible(bool p_visible); + bool are_sliders_visible() const; + + void set_hex_visible(bool p_visible); + bool is_hex_visible() const; + void set_focus_on_line_edit(); ColorPicker(); diff --git a/scene/gui/flow_container.cpp b/scene/gui/flow_container.cpp index b0d15aa7f4..44c5ec62f8 100644 --- a/scene/gui/flow_container.cpp +++ b/scene/gui/flow_container.cpp @@ -152,6 +152,28 @@ void FlowContainer::_resort() { line_data = lines_data[current_line_idx]; } + // The first child of each line adds the offset caused by the alignment, + // but only if the line doesn't contain a child that expands. + if (child_idx_in_line == 0 && Math::is_equal_approx(line_data.stretch_ratio_total, 0)) { + int alignment_ofs = 0; + switch (alignment) { + case ALIGNMENT_CENTER: + alignment_ofs = line_data.stretch_avail / 2; + break; + case ALIGNMENT_END: + alignment_ofs = line_data.stretch_avail; + break; + default: + break; + } + + if (vertical) { /* VERTICAL */ + ofs.y += alignment_ofs; + } else { /* HORIZONTAL */ + ofs.x += alignment_ofs; + } + } + if (vertical) { /* VERTICAL */ if (child->get_h_size_flags() & (SIZE_FILL | SIZE_SHRINK_CENTER | SIZE_SHRINK_END)) { child_size.width = line_data.min_line_height; @@ -282,6 +304,18 @@ int FlowContainer::get_line_count() const { return cached_line_count; } +void FlowContainer::set_alignment(AlignmentMode p_alignment) { + if (alignment == p_alignment) { + return; + } + alignment = p_alignment; + _resort(); +} + +FlowContainer::AlignmentMode FlowContainer::get_alignment() const { + return alignment; +} + void FlowContainer::set_vertical(bool p_vertical) { ERR_FAIL_COND_MSG(is_fixed, "Can't change orientation of " + get_class() + "."); vertical = p_vertical; @@ -300,8 +334,15 @@ FlowContainer::FlowContainer(bool p_vertical) { void FlowContainer::_bind_methods() { ClassDB::bind_method(D_METHOD("get_line_count"), &FlowContainer::get_line_count); + ClassDB::bind_method(D_METHOD("set_alignment", "alignment"), &FlowContainer::set_alignment); + ClassDB::bind_method(D_METHOD("get_alignment"), &FlowContainer::get_alignment); ClassDB::bind_method(D_METHOD("set_vertical", "vertical"), &FlowContainer::set_vertical); ClassDB::bind_method(D_METHOD("is_vertical"), &FlowContainer::is_vertical); + BIND_ENUM_CONSTANT(ALIGNMENT_BEGIN); + BIND_ENUM_CONSTANT(ALIGNMENT_CENTER); + BIND_ENUM_CONSTANT(ALIGNMENT_END); + + ADD_PROPERTY(PropertyInfo(Variant::INT, "alignment", PROPERTY_HINT_ENUM, "Begin,Center,End"), "set_alignment", "get_alignment"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "vertical"), "set_vertical", "is_vertical"); } diff --git a/scene/gui/flow_container.h b/scene/gui/flow_container.h index 536df27ad6..6a61e9b904 100644 --- a/scene/gui/flow_container.h +++ b/scene/gui/flow_container.h @@ -36,11 +36,19 @@ class FlowContainer : public Container { GDCLASS(FlowContainer, Container); +public: + enum AlignmentMode { + ALIGNMENT_BEGIN, + ALIGNMENT_CENTER, + ALIGNMENT_END + }; + private: int cached_size = 0; int cached_line_count = 0; bool vertical = false; + AlignmentMode alignment = ALIGNMENT_BEGIN; struct ThemeCache { int h_separation = 0; @@ -61,6 +69,9 @@ protected: public: int get_line_count() const; + void set_alignment(AlignmentMode p_alignment); + AlignmentMode get_alignment() const; + void set_vertical(bool p_vertical); bool is_vertical() const; @@ -88,4 +99,6 @@ public: FlowContainer(true) { is_fixed = true; } }; +VARIANT_ENUM_CAST(FlowContainer::AlignmentMode); + #endif // FLOW_CONTAINER_H diff --git a/scene/gui/scroll_container.cpp b/scene/gui/scroll_container.cpp index a6aa4707ff..ec34a8d26d 100644 --- a/scene/gui/scroll_container.cpp +++ b/scene/gui/scroll_container.cpp @@ -107,45 +107,65 @@ void ScrollContainer::gui_input(const Ref<InputEvent> &p_gui_input) { double prev_v_scroll = v_scroll->get_value(); double prev_h_scroll = h_scroll->get_value(); + bool h_scroll_enabled = horizontal_scroll_mode != SCROLL_MODE_DISABLED; + bool v_scroll_enabled = vertical_scroll_mode != SCROLL_MODE_DISABLED; Ref<InputEventMouseButton> mb = p_gui_input; if (mb.is_valid()) { - if (mb->get_button_index() == MouseButton::WHEEL_UP && mb->is_pressed()) { - // only horizontal is enabled, scroll horizontally - if (h_scroll->is_visible() && (!v_scroll->is_visible() || mb->is_shift_pressed())) { - h_scroll->set_value(h_scroll->get_value() - h_scroll->get_page() / 8 * mb->get_factor()); - } else if (v_scroll->is_visible_in_tree()) { - v_scroll->set_value(v_scroll->get_value() - v_scroll->get_page() / 8 * mb->get_factor()); + if (mb->is_pressed()) { + bool scroll_value_modified = false; + + bool v_scroll_hidden = !v_scroll->is_visible() && vertical_scroll_mode != SCROLL_MODE_SHOW_NEVER; + if (mb->get_button_index() == MouseButton::WHEEL_UP) { + // By default, the vertical orientation takes precedence. This is an exception. + if ((h_scroll_enabled && mb->is_shift_pressed()) || v_scroll_hidden) { + h_scroll->set_value(prev_h_scroll - h_scroll->get_page() / 8 * mb->get_factor()); + scroll_value_modified = true; + } else if (v_scroll_enabled) { + v_scroll->set_value(prev_v_scroll - v_scroll->get_page() / 8 * mb->get_factor()); + scroll_value_modified = true; + } } - } - - if (mb->get_button_index() == MouseButton::WHEEL_DOWN && mb->is_pressed()) { - // only horizontal is enabled, scroll horizontally - if (h_scroll->is_visible() && (!v_scroll->is_visible() || mb->is_shift_pressed())) { - h_scroll->set_value(h_scroll->get_value() + h_scroll->get_page() / 8 * mb->get_factor()); - } else if (v_scroll->is_visible()) { - v_scroll->set_value(v_scroll->get_value() + v_scroll->get_page() / 8 * mb->get_factor()); + if (mb->get_button_index() == MouseButton::WHEEL_DOWN) { + if ((h_scroll_enabled && mb->is_shift_pressed()) || v_scroll_hidden) { + h_scroll->set_value(prev_h_scroll + h_scroll->get_page() / 8 * mb->get_factor()); + scroll_value_modified = true; + } else if (v_scroll_enabled) { + v_scroll->set_value(prev_v_scroll + v_scroll->get_page() / 8 * mb->get_factor()); + scroll_value_modified = true; + } } - } - if (mb->get_button_index() == MouseButton::WHEEL_LEFT && mb->is_pressed()) { - if (h_scroll->is_visible_in_tree()) { - h_scroll->set_value(h_scroll->get_value() - h_scroll->get_page() * mb->get_factor() / 8); + bool h_scroll_hidden = !h_scroll->is_visible() && horizontal_scroll_mode != SCROLL_MODE_SHOW_NEVER; + if (mb->get_button_index() == MouseButton::WHEEL_LEFT) { + // By default, the horizontal orientation takes precedence. This is an exception. + if ((v_scroll_enabled && mb->is_shift_pressed()) || h_scroll_hidden) { + v_scroll->set_value(prev_v_scroll - v_scroll->get_page() / 8 * mb->get_factor()); + scroll_value_modified = true; + } else if (h_scroll_enabled) { + h_scroll->set_value(prev_h_scroll - h_scroll->get_page() / 8 * mb->get_factor()); + scroll_value_modified = true; + } } - } - - if (mb->get_button_index() == MouseButton::WHEEL_RIGHT && mb->is_pressed()) { - if (h_scroll->is_visible_in_tree()) { - h_scroll->set_value(h_scroll->get_value() + h_scroll->get_page() * mb->get_factor() / 8); + if (mb->get_button_index() == MouseButton::WHEEL_RIGHT) { + if ((v_scroll_enabled && mb->is_shift_pressed()) || h_scroll_hidden) { + v_scroll->set_value(prev_v_scroll + v_scroll->get_page() / 8 * mb->get_factor()); + scroll_value_modified = true; + } else if (h_scroll_enabled) { + h_scroll->set_value(prev_h_scroll + h_scroll->get_page() / 8 * mb->get_factor()); + scroll_value_modified = true; + } } - } - if (v_scroll->get_value() != prev_v_scroll || h_scroll->get_value() != prev_h_scroll) { - accept_event(); //accept event if scroll changed + if (scroll_value_modified && (v_scroll->get_value() != prev_v_scroll || h_scroll->get_value() != prev_h_scroll)) { + accept_event(); // Accept event if scroll changed. + return; + } } - if (!DisplayServer::get_singleton()->screen_is_touchscreen(DisplayServer::get_singleton()->window_get_current_screen(get_viewport()->get_window_id()))) { + bool screen_is_touchscreen = DisplayServer::get_singleton()->screen_is_touchscreen(DisplayServer::get_singleton()->window_get_current_screen(get_viewport()->get_window_id())); + if (!screen_is_touchscreen) { return; } @@ -161,8 +181,8 @@ void ScrollContainer::gui_input(const Ref<InputEvent> &p_gui_input) { drag_speed = Vector2(); drag_accum = Vector2(); last_drag_accum = Vector2(); - drag_from = Vector2(h_scroll->get_value(), v_scroll->get_value()); - drag_touching = DisplayServer::get_singleton()->screen_is_touchscreen(DisplayServer::get_singleton()->window_get_current_screen(get_viewport()->get_window_id())); + drag_from = Vector2(prev_h_scroll, prev_v_scroll); + drag_touching = screen_is_touchscreen; drag_touching_deaccel = false; beyond_deadzone = false; time_since_motion = 0; @@ -180,6 +200,7 @@ void ScrollContainer::gui_input(const Ref<InputEvent> &p_gui_input) { } } } + return; } Ref<InputEventMouseMotion> mm = p_gui_input; @@ -189,22 +210,22 @@ void ScrollContainer::gui_input(const Ref<InputEvent> &p_gui_input) { Vector2 motion = mm->get_relative(); drag_accum -= motion; - if (beyond_deadzone || (horizontal_scroll_mode != SCROLL_MODE_DISABLED && Math::abs(drag_accum.x) > deadzone) || (vertical_scroll_mode != SCROLL_MODE_DISABLED && Math::abs(drag_accum.y) > deadzone)) { + if (beyond_deadzone || (h_scroll_enabled && Math::abs(drag_accum.x) > deadzone) || (v_scroll_enabled && Math::abs(drag_accum.y) > deadzone)) { if (!beyond_deadzone) { propagate_notification(NOTIFICATION_SCROLL_BEGIN); emit_signal(SNAME("scroll_started")); beyond_deadzone = true; - // resetting drag_accum here ensures smooth scrolling after reaching deadzone + // Resetting drag_accum here ensures smooth scrolling after reaching deadzone. drag_accum = -motion; } Vector2 diff = drag_from + drag_accum; - if (horizontal_scroll_mode != SCROLL_MODE_DISABLED) { + if (h_scroll_enabled) { h_scroll->set_value(diff.x); } else { drag_accum.x = 0; } - if (vertical_scroll_mode != SCROLL_MODE_DISABLED) { + if (v_scroll_enabled) { v_scroll->set_value(diff.y); } else { drag_accum.y = 0; @@ -212,20 +233,26 @@ void ScrollContainer::gui_input(const Ref<InputEvent> &p_gui_input) { time_since_motion = 0; } } + + if (v_scroll->get_value() != prev_v_scroll || h_scroll->get_value() != prev_h_scroll) { + accept_event(); // Accept event if scroll changed. + } + return; } Ref<InputEventPanGesture> pan_gesture = p_gui_input; if (pan_gesture.is_valid()) { - if (h_scroll->is_visible_in_tree()) { - h_scroll->set_value(h_scroll->get_value() + h_scroll->get_page() * pan_gesture->get_delta().x / 8); + if (h_scroll_enabled) { + h_scroll->set_value(prev_h_scroll + h_scroll->get_page() * pan_gesture->get_delta().x / 8); } - if (v_scroll->is_visible_in_tree()) { - v_scroll->set_value(v_scroll->get_value() + v_scroll->get_page() * pan_gesture->get_delta().y / 8); + if (v_scroll_enabled) { + v_scroll->set_value(prev_v_scroll + v_scroll->get_page() * pan_gesture->get_delta().y / 8); } - } - if (v_scroll->get_value() != prev_v_scroll || h_scroll->get_value() != prev_h_scroll) { - accept_event(); //accept event if scroll changed + if (v_scroll->get_value() != prev_v_scroll || h_scroll->get_value() != prev_h_scroll) { + accept_event(); // Accept event if scroll changed. + } + return; } } diff --git a/scene/gui/tab_container.cpp b/scene/gui/tab_container.cpp index ab4808d312..9105267ad3 100644 --- a/scene/gui/tab_container.cpp +++ b/scene/gui/tab_container.cpp @@ -345,7 +345,7 @@ Vector<Control *> TabContainer::_get_tab_controls() const { Vector<Control *> controls; for (int i = 0; i < get_child_count(); i++) { Control *control = Object::cast_to<Control>(get_child(i)); - if (!control || control->is_set_as_top_level() || control == tab_bar || control == child_removing) { + if (!control || control->is_set_as_top_level() || control == tab_bar || children_removing.has(control)) { continue; } @@ -584,10 +584,10 @@ void TabContainer::remove_child_notify(Node *p_child) { int idx = get_tab_idx_from_control(c); - // Before this, the tab control has not changed; after this, the tab control has changed. - child_removing = p_child; + // As the child hasn't been removed yet, keep track of it so when the "tab_changed" signal is fired it can be ignored. + children_removing.push_back(c); tab_bar->remove_tab(idx); - child_removing = nullptr; + children_removing.erase(c); _update_margins(); if (get_tab_count() == 0) { diff --git a/scene/gui/tab_container.h b/scene/gui/tab_container.h index b552aa459b..60961e02d3 100644 --- a/scene/gui/tab_container.h +++ b/scene/gui/tab_container.h @@ -46,7 +46,7 @@ class TabContainer : public Container { bool drag_to_rearrange_enabled = false; bool use_hidden_tabs_for_min_size = false; bool theme_changing = false; - Node *child_removing = nullptr; + Vector<Control *> children_removing; struct ThemeCache { int side_margin = 0; diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index 144aa2a1ef..1b8444abf4 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -833,7 +833,7 @@ void TextEdit::_notification(int p_what) { continue; } - // If we've changed colour we are at the start of a new section, therefore we need to go back to the end + // If we've changed color we are at the start of a new section, therefore we need to go back to the end // of the previous section to draw it, we'll also add the character back on. if (color != previous_color) { characters--; @@ -2051,7 +2051,8 @@ void TextEdit::gui_input(const Ref<InputEvent> &p_gui_input) { } if (is_shortcut_keys_enabled()) { - // SELECT ALL, SELECT WORD UNDER CARET, ADD SELECTION FOR NEXT OCCURRENCE, CUT, COPY, PASTE. + // SELECT ALL, SELECT WORD UNDER CARET, ADD SELECTION FOR NEXT OCCURRENCE, + // CLEAR CARETS AND SELECTIONS, CUT, COPY, PASTE. if (k->is_action("ui_text_select_all", true)) { select_all(); accept_event(); @@ -2067,6 +2068,13 @@ void TextEdit::gui_input(const Ref<InputEvent> &p_gui_input) { accept_event(); return; } + if (k->is_action("ui_text_clear_carets_and_selection", true)) { + // Since the default shortcut is ESC, accepts the event only if it's actually performed. + if (_clear_carets_and_selection()) { + accept_event(); + return; + } + } if (k->is_action("ui_cut", true)) { cut(); accept_event(); @@ -2651,7 +2659,7 @@ void TextEdit::_do_backspace(bool p_word, bool p_all_to_left) { set_caret_line(get_caret_line(caret_idx), false, true, 0, caret_idx); set_caret_column(column, caret_idx == 0, caret_idx); - // Now we can clean up the overlaping caret. + // Now we can clean up the overlapping caret. if (overlapping_caret_index != -1) { backspace(overlapping_caret_index); i++; @@ -2819,6 +2827,20 @@ void TextEdit::_move_caret_document_end(bool p_select) { } } +bool TextEdit::_clear_carets_and_selection() { + if (get_caret_count() > 1) { + remove_secondary_carets(); + return true; + } + + if (has_selection()) { + deselect(); + return true; + } + + return false; +} + void TextEdit::_get_above_below_caret_line_column(int p_old_line, int p_old_wrap_index, int p_old_column, bool p_below, int &p_new_line, int &p_new_column, int p_last_fit_x) const { if (p_last_fit_x == -1) { p_last_fit_x = _get_column_x_offset_for_line(p_old_column, p_old_line, p_old_column); @@ -6538,7 +6560,7 @@ void TextEdit::_cut_internal(int p_caret) { int indent_level = get_indent_level(cl); double hscroll = get_h_scroll(); - // Check for overlaping carets. + // Check for overlapping carets. // We don't need to worry about selections as that is caught before this entire section. for (int j = i - 1; j >= 0; j--) { if (get_caret_line(caret_edit_order[j]) == cl) { diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h index 935f2a7ce8..92acbaf521 100644 --- a/scene/gui/text_edit.h +++ b/scene/gui/text_edit.h @@ -597,6 +597,7 @@ private: void _delete(bool p_word = false, bool p_all_to_right = false); void _move_caret_document_start(bool p_select); void _move_caret_document_end(bool p_select); + bool _clear_carets_and_selection(); // Used in add_caret_at_carets void _get_above_below_caret_line_column(int p_old_line, int p_old_wrap_index, int p_old_column, bool p_below, int &p_new_line, int &p_new_column, int p_last_fit_x = -1) const; |