diff options
Diffstat (limited to 'scene/gui')
39 files changed, 487 insertions, 289 deletions
diff --git a/scene/gui/base_button.cpp b/scene/gui/base_button.cpp index 66b14dc967..01e3cce78b 100644 --- a/scene/gui/base_button.cpp +++ b/scene/gui/base_button.cpp @@ -33,7 +33,6 @@ #include "core/config/project_settings.h" #include "core/os/keyboard.h" #include "scene/main/window.h" -#include "scene/scene_string_names.h" void BaseButton::_unpress_group() { if (!button_group.is_valid()) { @@ -135,7 +134,7 @@ void BaseButton::_notification(int p_what) { void BaseButton::_pressed() { GDVIRTUAL_CALL(_pressed); pressed(); - emit_signal(SNAME("pressed")); + emit_signal(SceneStringName(pressed)); } void BaseButton::_toggled(bool p_pressed) { @@ -162,7 +161,7 @@ void BaseButton::on_action_event(Ref<InputEvent> p_event) { status.pressed = !status.pressed; _unpress_group(); if (button_group.is_valid()) { - button_group->emit_signal(SNAME("pressed"), this); + button_group->emit_signal(SceneStringName(pressed), this); } _toggled(status.pressed); _pressed(); @@ -226,7 +225,7 @@ void BaseButton::set_pressed(bool p_pressed) { if (p_pressed) { _unpress_group(); if (button_group.is_valid()) { - button_group->emit_signal(SNAME("pressed"), this); + button_group->emit_signal(SceneStringName(pressed), this); } } _toggled(status.pressed); @@ -368,7 +367,7 @@ void BaseButton::shortcut_input(const Ref<InputEvent> &p_event) { _unpress_group(); if (button_group.is_valid()) { - button_group->emit_signal(SNAME("pressed"), this); + button_group->emit_signal(SceneStringName(pressed), this); } _toggled(status.pressed); diff --git a/scene/gui/box_container.cpp b/scene/gui/box_container.cpp index 88f65ca1bc..d8fcbbb883 100644 --- a/scene/gui/box_container.cpp +++ b/scene/gui/box_container.cpp @@ -243,8 +243,8 @@ Size2 BoxContainer::get_minimum_size() const { bool first = true; for (int i = 0; i < get_child_count(); i++) { - Control *c = as_sortable_control(get_child(i)); - if (!c) { + Control *c = Object::cast_to<Control>(get_child(i)); + if (!c || !c->is_visible() || c->is_set_as_top_level()) { continue; } diff --git a/scene/gui/button.cpp b/scene/gui/button.cpp index ad3f607661..3bf9d79c7f 100644 --- a/scene/gui/button.cpp +++ b/scene/gui/button.cpp @@ -50,6 +50,83 @@ void Button::_set_internal_margin(Side p_side, float p_value) { void Button::_queue_update_size_cache() { } +void Button::_update_theme_item_cache() { + Control::_update_theme_item_cache(); + + const bool rtl = is_layout_rtl(); + if (rtl && has_theme_stylebox(SNAME("normal_mirrored"))) { + theme_cache.max_style_size = theme_cache.normal_mirrored->get_minimum_size(); + theme_cache.style_margin_left = theme_cache.normal_mirrored->get_margin(SIDE_LEFT); + theme_cache.style_margin_right = theme_cache.normal_mirrored->get_margin(SIDE_RIGHT); + theme_cache.style_margin_top = theme_cache.normal_mirrored->get_margin(SIDE_TOP); + theme_cache.style_margin_bottom = theme_cache.normal_mirrored->get_margin(SIDE_BOTTOM); + } else { + theme_cache.max_style_size = theme_cache.normal->get_minimum_size(); + theme_cache.style_margin_left = theme_cache.normal->get_margin(SIDE_LEFT); + theme_cache.style_margin_right = theme_cache.normal->get_margin(SIDE_RIGHT); + theme_cache.style_margin_top = theme_cache.normal->get_margin(SIDE_TOP); + theme_cache.style_margin_bottom = theme_cache.normal->get_margin(SIDE_BOTTOM); + } + if (has_theme_stylebox("hover_pressed")) { + if (rtl && has_theme_stylebox(SNAME("hover_pressed_mirrored"))) { + theme_cache.max_style_size = theme_cache.max_style_size.max(theme_cache.hover_pressed_mirrored->get_minimum_size()); + theme_cache.style_margin_left = MAX(theme_cache.style_margin_left, theme_cache.hover_pressed_mirrored->get_margin(SIDE_LEFT)); + theme_cache.style_margin_right = MAX(theme_cache.style_margin_right, theme_cache.hover_pressed_mirrored->get_margin(SIDE_RIGHT)); + theme_cache.style_margin_top = MAX(theme_cache.style_margin_top, theme_cache.hover_pressed_mirrored->get_margin(SIDE_TOP)); + theme_cache.style_margin_bottom = MAX(theme_cache.style_margin_bottom, theme_cache.hover_pressed_mirrored->get_margin(SIDE_BOTTOM)); + } else { + theme_cache.max_style_size = theme_cache.max_style_size.max(theme_cache.hover_pressed->get_minimum_size()); + theme_cache.style_margin_left = MAX(theme_cache.style_margin_left, theme_cache.hover_pressed->get_margin(SIDE_LEFT)); + theme_cache.style_margin_right = MAX(theme_cache.style_margin_right, theme_cache.hover_pressed->get_margin(SIDE_RIGHT)); + theme_cache.style_margin_top = MAX(theme_cache.style_margin_top, theme_cache.hover_pressed->get_margin(SIDE_TOP)); + theme_cache.style_margin_bottom = MAX(theme_cache.style_margin_bottom, theme_cache.hover_pressed->get_margin(SIDE_BOTTOM)); + } + } + if (rtl && has_theme_stylebox(SNAME("pressed_mirrored"))) { + theme_cache.max_style_size = theme_cache.max_style_size.max(theme_cache.pressed_mirrored->get_minimum_size()); + theme_cache.style_margin_left = MAX(theme_cache.style_margin_left, theme_cache.pressed_mirrored->get_margin(SIDE_LEFT)); + theme_cache.style_margin_right = MAX(theme_cache.style_margin_right, theme_cache.pressed_mirrored->get_margin(SIDE_RIGHT)); + theme_cache.style_margin_top = MAX(theme_cache.style_margin_top, theme_cache.pressed_mirrored->get_margin(SIDE_TOP)); + theme_cache.style_margin_bottom = MAX(theme_cache.style_margin_bottom, theme_cache.pressed_mirrored->get_margin(SIDE_BOTTOM)); + } else { + theme_cache.max_style_size = theme_cache.max_style_size.max(theme_cache.pressed->get_minimum_size()); + theme_cache.style_margin_left = MAX(theme_cache.style_margin_left, theme_cache.pressed->get_margin(SIDE_LEFT)); + theme_cache.style_margin_right = MAX(theme_cache.style_margin_right, theme_cache.pressed->get_margin(SIDE_RIGHT)); + theme_cache.style_margin_top = MAX(theme_cache.style_margin_top, theme_cache.pressed->get_margin(SIDE_TOP)); + theme_cache.style_margin_bottom = MAX(theme_cache.style_margin_bottom, theme_cache.pressed->get_margin(SIDE_BOTTOM)); + } + if (rtl && has_theme_stylebox(SNAME("hover_mirrored"))) { + theme_cache.max_style_size = theme_cache.max_style_size.max(theme_cache.hover_mirrored->get_minimum_size()); + theme_cache.style_margin_left = MAX(theme_cache.style_margin_left, theme_cache.hover_mirrored->get_margin(SIDE_LEFT)); + theme_cache.style_margin_right = MAX(theme_cache.style_margin_right, theme_cache.hover_mirrored->get_margin(SIDE_RIGHT)); + theme_cache.style_margin_top = MAX(theme_cache.style_margin_top, theme_cache.hover_mirrored->get_margin(SIDE_TOP)); + theme_cache.style_margin_bottom = MAX(theme_cache.style_margin_bottom, theme_cache.hover_mirrored->get_margin(SIDE_BOTTOM)); + } else { + theme_cache.max_style_size = theme_cache.max_style_size.max(theme_cache.hover->get_minimum_size()); + theme_cache.style_margin_left = MAX(theme_cache.style_margin_left, theme_cache.hover->get_margin(SIDE_LEFT)); + theme_cache.style_margin_right = MAX(theme_cache.style_margin_right, theme_cache.hover->get_margin(SIDE_RIGHT)); + theme_cache.style_margin_top = MAX(theme_cache.style_margin_top, theme_cache.hover->get_margin(SIDE_TOP)); + theme_cache.style_margin_bottom = MAX(theme_cache.style_margin_bottom, theme_cache.hover->get_margin(SIDE_BOTTOM)); + } + if (rtl && has_theme_stylebox(SNAME("disabled_mirrored"))) { + theme_cache.max_style_size = theme_cache.max_style_size.max(theme_cache.disabled_mirrored->get_minimum_size()); + theme_cache.style_margin_left = MAX(theme_cache.style_margin_left, theme_cache.disabled_mirrored->get_margin(SIDE_LEFT)); + theme_cache.style_margin_right = MAX(theme_cache.style_margin_right, theme_cache.disabled_mirrored->get_margin(SIDE_RIGHT)); + theme_cache.style_margin_top = MAX(theme_cache.style_margin_top, theme_cache.disabled_mirrored->get_margin(SIDE_TOP)); + theme_cache.style_margin_bottom = MAX(theme_cache.style_margin_bottom, theme_cache.disabled_mirrored->get_margin(SIDE_BOTTOM)); + } else { + theme_cache.max_style_size = theme_cache.max_style_size.max(theme_cache.disabled->get_minimum_size()); + theme_cache.style_margin_left = MAX(theme_cache.style_margin_left, theme_cache.disabled->get_margin(SIDE_LEFT)); + theme_cache.style_margin_right = MAX(theme_cache.style_margin_right, theme_cache.disabled->get_margin(SIDE_RIGHT)); + theme_cache.style_margin_top = MAX(theme_cache.style_margin_top, theme_cache.disabled->get_margin(SIDE_TOP)); + theme_cache.style_margin_bottom = MAX(theme_cache.style_margin_bottom, theme_cache.disabled->get_margin(SIDE_BOTTOM)); + } +} + +Size2 Button::_get_largest_stylebox_size() const { + return theme_cache.max_style_size; +} + Ref<StyleBox> Button::_get_current_stylebox() const { Ref<StyleBox> stylebox = theme_cache.normal; const bool rtl = is_layout_rtl(); @@ -137,16 +214,13 @@ void Button::_notification(int p_what) { const RID ci = get_canvas_item(); const Size2 size = get_size(); - const Ref<StyleBox> style = _get_current_stylebox(); - { // Draws the stylebox in the current state. - if (!flat) { - style->draw(ci, Rect2(Point2(), size)); - } + // Draws the stylebox in the current state. + if (!flat) { + _get_current_stylebox()->draw(ci, Rect2(Point2(), size)); + } - if (has_focus()) { - Ref<StyleBox> style2 = theme_cache.focus; - style2->draw(ci, Rect2(Point2(), size)); - } + if (has_focus()) { + theme_cache.focus->draw(ci, Rect2(Point2(), size)); } Ref<Texture2D> _icon = icon; @@ -158,16 +232,11 @@ void Button::_notification(int p_what) { break; } - const float style_margin_left = style->get_margin(SIDE_LEFT); - const float style_margin_right = style->get_margin(SIDE_RIGHT); - const float style_margin_top = style->get_margin(SIDE_TOP); - const float style_margin_bottom = style->get_margin(SIDE_BOTTOM); - Size2 drawable_size_remained = size; { // The size after the stelybox is stripped. - drawable_size_remained.width -= style_margin_left + style_margin_right; - drawable_size_remained.height -= style_margin_top + style_margin_bottom; + drawable_size_remained.width -= theme_cache.style_margin_left + theme_cache.style_margin_right; + drawable_size_remained.height -= theme_cache.style_margin_top + theme_cache.style_margin_bottom; } const int h_separation = MAX(0, theme_cache.h_separation); @@ -298,6 +367,7 @@ void Button::_notification(int p_what) { icon_size = Size2(icon_width, icon_height); } icon_size = _fit_icon_size(icon_size); + icon_size = icon_size.round(); } if (icon_size.width > 0.0f) { @@ -311,12 +381,12 @@ void Button::_notification(int p_what) { [[fallthrough]]; case HORIZONTAL_ALIGNMENT_FILL: case HORIZONTAL_ALIGNMENT_LEFT: { - icon_ofs.x += style_margin_left; + icon_ofs.x += theme_cache.style_margin_left; icon_ofs.x += left_internal_margin_with_h_separation; } break; case HORIZONTAL_ALIGNMENT_RIGHT: { - icon_ofs.x = size.x - style_margin_right; + icon_ofs.x = size.x - theme_cache.style_margin_right; icon_ofs.x -= right_internal_margin_with_h_separation; icon_ofs.x -= icon_size.width; } break; @@ -329,13 +399,14 @@ void Button::_notification(int p_what) { [[fallthrough]]; case VERTICAL_ALIGNMENT_FILL: case VERTICAL_ALIGNMENT_TOP: { - icon_ofs.y += style_margin_top; + icon_ofs.y += theme_cache.style_margin_top; } break; case VERTICAL_ALIGNMENT_BOTTOM: { - icon_ofs.y = size.y - style_margin_bottom - icon_size.height; + icon_ofs.y = size.y - theme_cache.style_margin_bottom - icon_size.height; } break; } + icon_ofs = icon_ofs.floor(); Rect2 icon_region = Rect2(icon_ofs, icon_size); draw_texture_rect(_icon, icon_region, false, icon_modulate_color); @@ -371,7 +442,7 @@ void Button::_notification(int p_what) { case HORIZONTAL_ALIGNMENT_FILL: case HORIZONTAL_ALIGNMENT_LEFT: case HORIZONTAL_ALIGNMENT_RIGHT: { - text_ofs.x += style_margin_left; + text_ofs.x += theme_cache.style_margin_left; text_ofs.x += left_internal_margin_with_h_separation; if (icon_align_rtl_checked == HORIZONTAL_ALIGNMENT_LEFT) { // Offset by the space's width that occupied by icon and h_separation together. @@ -380,7 +451,7 @@ void Button::_notification(int p_what) { } break; } - text_ofs.y = (drawable_size_remained.height - text_buf->get_size().height) / 2.0f + style_margin_top; + text_ofs.y = (drawable_size_remained.height - text_buf->get_size().height) / 2.0f + theme_cache.style_margin_top; if (vertical_icon_alignment == VERTICAL_ALIGNMENT_TOP) { text_ofs.y += custom_element_size.height - drawable_size_remained.height; // Offset by the icon's height. } @@ -450,7 +521,7 @@ Size2 Button::get_minimum_size_for_text_and_icon(const String &p_text, Ref<Textu } } - return _get_current_stylebox()->get_minimum_size() + minsize; + return _get_largest_stylebox_size() + minsize; } void Button::_shape(Ref<TextParagraph> p_paragraph, String p_text) { diff --git a/scene/gui/button.h b/scene/gui/button.h index 86fdbd35d5..eefb690913 100644 --- a/scene/gui/button.h +++ b/scene/gui/button.h @@ -69,6 +69,12 @@ private: Ref<StyleBox> disabled_mirrored; Ref<StyleBox> focus; + Size2 max_style_size; + float style_margin_left = 0; + float style_margin_right = 0; + float style_margin_top = 0; + float style_margin_bottom = 0; + Color font_color; Color font_focus_color; Color font_pressed_color; @@ -94,16 +100,18 @@ private: int icon_max_width = 0; } theme_cache; - Size2 _fit_icon_size(const Size2 &p_size) const; - void _shape(Ref<TextParagraph> p_paragraph = Ref<TextParagraph>(), String p_text = ""); void _texture_changed(); protected: + virtual void _update_theme_item_cache() override; + void _set_internal_margin(Side p_side, float p_value); virtual void _queue_update_size_cache(); + Size2 _fit_icon_size(const Size2 &p_size) const; Ref<StyleBox> _get_current_stylebox() const; + Size2 _get_largest_stylebox_size() const; void _notification(int p_what); static void _bind_methods(); diff --git a/scene/gui/check_box.cpp b/scene/gui/check_box.cpp index af6696834e..99937aaf41 100644 --- a/scene/gui/check_box.cpp +++ b/scene/gui/check_box.cpp @@ -59,14 +59,14 @@ Size2 CheckBox::get_icon_size() const { if (!theme_cache.radio_unchecked_disabled.is_null()) { tex_size = tex_size.max(theme_cache.radio_unchecked_disabled->get_size()); } - return tex_size; + return _fit_icon_size(tex_size); } Size2 CheckBox::get_minimum_size() const { Size2 minsize = Button::get_minimum_size(); const Size2 tex_size = get_icon_size(); if (tex_size.width > 0 || tex_size.height > 0) { - const Size2 padding = _get_current_stylebox()->get_minimum_size(); + const Size2 padding = _get_largest_stylebox_size(); Size2 content_size = minsize - padding; if (content_size.width > 0 && tex_size.width > 0) { content_size.width += MAX(0, theme_cache.h_separation); @@ -127,9 +127,9 @@ void CheckBox::_notification(int p_what) { ofs.y = int((get_size().height - get_icon_size().height) / 2) + theme_cache.check_v_offset; if (is_pressed()) { - on_tex->draw(ci, ofs); + on_tex->draw_rect(ci, Rect2(ofs, _fit_icon_size(on_tex->get_size()))); } else { - off_tex->draw(ci, ofs); + off_tex->draw_rect(ci, Rect2(ofs, _fit_icon_size(off_tex->get_size()))); } } break; } diff --git a/scene/gui/check_button.cpp b/scene/gui/check_button.cpp index ab3b74a3c3..29b9504776 100644 --- a/scene/gui/check_button.cpp +++ b/scene/gui/check_button.cpp @@ -63,14 +63,14 @@ Size2 CheckButton::get_icon_size() const { tex_size = tex_size.max(off_tex->get_size()); } - return tex_size; + return _fit_icon_size(tex_size); } Size2 CheckButton::get_minimum_size() const { Size2 minsize = Button::get_minimum_size(); const Size2 tex_size = get_icon_size(); if (tex_size.width > 0 || tex_size.height > 0) { - const Size2 padding = _get_current_stylebox()->get_minimum_size(); + const Size2 padding = _get_largest_stylebox_size(); Size2 content_size = minsize - padding; if (content_size.width > 0 && tex_size.width > 0) { content_size.width += MAX(0, theme_cache.h_separation); @@ -134,9 +134,9 @@ void CheckButton::_notification(int p_what) { ofs.y = (get_size().height - tex_size.height) / 2 + theme_cache.check_v_offset; if (is_pressed()) { - on_tex->draw(ci, ofs); + on_tex->draw_rect(ci, Rect2(ofs, _fit_icon_size(on_tex->get_size()))); } else { - off_tex->draw(ci, ofs); + off_tex->draw_rect(ci, Rect2(ofs, _fit_icon_size(off_tex->get_size()))); } } break; } diff --git a/scene/gui/code_edit.cpp b/scene/gui/code_edit.cpp index 8131fe7aaa..c843bb8c44 100644 --- a/scene/gui/code_edit.cpp +++ b/scene/gui/code_edit.cpp @@ -3050,7 +3050,7 @@ void CodeEdit::_update_delimiter_cache(int p_from_line, int p_to_line) { } int CodeEdit::_is_in_delimiter(int p_line, int p_column, DelimiterType p_type) const { - if (delimiters.size() == 0) { + if (delimiters.size() == 0 || p_line >= delimiter_cache.size()) { return -1; } ERR_FAIL_INDEX_V(p_line, get_line_count(), 0); diff --git a/scene/gui/color_picker.cpp b/scene/gui/color_picker.cpp index aeaaac1efc..245a086dda 100644 --- a/scene/gui/color_picker.cpp +++ b/scene/gui/color_picker.cpp @@ -95,8 +95,8 @@ void ColorPicker::_notification(int p_what) { for (int i = 0; i < MODE_BUTTON_COUNT; i++) { mode_btns[i]->begin_bulk_theme_override(); - mode_btns[i]->add_theme_style_override(SNAME("pressed"), theme_cache.mode_button_pressed); - mode_btns[i]->add_theme_style_override(SNAME("normal"), theme_cache.mode_button_normal); + mode_btns[i]->add_theme_style_override(SceneStringName(pressed), theme_cache.mode_button_pressed); + mode_btns[i]->add_theme_style_override(CoreStringName(normal), theme_cache.mode_button_normal); mode_btns[i]->add_theme_style_override(SNAME("hover"), theme_cache.mode_button_hover); mode_btns[i]->end_bulk_theme_override(); } @@ -420,18 +420,18 @@ void ColorPicker::create_slider(GridContainer *gc, int idx) { LineEdit *vle = val->get_line_edit(); vle->connect("text_changed", callable_mp(this, &ColorPicker::_text_changed)); - vle->connect("gui_input", callable_mp(this, &ColorPicker::_line_edit_input)); + vle->connect(SceneStringName(gui_input), callable_mp(this, &ColorPicker::_line_edit_input)); vle->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_RIGHT); - val->connect("gui_input", callable_mp(this, &ColorPicker::_slider_or_spin_input)); + val->connect(SceneStringName(gui_input), callable_mp(this, &ColorPicker::_slider_or_spin_input)); slider->set_h_size_flags(SIZE_EXPAND_FILL); slider->connect("drag_started", callable_mp(this, &ColorPicker::_slider_drag_started)); slider->connect("value_changed", callable_mp(this, &ColorPicker::_slider_value_changed).unbind(1)); slider->connect("drag_ended", callable_mp(this, &ColorPicker::_slider_drag_ended).unbind(1)); - slider->connect("draw", callable_mp(this, &ColorPicker::_slider_draw).bind(idx)); - slider->connect("gui_input", callable_mp(this, &ColorPicker::_slider_or_spin_input)); + slider->connect(SceneStringName(draw), callable_mp(this, &ColorPicker::_slider_draw).bind(idx)); + slider->connect(SceneStringName(gui_input), callable_mp(this, &ColorPicker::_slider_or_spin_input)); if (idx < SLIDER_COUNT) { sliders[idx] = slider; @@ -761,7 +761,7 @@ void ColorPicker::_add_preset_button(int p_size, const Color &p_color) { btn_preset_new->set_button_group(preset_group); preset_container->add_child(btn_preset_new); btn_preset_new->set_pressed(true); - btn_preset_new->connect("gui_input", callable_mp(this, &ColorPicker::_preset_input).bind(p_color)); + btn_preset_new->connect(SceneStringName(gui_input), callable_mp(this, &ColorPicker::_preset_input).bind(p_color)); } void ColorPicker::_add_recent_preset_button(int p_size, const Color &p_color) { @@ -1510,7 +1510,7 @@ void ColorPicker::_pick_button_pressed() { if (!picker_window) { picker_window = memnew(Popup); picker_window->set_size(Vector2i(1, 1)); - picker_window->connect("visibility_changed", callable_mp(this, &ColorPicker::_pick_finished)); + picker_window->connect(SceneStringName(visibility_changed), callable_mp(this, &ColorPicker::_pick_finished)); add_child(picker_window, false, INTERNAL_MODE_FRONT); } picker_window->popup(); @@ -1546,7 +1546,7 @@ void ColorPicker::_pick_button_pressed_legacy() { picker_texture_rect->set_anchors_preset(Control::PRESET_FULL_RECT); picker_window->add_child(picker_texture_rect); picker_texture_rect->set_default_cursor_shape(CURSOR_POINTING_HAND); - picker_texture_rect->connect("gui_input", callable_mp(this, &ColorPicker::_picker_texture_input)); + picker_texture_rect->connect(SceneStringName(gui_input), callable_mp(this, &ColorPicker::_picker_texture_input)); picker_preview = memnew(Panel); picker_preview->set_anchors_preset(Control::PRESET_CENTER_TOP); @@ -1823,11 +1823,11 @@ ColorPicker::ColorPicker() { uv_edit = memnew(Control); hb_edit->add_child(uv_edit); - uv_edit->connect("gui_input", callable_mp(this, &ColorPicker::_uv_input).bind(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_h_size_flags(SIZE_EXPAND_FILL); uv_edit->set_v_size_flags(SIZE_EXPAND_FILL); - uv_edit->connect("draw", callable_mp(this, &ColorPicker::_hsv_draw).bind(0, uv_edit)); + uv_edit->connect(SceneStringName(draw), callable_mp(this, &ColorPicker::_hsv_draw).bind(0, uv_edit)); sample_hbc = memnew(HBoxContainer); real_vbox->add_child(sample_hbc); @@ -1836,18 +1836,18 @@ ColorPicker::ColorPicker() { sample_hbc->add_child(btn_pick); if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_SCREEN_CAPTURE)) { btn_pick->set_tooltip_text(ETR("Pick a color from the screen.")); - btn_pick->connect(SNAME("pressed"), callable_mp(this, &ColorPicker::_pick_button_pressed)); + btn_pick->connect(SceneStringName(pressed), callable_mp(this, &ColorPicker::_pick_button_pressed)); } else { // On unsupported platforms, use a legacy method for color picking. btn_pick->set_tooltip_text(ETR("Pick a color from the application window.")); - btn_pick->connect(SNAME("pressed"), callable_mp(this, &ColorPicker::_pick_button_pressed_legacy)); + btn_pick->connect(SceneStringName(pressed), callable_mp(this, &ColorPicker::_pick_button_pressed_legacy)); } sample = memnew(TextureRect); 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)); + sample->connect(SceneStringName(gui_input), callable_mp(this, &ColorPicker::_sample_input)); + sample->connect(SceneStringName(draw), callable_mp(this, &ColorPicker::_sample_draw)); btn_shape = memnew(MenuButton); btn_shape->set_flat(false); @@ -1883,7 +1883,7 @@ ColorPicker::ColorPicker() { mode_btns[i]->set_toggle_mode(true); mode_btns[i]->set_text(modes[i]->get_name()); mode_btns[i]->set_button_group(mode_group); - mode_btns[i]->connect("pressed", callable_mp(this, &ColorPicker::set_color_mode).bind((ColorModeType)i)); + mode_btns[i]->connect(SceneStringName(pressed), callable_mp(this, &ColorPicker::set_color_mode).bind((ColorModeType)i)); } mode_btns[0]->set_pressed(true); @@ -1936,7 +1936,7 @@ ColorPicker::ColorPicker() { text_type->set_text("#"); text_type->set_tooltip_text(RTR("Switch between hexadecimal and code values.")); if (Engine::get_singleton()->is_editor_hint()) { - text_type->connect("pressed", callable_mp(this, &ColorPicker::_text_type_toggled)); + text_type->connect(SceneStringName(pressed), callable_mp(this, &ColorPicker::_text_type_toggled)); } else { text_type->set_flat(true); text_type->set_mouse_filter(MOUSE_FILTER_IGNORE); @@ -1950,7 +1950,7 @@ ColorPicker::ColorPicker() { c_text->set_placeholder(ETR("Hex code or named color")); c_text->connect("text_submitted", callable_mp(this, &ColorPicker::_html_submitted)); c_text->connect("text_changed", callable_mp(this, &ColorPicker::_text_changed)); - c_text->connect("focus_exited", callable_mp(this, &ColorPicker::_html_focus_exit)); + c_text->connect(SceneStringName(focus_exited), callable_mp(this, &ColorPicker::_html_focus_exit)); wheel_edit = memnew(AspectRatioContainer); wheel_edit->set_h_size_flags(SIZE_EXPAND_FILL); @@ -1969,19 +1969,19 @@ ColorPicker::ColorPicker() { wheel = memnew(Control); wheel_margin->add_child(wheel); wheel->set_mouse_filter(MOUSE_FILTER_PASS); - wheel->connect("draw", callable_mp(this, &ColorPicker::_hsv_draw).bind(2, wheel)); + wheel->connect(SceneStringName(draw), callable_mp(this, &ColorPicker::_hsv_draw).bind(2, wheel)); wheel_uv = memnew(Control); wheel_margin->add_child(wheel_uv); - wheel_uv->connect("gui_input", callable_mp(this, &ColorPicker::_uv_input).bind(wheel_uv)); - wheel_uv->connect("draw", callable_mp(this, &ColorPicker::_hsv_draw).bind(0, wheel_uv)); + 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)); w_edit = memnew(Control); hb_edit->add_child(w_edit); w_edit->set_h_size_flags(SIZE_FILL); w_edit->set_v_size_flags(SIZE_EXPAND_FILL); - w_edit->connect("gui_input", callable_mp(this, &ColorPicker::_w_input)); - w_edit->connect("draw", callable_mp(this, &ColorPicker::_hsv_draw).bind(1, w_edit)); + 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)); _update_controls(); updating = false; @@ -2026,7 +2026,7 @@ ColorPicker::ColorPicker() { btn_add_preset = memnew(Button); btn_add_preset->set_icon_alignment(HORIZONTAL_ALIGNMENT_CENTER); btn_add_preset->set_tooltip_text(ETR("Add current color as a preset.")); - btn_add_preset->connect("pressed", callable_mp(this, &ColorPicker::_add_preset_pressed)); + btn_add_preset->connect(SceneStringName(pressed), callable_mp(this, &ColorPicker::_add_preset_pressed)); preset_container->add_child(btn_add_preset); } @@ -2171,7 +2171,7 @@ void ColorPickerButton::_update_picker() { picker->connect("color_changed", callable_mp(this, &ColorPickerButton::_color_changed)); popup->connect("about_to_popup", callable_mp(this, &ColorPickerButton::_about_to_popup)); popup->connect("popup_hide", callable_mp(this, &ColorPickerButton::_modal_closed)); - picker->connect("minimum_size_changed", callable_mp((Window *)popup, &Window::reset_size)); + picker->connect(SceneStringName(minimum_size_changed), callable_mp((Window *)popup, &Window::reset_size)); picker->set_pick_color(color); picker->set_edit_alpha(edit_alpha); picker->set_display_old_color(true); diff --git a/scene/gui/container.cpp b/scene/gui/container.cpp index 5db8d69eef..f1faf3e899 100644 --- a/scene/gui/container.cpp +++ b/scene/gui/container.cpp @@ -30,8 +30,6 @@ #include "container.h" -#include "scene/scene_string_names.h" - void Container::_child_minsize_changed() { update_minimum_size(); queue_sort(); @@ -45,9 +43,9 @@ void Container::add_child_notify(Node *p_child) { return; } - control->connect(SNAME("size_flags_changed"), callable_mp(this, &Container::queue_sort)); - control->connect(SNAME("minimum_size_changed"), callable_mp(this, &Container::_child_minsize_changed)); - control->connect(SNAME("visibility_changed"), callable_mp(this, &Container::_child_minsize_changed)); + control->connect(SceneStringName(size_flags_changed), callable_mp(this, &Container::queue_sort)); + control->connect(SceneStringName(minimum_size_changed), callable_mp(this, &Container::_child_minsize_changed)); + control->connect(SceneStringName(visibility_changed), callable_mp(this, &Container::_child_minsize_changed)); update_minimum_size(); queue_sort(); @@ -72,9 +70,9 @@ void Container::remove_child_notify(Node *p_child) { return; } - control->disconnect("size_flags_changed", callable_mp(this, &Container::queue_sort)); - control->disconnect("minimum_size_changed", callable_mp(this, &Container::_child_minsize_changed)); - control->disconnect("visibility_changed", callable_mp(this, &Container::_child_minsize_changed)); + control->disconnect(SceneStringName(size_flags_changed), callable_mp(this, &Container::queue_sort)); + control->disconnect(SceneStringName(minimum_size_changed), callable_mp(this, &Container::_child_minsize_changed)); + control->disconnect(SceneStringName(visibility_changed), callable_mp(this, &Container::_child_minsize_changed)); update_minimum_size(); queue_sort(); @@ -86,10 +84,10 @@ void Container::_sort_children() { } notification(NOTIFICATION_PRE_SORT_CHILDREN); - emit_signal(SceneStringNames::get_singleton()->pre_sort_children); + emit_signal(SceneStringName(pre_sort_children)); notification(NOTIFICATION_SORT_CHILDREN); - emit_signal(SceneStringNames::get_singleton()->sort_children); + emit_signal(SceneStringName(sort_children)); pending_sort = false; } diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp index 2dd12b92f3..0d5c69b207 100644 --- a/scene/gui/control.cpp +++ b/scene/gui/control.cpp @@ -42,7 +42,6 @@ #include "scene/gui/panel.h" #include "scene/main/canvas_layer.h" #include "scene/main/window.h" -#include "scene/scene_string_names.h" #include "scene/theme/theme_db.h" #include "scene/theme/theme_owner.h" #include "servers/rendering_server.h" @@ -212,17 +211,17 @@ void Control::get_argument_options(const StringName &p_function, int p_idx, List const String pf = p_function; Theme::DataType type = Theme::DATA_TYPE_MAX; - if (pf == "add_theme_color_override" || pf == "has_theme_color" || pf == "has_theme_color_override" || pf == "get_theme_color") { + if (pf == "add_theme_color_override" || pf == "has_theme_color" || pf == "has_theme_color_override" || pf == "get_theme_color" || pf == "remove_theme_color_override") { type = Theme::DATA_TYPE_COLOR; - } else if (pf == "add_theme_constant_override" || pf == "has_theme_constant" || pf == "has_theme_constant_override" || pf == "get_theme_constant") { + } else if (pf == "add_theme_constant_override" || pf == "has_theme_constant" || pf == "has_theme_constant_override" || pf == "get_theme_constant" || pf == "remove_theme_constant_override") { type = Theme::DATA_TYPE_CONSTANT; - } else if (pf == "add_theme_font_override" || pf == "has_theme_font" || pf == "has_theme_font_override" || pf == "get_theme_font") { + } else if (pf == "add_theme_font_override" || pf == "has_theme_font" || pf == "has_theme_font_override" || pf == "get_theme_font" || pf == "remove_theme_font_override") { type = Theme::DATA_TYPE_FONT; - } else if (pf == "add_theme_font_size_override" || pf == "has_theme_font_size" || pf == "has_theme_font_size_override" || pf == "get_theme_font_size") { + } else if (pf == "add_theme_font_size_override" || pf == "has_theme_font_size" || pf == "has_theme_font_size_override" || pf == "get_theme_font_size" || pf == "remove_theme_font_size_override") { type = Theme::DATA_TYPE_FONT_SIZE; - } else if (pf == "add_theme_icon_override" || pf == "has_theme_icon" || pf == "has_theme_icon_override" || pf == "get_theme_icon") { + } else if (pf == "add_theme_icon_override" || pf == "has_theme_icon" || pf == "has_theme_icon_override" || pf == "get_theme_icon" || pf == "remove_theme_icon_override") { type = Theme::DATA_TYPE_ICON; - } else if (pf == "add_theme_style_override" || pf == "has_theme_style" || pf == "has_theme_style_override" || pf == "get_theme_style") { + } else if (pf == "add_theme_stylebox_override" || pf == "has_theme_stylebox" || pf == "has_theme_stylebox_override" || pf == "get_theme_stylebox" || pf == "remove_theme_stylebox_override") { type = Theme::DATA_TYPE_STYLEBOX; } @@ -1606,7 +1605,7 @@ void Control::_update_minimum_size() { if (minsize != data.last_minimum_size) { data.last_minimum_size = minsize; _size_changed(); - emit_signal(SceneStringNames::get_singleton()->minimum_size_changed); + emit_signal(SceneStringName(minimum_size_changed)); } } @@ -1770,7 +1769,7 @@ void Control::set_h_size_flags(BitField<SizeFlags> p_flags) { return; } data.h_size_flags = p_flags; - emit_signal(SceneStringNames::get_singleton()->size_flags_changed); + emit_signal(SceneStringName(size_flags_changed)); } BitField<Control::SizeFlags> Control::get_h_size_flags() const { @@ -1784,7 +1783,7 @@ void Control::set_v_size_flags(BitField<SizeFlags> p_flags) { return; } data.v_size_flags = p_flags; - emit_signal(SceneStringNames::get_singleton()->size_flags_changed); + emit_signal(SceneStringName(size_flags_changed)); } BitField<Control::SizeFlags> Control::get_v_size_flags() const { @@ -1799,7 +1798,7 @@ void Control::set_stretch_ratio(real_t p_ratio) { } data.expand = p_ratio; - emit_signal(SceneStringNames::get_singleton()->size_flags_changed); + emit_signal(SceneStringName(size_flags_changed)); } real_t Control::get_stretch_ratio() const { @@ -1811,7 +1810,7 @@ real_t Control::get_stretch_ratio() const { void Control::_call_gui_input(const Ref<InputEvent> &p_event) { if (p_event->get_device() != InputEvent::DEVICE_ID_INTERNAL) { - emit_signal(SceneStringNames::get_singleton()->gui_input, p_event); // Signal should be first, so it's possible to override an event (and then accept it). + emit_signal(SceneStringName(gui_input), p_event); // Signal should be first, so it's possible to override an event (and then accept it). } if (!is_inside_tree() || get_viewport()->is_input_handled()) { return; // Input was handled, abort. @@ -3223,7 +3222,7 @@ void Control::_notification(int p_notification) { case NOTIFICATION_READY: { #ifdef DEBUG_ENABLED - connect("ready", callable_mp(this, &Control::_clear_size_warning), CONNECT_DEFERRED | CONNECT_ONE_SHOT); + connect(SceneStringName(ready), callable_mp(this, &Control::_clear_size_warning), CONNECT_DEFERRED | CONNECT_ONE_SHOT); #endif } break; @@ -3262,7 +3261,7 @@ void Control::_notification(int p_notification) { data.parent_canvas_item = get_parent_item(); if (data.parent_canvas_item) { - data.parent_canvas_item->connect("item_rect_changed", callable_mp(this, &Control::_size_changed)); + data.parent_canvas_item->connect(SceneStringName(item_rect_changed), callable_mp(this, &Control::_size_changed)); } else { // Connect viewport. Viewport *viewport = get_viewport(); @@ -3273,7 +3272,7 @@ void Control::_notification(int p_notification) { case NOTIFICATION_EXIT_CANVAS: { if (data.parent_canvas_item) { - data.parent_canvas_item->disconnect("item_rect_changed", callable_mp(this, &Control::_size_changed)); + data.parent_canvas_item->disconnect(SceneStringName(item_rect_changed), callable_mp(this, &Control::_size_changed)); data.parent_canvas_item = nullptr; } else { // Disconnect viewport. @@ -3299,7 +3298,7 @@ void Control::_notification(int p_notification) { } break; case NOTIFICATION_RESIZED: { - emit_signal(SceneStringNames::get_singleton()->resized); + emit_signal(SceneStringName(resized)); } break; case NOTIFICATION_DRAW: { @@ -3309,25 +3308,25 @@ void Control::_notification(int p_notification) { } break; case NOTIFICATION_MOUSE_ENTER: { - emit_signal(SceneStringNames::get_singleton()->mouse_entered); + emit_signal(SceneStringName(mouse_entered)); } break; case NOTIFICATION_MOUSE_EXIT: { - emit_signal(SceneStringNames::get_singleton()->mouse_exited); + emit_signal(SceneStringName(mouse_exited)); } break; case NOTIFICATION_FOCUS_ENTER: { - emit_signal(SceneStringNames::get_singleton()->focus_entered); + emit_signal(SceneStringName(focus_entered)); queue_redraw(); } break; case NOTIFICATION_FOCUS_EXIT: { - emit_signal(SceneStringNames::get_singleton()->focus_exited); + emit_signal(SceneStringName(focus_exited)); queue_redraw(); } break; case NOTIFICATION_THEME_CHANGED: { - emit_signal(SceneStringNames::get_singleton()->theme_changed); + emit_signal(SceneStringName(theme_changed)); _invalidate_theme_cache(); _update_theme_item_cache(); diff --git a/scene/gui/dialogs.cpp b/scene/gui/dialogs.cpp index 4d2080dda2..3d8be38fbd 100644 --- a/scene/gui/dialogs.cpp +++ b/scene/gui/dialogs.cpp @@ -47,7 +47,7 @@ void AcceptDialog::_input_from_window(const Ref<InputEvent> &p_event) { } void AcceptDialog::_parent_focused() { - if (!is_exclusive() && get_flag(FLAG_POPUP)) { + if (popped_up && !is_exclusive() && get_flag(FLAG_POPUP)) { _cancel_pressed(); } } @@ -68,16 +68,25 @@ void AcceptDialog::_notification(int p_what) { parent_visible = get_parent_visible_window(); if (parent_visible) { - parent_visible->connect("focus_entered", callable_mp(this, &AcceptDialog::_parent_focused)); + parent_visible->connect(SceneStringName(focus_entered), callable_mp(this, &AcceptDialog::_parent_focused)); } } else { + popped_up = false; if (parent_visible) { - parent_visible->disconnect("focus_entered", callable_mp(this, &AcceptDialog::_parent_focused)); + parent_visible->disconnect(SceneStringName(focus_entered), callable_mp(this, &AcceptDialog::_parent_focused)); parent_visible = nullptr; } } } break; + case NOTIFICATION_WM_WINDOW_FOCUS_IN: { + if (!is_in_edited_scene_root()) { + if (has_focus()) { + popped_up = true; + } + } + } break; + case NOTIFICATION_THEME_CHANGED: { bg_panel->add_theme_style_override("panel", theme_cache.panel_style); @@ -89,7 +98,7 @@ void AcceptDialog::_notification(int p_what) { case NOTIFICATION_EXIT_TREE: { if (parent_visible) { - parent_visible->disconnect("focus_entered", callable_mp(this, &AcceptDialog::_parent_focused)); + parent_visible->disconnect(SceneStringName(focus_entered), callable_mp(this, &AcceptDialog::_parent_focused)); parent_visible = nullptr; } } break; @@ -114,8 +123,14 @@ void AcceptDialog::_text_submitted(const String &p_text) { _ok_pressed(); } +void AcceptDialog::_post_popup() { + Window::_post_popup(); + popped_up = true; +} + void AcceptDialog::_ok_pressed() { if (hide_on_ok) { + popped_up = false; set_visible(false); } ok_pressed(); @@ -124,9 +139,10 @@ void AcceptDialog::_ok_pressed() { } void AcceptDialog::_cancel_pressed() { + popped_up = false; Window *parent_window = parent_visible; if (parent_visible) { - parent_visible->disconnect("focus_entered", callable_mp(this, &AcceptDialog::_parent_focused)); + parent_visible->disconnect(SceneStringName(focus_entered), callable_mp(this, &AcceptDialog::_parent_focused)); parent_visible = nullptr; } @@ -308,7 +324,7 @@ Button *AcceptDialog::add_button(const String &p_text, bool p_right, const Strin } button->set_meta("__right_spacer", right_spacer); - button->connect("visibility_changed", callable_mp(this, &AcceptDialog::_custom_button_visibility_changed).bind(button)); + button->connect(SceneStringName(visibility_changed), callable_mp(this, &AcceptDialog::_custom_button_visibility_changed).bind(button)); child_controls_changed(); if (is_visible()) { @@ -316,7 +332,7 @@ Button *AcceptDialog::add_button(const String &p_text, bool p_right, const Strin } if (!p_action.is_empty()) { - button->connect("pressed", callable_mp(this, &AcceptDialog::_custom_action).bind(p_action)); + button->connect(SceneStringName(pressed), callable_mp(this, &AcceptDialog::_custom_action).bind(p_action)); } return button; @@ -330,7 +346,7 @@ Button *AcceptDialog::add_cancel_button(const String &p_cancel) { Button *b = swap_cancel_ok ? add_button(c, true) : add_button(c); - b->connect("pressed", callable_mp(this, &AcceptDialog::_cancel_pressed)); + b->connect(SceneStringName(pressed), callable_mp(this, &AcceptDialog::_cancel_pressed)); return b; } @@ -345,12 +361,12 @@ void AcceptDialog::remove_button(Button *p_button) { ERR_FAIL_COND_MSG(right_spacer->get_parent() != buttons_hbox, vformat("Cannot remove button %s as its associated spacer does not belong to this dialog.", p_button->get_name())); } - p_button->disconnect("visibility_changed", callable_mp(this, &AcceptDialog::_custom_button_visibility_changed)); - if (p_button->is_connected("pressed", callable_mp(this, &AcceptDialog::_custom_action))) { - p_button->disconnect("pressed", callable_mp(this, &AcceptDialog::_custom_action)); + p_button->disconnect(SceneStringName(visibility_changed), callable_mp(this, &AcceptDialog::_custom_button_visibility_changed)); + if (p_button->is_connected(SceneStringName(pressed), callable_mp(this, &AcceptDialog::_custom_action))) { + p_button->disconnect(SceneStringName(pressed), callable_mp(this, &AcceptDialog::_custom_action)); } - if (p_button->is_connected("pressed", callable_mp(this, &AcceptDialog::_cancel_pressed))) { - p_button->disconnect("pressed", callable_mp(this, &AcceptDialog::_cancel_pressed)); + if (p_button->is_connected(SceneStringName(pressed), callable_mp(this, &AcceptDialog::_cancel_pressed))) { + p_button->disconnect(SceneStringName(pressed), callable_mp(this, &AcceptDialog::_cancel_pressed)); } if (right_spacer) { @@ -433,7 +449,7 @@ AcceptDialog::AcceptDialog() { buttons_hbox->add_child(ok_button); buttons_hbox->add_spacer(); - ok_button->connect("pressed", callable_mp(this, &AcceptDialog::_ok_pressed)); + ok_button->connect(SceneStringName(pressed), callable_mp(this, &AcceptDialog::_ok_pressed)); set_title(ETR("Alert!")); } diff --git a/scene/gui/dialogs.h b/scene/gui/dialogs.h index 12b48c903a..404237bfd8 100644 --- a/scene/gui/dialogs.h +++ b/scene/gui/dialogs.h @@ -51,6 +51,7 @@ class AcceptDialog : public Window { HBoxContainer *buttons_hbox = nullptr; Button *ok_button = nullptr; + bool popped_up = false; bool hide_on_ok = true; bool close_on_escape = true; @@ -72,6 +73,7 @@ class AcceptDialog : public Window { protected: virtual Size2 _get_contents_minimum_size() const override; virtual void _input_from_window(const Ref<InputEvent> &p_event) override; + virtual void _post_popup() override; void _notification(int p_what); static void _bind_methods(); diff --git a/scene/gui/file_dialog.cpp b/scene/gui/file_dialog.cpp index 97a2917dc1..0c146ce173 100644 --- a/scene/gui/file_dialog.cpp +++ b/scene/gui/file_dialog.cpp @@ -1344,6 +1344,7 @@ void FileDialog::_bind_methods() { Option defaults; base_property_helper.set_prefix("option_"); + base_property_helper.set_array_length_getter(&FileDialog::get_option_count); base_property_helper.register_property(PropertyInfo(Variant::STRING, "name"), defaults.name, &FileDialog::set_option_name, &FileDialog::get_option_name); base_property_helper.register_property(PropertyInfo(Variant::PACKED_STRING_ARRAY, "values"), defaults.values, &FileDialog::set_option_values, &FileDialog::get_option_values); base_property_helper.register_property(PropertyInfo(Variant::INT, "default"), defaults.default_idx, &FileDialog::set_option_default, &FileDialog::get_option_default); @@ -1408,9 +1409,9 @@ FileDialog::FileDialog() { hbc->add_child(dir_prev); hbc->add_child(dir_next); hbc->add_child(dir_up); - dir_prev->connect("pressed", callable_mp(this, &FileDialog::_go_back)); - dir_next->connect("pressed", callable_mp(this, &FileDialog::_go_forward)); - dir_up->connect("pressed", callable_mp(this, &FileDialog::_go_up)); + dir_prev->connect(SceneStringName(pressed), callable_mp(this, &FileDialog::_go_back)); + dir_next->connect(SceneStringName(pressed), callable_mp(this, &FileDialog::_go_forward)); + dir_up->connect(SceneStringName(pressed), callable_mp(this, &FileDialog::_go_up)); hbc->add_child(memnew(Label(ETR("Path:")))); @@ -1429,7 +1430,7 @@ FileDialog::FileDialog() { refresh = memnew(Button); refresh->set_theme_type_variation("FlatButton"); refresh->set_tooltip_text(ETR("Refresh files.")); - refresh->connect("pressed", callable_mp(this, &FileDialog::update_file_list)); + refresh->connect(SceneStringName(pressed), callable_mp(this, &FileDialog::update_file_list)); hbc->add_child(refresh); show_hidden = memnew(Button); @@ -1446,7 +1447,7 @@ FileDialog::FileDialog() { makedir = memnew(Button); makedir->set_theme_type_variation("FlatButton"); makedir->set_tooltip_text(ETR("Create a new folder.")); - makedir->connect("pressed", callable_mp(this, &FileDialog::_make_dir)); + makedir->connect(SceneStringName(pressed), callable_mp(this, &FileDialog::_make_dir)); hbc->add_child(makedir); vbox->add_child(hbc); diff --git a/scene/gui/graph_edit.cpp b/scene/gui/graph_edit.cpp index 646e45b27a..6c2a61d255 100644 --- a/scene/gui/graph_edit.cpp +++ b/scene/gui/graph_edit.cpp @@ -601,7 +601,7 @@ void GraphEdit::add_child_notify(Node *p_child) { GraphNode *graph_node = Object::cast_to<GraphNode>(graph_element); if (graph_node) { graph_node->connect("slot_updated", callable_mp(this, &GraphEdit::_graph_node_slot_updated).bind(graph_element)); - graph_node->connect("item_rect_changed", callable_mp(this, &GraphEdit::_graph_node_rect_changed).bind(graph_node)); + graph_node->connect(SceneStringName(item_rect_changed), callable_mp(this, &GraphEdit::_graph_node_rect_changed).bind(graph_node)); _ensure_node_order_from(graph_node); } @@ -618,8 +618,8 @@ void GraphEdit::add_child_notify(Node *p_child) { } graph_element->connect("raise_request", callable_mp(this, &GraphEdit::_ensure_node_order_from).bind(graph_element)); graph_element->connect("resize_request", callable_mp(this, &GraphEdit::_graph_element_resize_request).bind(graph_element)); - graph_element->connect("item_rect_changed", callable_mp((CanvasItem *)connections_layer, &CanvasItem::queue_redraw)); - graph_element->connect("item_rect_changed", callable_mp((CanvasItem *)minimap, &GraphEditMinimap::queue_redraw)); + graph_element->connect(SceneStringName(item_rect_changed), callable_mp((CanvasItem *)connections_layer, &CanvasItem::queue_redraw)); + graph_element->connect(SceneStringName(item_rect_changed), callable_mp((CanvasItem *)minimap, &GraphEditMinimap::queue_redraw)); graph_element->set_scale(Vector2(zoom, zoom)); _graph_element_moved(graph_element); @@ -651,7 +651,7 @@ void GraphEdit::remove_child_notify(Node *p_child) { GraphNode *graph_node = Object::cast_to<GraphNode>(graph_element); if (graph_node) { graph_node->disconnect("slot_updated", callable_mp(this, &GraphEdit::_graph_node_slot_updated)); - graph_node->disconnect("item_rect_changed", callable_mp(this, &GraphEdit::_graph_node_rect_changed)); + graph_node->disconnect(SceneStringName(item_rect_changed), callable_mp(this, &GraphEdit::_graph_node_rect_changed)); // Invalidate all adjacent connections, so that they are removed before the next redraw. for (const Ref<Connection> &conn : connection_map[graph_node->get_name()]) { @@ -692,7 +692,7 @@ void GraphEdit::remove_child_notify(Node *p_child) { // In case of the whole GraphEdit being destroyed these references can already be freed. if (minimap != nullptr && minimap->is_inside_tree()) { - graph_element->disconnect("item_rect_changed", callable_mp((CanvasItem *)minimap, &GraphEditMinimap::queue_redraw)); + graph_element->disconnect(SceneStringName(item_rect_changed), callable_mp((CanvasItem *)minimap, &GraphEditMinimap::queue_redraw)); } } } @@ -898,6 +898,12 @@ bool GraphEdit::_filter_input(const Point2 &p_point) { return true; } } + + // This prevents interactions with a port hotzone that is behind another node. + Rect2 graph_node_rect = Rect2(graph_node->get_position(), graph_node->get_size() * zoom); + if (graph_node_rect.has_point(click_pos * zoom)) { + break; + } } return false; @@ -1027,6 +1033,12 @@ void GraphEdit::_top_connection_layer_input(const Ref<InputEvent> &p_ev) { return; } } + + // This prevents interactions with a port hotzone that is behind another node. + Rect2 graph_node_rect = Rect2(graph_node->get_position(), graph_node->get_size() * zoom); + if (graph_node_rect.has_point(click_pos * zoom)) { + break; + } } } @@ -1059,7 +1071,7 @@ void GraphEdit::_top_connection_layer_input(const Ref<InputEvent> &p_ev) { port_size.height = MAX(port_size.height, child ? child->get_size().y : 0); int type = graph_node->get_output_port_type(j); - if ((type == connecting_type || + if ((type == connecting_type || graph_node->is_ignoring_valid_connection_type() || valid_connection_types.has(ConnectionType(type, connecting_type))) && is_in_output_hotzone(graph_node, j, mpos, port_size)) { if (!is_node_hover_valid(graph_node->get_name(), j, connecting_from_node, connecting_from_port_index)) { @@ -1084,7 +1096,7 @@ void GraphEdit::_top_connection_layer_input(const Ref<InputEvent> &p_ev) { port_size.height = MAX(port_size.height, child ? child->get_size().y : 0); int type = graph_node->get_input_port_type(j); - if ((type == connecting_type || valid_connection_types.has(ConnectionType(connecting_type, type))) && + if ((type == connecting_type || graph_node->is_ignoring_valid_connection_type() || valid_connection_types.has(ConnectionType(connecting_type, type))) && is_in_input_hotzone(graph_node, j, mpos, port_size)) { if (!is_node_hover_valid(connecting_from_node, connecting_from_port_index, graph_node->get_name(), j)) { continue; @@ -1117,6 +1129,8 @@ void GraphEdit::_top_connection_layer_input(const Ref<InputEvent> &p_ev) { emit_signal(SNAME("connection_from_empty"), connecting_from_node, connecting_from_port_index, mb->get_position()); } } + } else { + set_selected(get_node_or_null(NodePath(connecting_from_node))); } if (connecting) { @@ -1285,18 +1299,26 @@ List<Ref<GraphEdit::Connection>> GraphEdit::get_connections_intersecting_with_re return intersecting_connections; } -void GraphEdit::_draw_minimap_connection_line(CanvasItem *p_where, const Vector2 &p_from, const Vector2 &p_to, const Color &p_from_color, const Color &p_to_color) { - const Vector<Vector2> &points = get_connection_line(p_from, p_to); +void GraphEdit::_draw_minimap_connection_line(const Vector2 &p_from_graph_position, const Vector2 &p_to_graph_position, const Color &p_from_color, const Color &p_to_color) { + Vector<Vector2> points = get_connection_line(p_from_graph_position, p_to_graph_position); + ERR_FAIL_COND_MSG(points.size() < 2, "\"_get_connection_line()\" returned an invalid line."); + // Convert to minimap points. + for (Vector2 &point : points) { + point = minimap->_convert_from_graph_position(point) + minimap->minimap_offset; + } + + // Setup polyline colors. LocalVector<Color> colors; colors.reserve(points.size()); - - float length_inv = 1.0 / (p_from).distance_to(p_to); + const Vector2 &from = points[0]; + const Vector2 &to = points[points.size() - 1]; + float length_inv = 1.0 / (from).distance_to(to); for (const Vector2 &point : points) { - float normalized_curve_position = (p_from).distance_to(point) * length_inv; + float normalized_curve_position = from.distance_to(point) * length_inv; colors.push_back(p_from_color.lerp(p_to_color, normalized_curve_position)); } - p_where->draw_polyline_colors(points, colors, 0.5, lines_antialiased); + minimap->draw_polyline_colors(points, colors, 0.5, lines_antialiased); } void GraphEdit::_update_connections() { @@ -1551,8 +1573,8 @@ void GraphEdit::_minimap_draw() { // Draw node connections. for (const Ref<Connection> &c : connections) { - Vector2 from_position = minimap->_convert_from_graph_position(c->_cache.from_pos * zoom - graph_offset) + minimap_offset; - Vector2 to_position = minimap->_convert_from_graph_position(c->_cache.to_pos * zoom - graph_offset) + minimap_offset; + Vector2 from_graph_position = c->_cache.from_pos * zoom - graph_offset; + Vector2 to_graph_position = c->_cache.to_pos * zoom - graph_offset; Color from_color = c->_cache.from_color; Color to_color = c->_cache.to_color; @@ -1560,7 +1582,8 @@ void GraphEdit::_minimap_draw() { from_color = from_color.lerp(theme_cache.activity_color, c->activity); to_color = to_color.lerp(theme_cache.activity_color, c->activity); } - _draw_minimap_connection_line(minimap, from_position, to_position, from_color, to_color); + + _draw_minimap_connection_line(from_graph_position, to_graph_position, from_color, to_color); } // Draw the "camera" viewport. @@ -1636,12 +1659,12 @@ void GraphEdit::_draw_grid() { void GraphEdit::set_selected(Node *p_child) { for (int i = get_child_count() - 1; i >= 0; i--) { - GraphNode *graph_node = Object::cast_to<GraphNode>(get_child(i)); - if (!graph_node) { + GraphElement *graph_element = Object::cast_to<GraphElement>(get_child(i)); + if (!graph_element) { continue; } - graph_node->set_selected(graph_node == p_child); + graph_element->set_selected(graph_element == p_child); } } @@ -2755,12 +2778,12 @@ GraphEdit::GraphEdit() { add_child(top_layer, false, INTERNAL_MODE_BACK); top_layer->set_mouse_filter(MOUSE_FILTER_IGNORE); top_layer->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT); - top_layer->connect("draw", callable_mp(this, &GraphEdit::_top_layer_draw)); - top_layer->connect("focus_exited", callable_mp(panner.ptr(), &ViewPanner::release_pan_key)); + top_layer->connect(SceneStringName(draw), callable_mp(this, &GraphEdit::_top_layer_draw)); + top_layer->connect(SceneStringName(focus_exited), callable_mp(panner.ptr(), &ViewPanner::release_pan_key)); connections_layer = memnew(Control); add_child(connections_layer, false); - connections_layer->connect("draw", callable_mp(this, &GraphEdit::_update_connections)); + connections_layer->connect(SceneStringName(draw), callable_mp(this, &GraphEdit::_update_connections)); connections_layer->set_name("_connection_layer"); connections_layer->set_disable_visibility_clip(true); // Necessary, so it can draw freely and be offset. connections_layer->set_mouse_filter(MOUSE_FILTER_IGNORE); @@ -2772,7 +2795,7 @@ GraphEdit::GraphEdit() { top_connection_layer->set_mouse_filter(MOUSE_FILTER_PASS); top_connection_layer->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT); - top_connection_layer->connect("gui_input", callable_mp(this, &GraphEdit::_top_connection_layer_input)); + top_connection_layer->connect(SceneStringName(gui_input), callable_mp(this, &GraphEdit::_top_connection_layer_input)); dragged_connection_line = memnew(Line2D); dragged_connection_line->set_texture_mode(Line2D::LINE_TEXTURE_STRETCH); @@ -2822,7 +2845,7 @@ GraphEdit::GraphEdit() { zoom_minus_button->set_tooltip_text(ETR("Zoom Out")); zoom_minus_button->set_focus_mode(FOCUS_NONE); menu_hbox->add_child(zoom_minus_button); - zoom_minus_button->connect("pressed", callable_mp(this, &GraphEdit::_zoom_minus)); + zoom_minus_button->connect(SceneStringName(pressed), callable_mp(this, &GraphEdit::_zoom_minus)); zoom_reset_button = memnew(Button); zoom_reset_button->set_theme_type_variation("FlatButton"); @@ -2830,7 +2853,7 @@ GraphEdit::GraphEdit() { zoom_reset_button->set_tooltip_text(ETR("Zoom Reset")); zoom_reset_button->set_focus_mode(FOCUS_NONE); menu_hbox->add_child(zoom_reset_button); - zoom_reset_button->connect("pressed", callable_mp(this, &GraphEdit::_zoom_reset)); + zoom_reset_button->connect(SceneStringName(pressed), callable_mp(this, &GraphEdit::_zoom_reset)); zoom_plus_button = memnew(Button); zoom_plus_button->set_theme_type_variation("FlatButton"); @@ -2838,7 +2861,7 @@ GraphEdit::GraphEdit() { zoom_plus_button->set_tooltip_text(ETR("Zoom In")); zoom_plus_button->set_focus_mode(FOCUS_NONE); menu_hbox->add_child(zoom_plus_button); - zoom_plus_button->connect("pressed", callable_mp(this, &GraphEdit::_zoom_plus)); + zoom_plus_button->connect(SceneStringName(pressed), callable_mp(this, &GraphEdit::_zoom_plus)); // Grid controls. @@ -2850,7 +2873,7 @@ GraphEdit::GraphEdit() { toggle_grid_button->set_tooltip_text(ETR("Toggle the visual grid.")); toggle_grid_button->set_focus_mode(FOCUS_NONE); menu_hbox->add_child(toggle_grid_button); - toggle_grid_button->connect("pressed", callable_mp(this, &GraphEdit::_show_grid_toggled)); + toggle_grid_button->connect(SceneStringName(pressed), callable_mp(this, &GraphEdit::_show_grid_toggled)); toggle_snapping_button = memnew(Button); toggle_snapping_button->set_theme_type_variation("FlatButton"); @@ -2860,7 +2883,7 @@ GraphEdit::GraphEdit() { toggle_snapping_button->set_pressed(snapping_enabled); toggle_snapping_button->set_focus_mode(FOCUS_NONE); menu_hbox->add_child(toggle_snapping_button); - toggle_snapping_button->connect("pressed", callable_mp(this, &GraphEdit::_snapping_toggled)); + toggle_snapping_button->connect(SceneStringName(pressed), callable_mp(this, &GraphEdit::_snapping_toggled)); snapping_distance_spinbox = memnew(SpinBox); snapping_distance_spinbox->set_visible(show_grid_buttons); @@ -2882,12 +2905,12 @@ GraphEdit::GraphEdit() { minimap_button->set_pressed(show_grid); minimap_button->set_focus_mode(FOCUS_NONE); menu_hbox->add_child(minimap_button); - minimap_button->connect("pressed", callable_mp(this, &GraphEdit::_minimap_toggled)); + minimap_button->connect(SceneStringName(pressed), callable_mp(this, &GraphEdit::_minimap_toggled)); arrange_button = memnew(Button); arrange_button->set_theme_type_variation("FlatButton"); arrange_button->set_visible(show_arrange_button); - arrange_button->connect("pressed", callable_mp(this, &GraphEdit::arrange_nodes)); + arrange_button->connect(SceneStringName(pressed), callable_mp(this, &GraphEdit::arrange_nodes)); arrange_button->set_focus_mode(FOCUS_NONE); menu_hbox->add_child(arrange_button); arrange_button->set_tooltip_text(ETR("Automatically arrange selected nodes.")); @@ -2909,7 +2932,7 @@ GraphEdit::GraphEdit() { minimap->set_offset(Side::SIDE_TOP, -minimap_size.height - MINIMAP_OFFSET); minimap->set_offset(Side::SIDE_RIGHT, -MINIMAP_OFFSET); minimap->set_offset(Side::SIDE_BOTTOM, -MINIMAP_OFFSET); - minimap->connect("draw", callable_mp(this, &GraphEdit::_minimap_draw)); + minimap->connect(SceneStringName(draw), callable_mp(this, &GraphEdit::_minimap_draw)); set_clip_contents(true); diff --git a/scene/gui/graph_edit.h b/scene/gui/graph_edit.h index eeda9ae200..20c98c462c 100644 --- a/scene/gui/graph_edit.h +++ b/scene/gui/graph_edit.h @@ -328,7 +328,7 @@ private: void _top_connection_layer_input(const Ref<InputEvent> &p_ev); float _get_shader_line_width(); - void _draw_minimap_connection_line(CanvasItem *p_where, const Vector2 &p_from, const Vector2 &p_to, const Color &p_color, const Color &p_to_color); + void _draw_minimap_connection_line(const Vector2 &p_from_graph_position, const Vector2 &p_to_graph_position, const Color &p_from_color, const Color &p_to_color); void _invalidate_connection_line_cache(); void _update_top_connection_layer(); void _update_connections(); diff --git a/scene/gui/graph_node.cpp b/scene/gui/graph_node.cpp index 75ac5c5135..d804f83e1c 100644 --- a/scene/gui/graph_node.cpp +++ b/scene/gui/graph_node.cpp @@ -604,6 +604,14 @@ void GraphNode::set_slot_draw_stylebox(int p_slot_index, bool p_enable) { emit_signal(SNAME("slot_updated"), p_slot_index); } +void GraphNode::set_ignore_invalid_connection_type(bool p_ignore) { + ignore_invalid_connection_type = p_ignore; +} + +bool GraphNode::is_ignoring_valid_connection_type() const { + return ignore_invalid_connection_type; +} + Size2 GraphNode::get_minimum_size() const { Ref<StyleBox> sb_panel = theme_cache.panel; Ref<StyleBox> sb_titlebar = theme_cache.titlebar; @@ -859,6 +867,9 @@ void GraphNode::_bind_methods() { ClassDB::bind_method(D_METHOD("is_slot_draw_stylebox", "slot_index"), &GraphNode::is_slot_draw_stylebox); ClassDB::bind_method(D_METHOD("set_slot_draw_stylebox", "slot_index", "enable"), &GraphNode::set_slot_draw_stylebox); + ClassDB::bind_method(D_METHOD("set_ignore_invalid_connection_type", "ignore"), &GraphNode::set_ignore_invalid_connection_type); + ClassDB::bind_method(D_METHOD("is_ignoring_valid_connection_type"), &GraphNode::is_ignoring_valid_connection_type); + ClassDB::bind_method(D_METHOD("get_input_port_count"), &GraphNode::get_input_port_count); ClassDB::bind_method(D_METHOD("get_input_port_position", "port_idx"), &GraphNode::get_input_port_position); ClassDB::bind_method(D_METHOD("get_input_port_type", "port_idx"), &GraphNode::get_input_port_type); @@ -874,6 +885,8 @@ void GraphNode::_bind_methods() { GDVIRTUAL_BIND(_draw_port, "slot_index", "position", "left", "color") ADD_PROPERTY(PropertyInfo(Variant::STRING, "title"), "set_title", "get_title"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "ignore_invalid_connection_type"), "set_ignore_invalid_connection_type", "is_ignoring_valid_connection_type"); + ADD_SIGNAL(MethodInfo("slot_updated", PropertyInfo(Variant::INT, "slot_index"))); BIND_THEME_ITEM(Theme::DATA_TYPE_STYLEBOX, GraphNode, panel); diff --git a/scene/gui/graph_node.h b/scene/gui/graph_node.h index 71cc322baa..27af3192c8 100644 --- a/scene/gui/graph_node.h +++ b/scene/gui/graph_node.h @@ -95,6 +95,8 @@ class GraphNode : public GraphElement { bool port_pos_dirty = true; + bool ignore_invalid_connection_type = false; + void _port_pos_update(); protected: @@ -147,6 +149,9 @@ public: bool is_slot_draw_stylebox(int p_slot_index) const; void set_slot_draw_stylebox(int p_slot_index, bool p_enable); + void set_ignore_invalid_connection_type(bool p_ignore); + bool is_ignoring_valid_connection_type() const; + int get_input_port_count(); Vector2 get_input_port_position(int p_port_idx); int get_input_port_type(int p_port_idx); diff --git a/scene/gui/item_list.cpp b/scene/gui/item_list.cpp index 8376ef48b6..cfb46aebc8 100644 --- a/scene/gui/item_list.cpp +++ b/scene/gui/item_list.cpp @@ -1882,6 +1882,7 @@ void ItemList::_bind_methods() { Item defaults(true); base_property_helper.set_prefix("item_"); + base_property_helper.set_array_length_getter(&ItemList::get_item_count); base_property_helper.register_property(PropertyInfo(Variant::STRING, "text"), defaults.text, &ItemList::set_item_text, &ItemList::get_item_text); base_property_helper.register_property(PropertyInfo(Variant::OBJECT, "icon", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), defaults.icon, &ItemList::set_item_icon, &ItemList::get_item_icon); base_property_helper.register_property(PropertyInfo(Variant::BOOL, "selectable"), defaults.selectable, &ItemList::set_item_selectable, &ItemList::is_item_selectable); @@ -1893,7 +1894,7 @@ ItemList::ItemList() { add_child(scroll_bar, false, INTERNAL_MODE_FRONT); scroll_bar->connect("value_changed", callable_mp(this, &ItemList::_scroll_changed)); - connect("mouse_exited", callable_mp(this, &ItemList::_mouse_exited)); + connect(SceneStringName(mouse_exited), callable_mp(this, &ItemList::_mouse_exited)); set_focus_mode(FOCUS_ALL); set_clip_contents(true); diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp index c263e14b8a..729e219825 100644 --- a/scene/gui/line_edit.cpp +++ b/scene/gui/line_edit.cpp @@ -2473,8 +2473,8 @@ void LineEdit::_generate_context_menu() { menu_dir->connect("id_pressed", callable_mp(this, &LineEdit::menu_option)); menu_ctl->connect("id_pressed", callable_mp(this, &LineEdit::menu_option)); - menu->connect(SNAME("focus_entered"), callable_mp(this, &LineEdit::_validate_caret_can_draw)); - menu->connect(SNAME("focus_exited"), callable_mp(this, &LineEdit::_validate_caret_can_draw)); + menu->connect(SceneStringName(focus_entered), callable_mp(this, &LineEdit::_validate_caret_can_draw)); + menu->connect(SceneStringName(focus_exited), callable_mp(this, &LineEdit::_validate_caret_can_draw)); } void LineEdit::_update_context_menu() { diff --git a/scene/gui/margin_container.cpp b/scene/gui/margin_container.cpp index 91e6c1f092..06e4a7cc13 100644 --- a/scene/gui/margin_container.cpp +++ b/scene/gui/margin_container.cpp @@ -36,8 +36,8 @@ Size2 MarginContainer::get_minimum_size() const { Size2 max; for (int i = 0; i < get_child_count(); i++) { - Control *c = as_sortable_control(get_child(i)); - if (!c) { + Control *c = Object::cast_to<Control>(get_child(i)); + if (!c || !c->is_visible() || c->is_set_as_top_level()) { continue; } diff --git a/scene/gui/menu_button.cpp b/scene/gui/menu_button.cpp index e83d9c7c1b..998f99b2f9 100644 --- a/scene/gui/menu_button.cpp +++ b/scene/gui/menu_button.cpp @@ -190,6 +190,7 @@ void MenuButton::_bind_methods() { PopupMenu::Item defaults(true); base_property_helper.set_prefix("popup/item_"); + base_property_helper.set_array_length_getter(&MenuButton::get_item_count); base_property_helper.register_property(PropertyInfo(Variant::STRING, "text"), defaults.text); base_property_helper.register_property(PropertyInfo(Variant::OBJECT, "icon", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), defaults.icon); base_property_helper.register_property(PropertyInfo(Variant::INT, "checkable", PROPERTY_HINT_ENUM, "No,As Checkbox,As Radio Button"), defaults.checkable_type); diff --git a/scene/gui/nine_patch_rect.cpp b/scene/gui/nine_patch_rect.cpp index e2ae824e60..f9181d2a2d 100644 --- a/scene/gui/nine_patch_rect.cpp +++ b/scene/gui/nine_patch_rect.cpp @@ -30,7 +30,6 @@ #include "nine_patch_rect.h" -#include "scene/scene_string_names.h" #include "servers/rendering_server.h" void NinePatchRect::_notification(int p_what) { @@ -111,7 +110,7 @@ void NinePatchRect::set_texture(const Ref<Texture2D> &p_tex) { queue_redraw(); update_minimum_size(); - emit_signal(SceneStringNames::get_singleton()->texture_changed); + emit_signal(SceneStringName(texture_changed)); } Ref<Texture2D> NinePatchRect::get_texture() const { diff --git a/scene/gui/option_button.cpp b/scene/gui/option_button.cpp index 509c6aca99..68e72ea996 100644 --- a/scene/gui/option_button.cpp +++ b/scene/gui/option_button.cpp @@ -60,7 +60,7 @@ Size2 OptionButton::get_minimum_size() const { } if (has_theme_icon(SNAME("arrow"))) { - const Size2 padding = _get_current_stylebox()->get_minimum_size(); + const Size2 padding = _get_largest_stylebox_size(); const Size2 arrow_size = theme_cache.arrow_icon->get_size(); Size2 content_size = minsize - padding; @@ -571,6 +571,7 @@ void OptionButton::_bind_methods() { PopupMenu::Item defaults(true); base_property_helper.set_prefix("popup/item_"); + base_property_helper.set_array_length_getter(&OptionButton::get_item_count); base_property_helper.register_property(PropertyInfo(Variant::STRING, "text"), defaults.text, &OptionButton::_dummy_setter, &OptionButton::get_item_text); base_property_helper.register_property(PropertyInfo(Variant::OBJECT, "icon", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), defaults.icon, &OptionButton::_dummy_setter, &OptionButton::get_item_icon); base_property_helper.register_property(PropertyInfo(Variant::INT, "id", PROPERTY_HINT_RANGE, "0,10,1,or_greater"), defaults.id, &OptionButton::_dummy_setter, &OptionButton::get_item_id); diff --git a/scene/gui/popup.cpp b/scene/gui/popup.cpp index 97b33c4f74..38204af6d5 100644 --- a/scene/gui/popup.cpp +++ b/scene/gui/popup.cpp @@ -37,6 +37,7 @@ void Popup::_input_from_window(const Ref<InputEvent> &p_event) { if (get_flag(FLAG_POPUP) && p_event->is_action_pressed(SNAME("ui_cancel"), false, true)) { + hide_reason = HIDE_REASON_CANCELED; // ESC pressed, mark as canceled unconditionally. _close_pressed(); } Window::_input_from_window(p_event); @@ -51,8 +52,8 @@ void Popup::_initialize_visible_parents() { parent_window = parent_window->get_parent_visible_window(); if (parent_window) { visible_parents.push_back(parent_window); - parent_window->connect("focus_entered", callable_mp(this, &Popup::_parent_focused)); - parent_window->connect("tree_exited", callable_mp(this, &Popup::_deinitialize_visible_parents)); + parent_window->connect(SceneStringName(focus_entered), callable_mp(this, &Popup::_parent_focused)); + parent_window->connect(SceneStringName(tree_exited), callable_mp(this, &Popup::_deinitialize_visible_parents)); } } } @@ -61,8 +62,8 @@ void Popup::_initialize_visible_parents() { void Popup::_deinitialize_visible_parents() { if (is_embedded()) { for (Window *parent_window : visible_parents) { - parent_window->disconnect("focus_entered", callable_mp(this, &Popup::_parent_focused)); - parent_window->disconnect("tree_exited", callable_mp(this, &Popup::_deinitialize_visible_parents)); + parent_window->disconnect(SceneStringName(focus_entered), callable_mp(this, &Popup::_parent_focused)); + parent_window->disconnect(SceneStringName(tree_exited), callable_mp(this, &Popup::_deinitialize_visible_parents)); } visible_parents.clear(); @@ -104,13 +105,18 @@ void Popup::_notification(int p_what) { case NOTIFICATION_WM_CLOSE_REQUEST: { if (!is_in_edited_scene_root()) { - hide_reason = HIDE_REASON_UNFOCUSED; + if (hide_reason == HIDE_REASON_NONE) { + hide_reason = HIDE_REASON_UNFOCUSED; + } _close_pressed(); } } break; case NOTIFICATION_APPLICATION_FOCUS_OUT: { if (!is_in_edited_scene_root() && get_flag(FLAG_POPUP)) { + if (hide_reason == HIDE_REASON_NONE) { + hide_reason = HIDE_REASON_UNFOCUSED; + } _close_pressed(); } } break; @@ -119,7 +125,9 @@ void Popup::_notification(int p_what) { void Popup::_parent_focused() { if (popped_up && get_flag(FLAG_POPUP)) { - hide_reason = HIDE_REASON_UNFOCUSED; + if (hide_reason == HIDE_REASON_NONE) { + hide_reason = HIDE_REASON_UNFOCUSED; + } _close_pressed(); } } diff --git a/scene/gui/popup_menu.cpp b/scene/gui/popup_menu.cpp index 9b991972be..bdd0102b63 100644 --- a/scene/gui/popup_menu.cpp +++ b/scene/gui/popup_menu.cpp @@ -1014,9 +1014,6 @@ void PopupMenu::_notification(int p_what) { float pm_delay = pm->get_submenu_popup_delay(); set_submenu_popup_delay(pm_delay); } - if (!is_embedded()) { - set_flag(FLAG_NO_FOCUS, true); - } if (system_menu_id != NativeMenu::INVALID_MENU_ID) { bind_global_menu(); } @@ -2808,6 +2805,7 @@ void PopupMenu::_bind_methods() { Item defaults(true); base_property_helper.set_prefix("item_"); + base_property_helper.set_array_length_getter(&PopupMenu::get_item_count); base_property_helper.register_property(PropertyInfo(Variant::STRING, "text"), defaults.text, &PopupMenu::set_item_text, &PopupMenu::get_item_text); base_property_helper.register_property(PropertyInfo(Variant::OBJECT, "icon", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), defaults.icon, &PopupMenu::set_item_icon, &PopupMenu::get_item_icon); base_property_helper.register_property(PropertyInfo(Variant::INT, "checkable", PROPERTY_HINT_ENUM, "No,As checkbox,As radio button"), defaults.checkable_type, &PopupMenu::_set_item_checkable_type, &PopupMenu::_get_item_checkable_type); @@ -2828,6 +2826,8 @@ void PopupMenu::popup(const Rect2i &p_bounds) { if (native) { NativeMenu::get_singleton()->popup(global_menu, (p_bounds != Rect2i()) ? p_bounds.position : get_position()); } else { + set_flag(FLAG_NO_FOCUS, !is_embedded()); + moved = Vector2(); popup_time_msec = OS::get_singleton()->get_ticks_msec(); if (!is_embedded()) { @@ -2855,6 +2855,8 @@ void PopupMenu::set_visible(bool p_visible) { NativeMenu::get_singleton()->popup(global_menu, get_position()); } } else { + set_flag(FLAG_NO_FOCUS, !is_embedded()); + Popup::set_visible(p_visible); } } @@ -2873,7 +2875,7 @@ PopupMenu::PopupMenu() { control->set_h_size_flags(Control::SIZE_EXPAND_FILL); control->set_v_size_flags(Control::SIZE_EXPAND_FILL); scroll_container->add_child(control, false, INTERNAL_MODE_FRONT); - control->connect("draw", callable_mp(this, &PopupMenu::_draw_items)); + control->connect(SceneStringName(draw), callable_mp(this, &PopupMenu::_draw_items)); submenu_timer = memnew(Timer); submenu_timer->set_wait_time(0.3); diff --git a/scene/gui/range.cpp b/scene/gui/range.cpp index 236dfcc864..00f4a1089a 100644 --- a/scene/gui/range.cpp +++ b/scene/gui/range.cpp @@ -60,7 +60,7 @@ void Range::Shared::emit_value_changed() { } void Range::_changed_notify(const char *p_what) { - emit_signal(SNAME("changed")); + emit_signal(CoreStringName(changed)); queue_redraw(); } diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp index 19b02f33c6..f6942ca206 100644 --- a/scene/gui/rich_text_label.cpp +++ b/scene/gui/rich_text_label.cpp @@ -39,7 +39,6 @@ #include "scene/gui/label.h" #include "scene/gui/rich_text_effect.h" #include "scene/resources/atlas_texture.h" -#include "scene/scene_string_names.h" #include "scene/theme/theme_db.h" #include "servers/display_server.h" @@ -1608,8 +1607,34 @@ float RichTextLabel::_find_click_in_line(ItemFrame *p_frame, int p_line, const V if (p_meta) { int64_t glyph_idx = TS->shaped_text_hit_test_grapheme(rid, p_click.x - rect.position.x); if (glyph_idx >= 0) { + float baseline_y = rect.position.y + TS->shaped_text_get_ascent(rid); const Glyph *glyphs = TS->shaped_text_get_glyphs(rid); - char_pos = glyphs[glyph_idx].start; + if (glyphs[glyph_idx].flags & TextServer::GRAPHEME_IS_EMBEDDED_OBJECT) { + // Emebedded object. + for (int i = 0; i < objects.size(); i++) { + if (TS->shaped_text_get_object_glyph(rid, objects[i]) == glyph_idx) { + Rect2 obj_rect = TS->shaped_text_get_object_rect(rid, objects[i]); + obj_rect.position.y += baseline_y; + if (p_click.y >= obj_rect.position.y && p_click.y <= obj_rect.position.y + obj_rect.size.y) { + char_pos = glyphs[glyph_idx].start; + } + break; + } + } + } else if (glyphs[glyph_idx].font_rid != RID()) { + // Normal glyph. + float fa = TS->font_get_ascent(glyphs[glyph_idx].font_rid, glyphs[glyph_idx].font_size); + float fd = TS->font_get_descent(glyphs[glyph_idx].font_rid, glyphs[glyph_idx].font_size); + if (p_click.y >= baseline_y - fa && p_click.y <= baseline_y + fd) { + char_pos = glyphs[glyph_idx].start; + } + } else if (!(glyphs[glyph_idx].flags & TextServer::GRAPHEME_IS_VIRTUAL)) { + // Hex code box. + Vector2 gl_size = TS->get_hex_code_box_size(glyphs[glyph_idx].font_size, glyphs[glyph_idx].index); + if (p_click.y >= baseline_y - gl_size.y * 0.9 && p_click.y <= baseline_y + gl_size.y * 0.2) { + char_pos = glyphs[glyph_idx].start; + } + } } } else { char_pos = TS->shaped_text_hit_test_position(rid, p_click.x - rect.position.x); @@ -2993,7 +3018,7 @@ void RichTextLabel::_process_line_caches() { if (fit_content) { update_minimum_size(); } - emit_signal(SNAME("finished")); + emit_signal(SceneStringName(finished)); } void RichTextLabel::_invalidate_current_line(ItemFrame *p_frame) { diff --git a/scene/gui/scroll_bar.cpp b/scene/gui/scroll_bar.cpp index b35c4e9308..af9f08e389 100644 --- a/scene/gui/scroll_bar.cpp +++ b/scene/gui/scroll_bar.cpp @@ -310,15 +310,15 @@ void ScrollBar::_notification(int p_what) { } if (drag_node) { - drag_node->connect("gui_input", callable_mp(this, &ScrollBar::_drag_node_input)); - drag_node->connect("tree_exiting", callable_mp(this, &ScrollBar::_drag_node_exit), CONNECT_ONE_SHOT); + drag_node->connect(SceneStringName(gui_input), callable_mp(this, &ScrollBar::_drag_node_input)); + drag_node->connect(SceneStringName(tree_exiting), callable_mp(this, &ScrollBar::_drag_node_exit), CONNECT_ONE_SHOT); } } break; case NOTIFICATION_EXIT_TREE: { if (drag_node) { - drag_node->disconnect("gui_input", callable_mp(this, &ScrollBar::_drag_node_input)); - drag_node->disconnect("tree_exiting", callable_mp(this, &ScrollBar::_drag_node_exit)); + drag_node->disconnect(SceneStringName(gui_input), callable_mp(this, &ScrollBar::_drag_node_input)); + drag_node->disconnect(SceneStringName(tree_exiting), callable_mp(this, &ScrollBar::_drag_node_exit)); } drag_node = nullptr; @@ -522,7 +522,7 @@ float ScrollBar::get_custom_step() const { void ScrollBar::_drag_node_exit() { if (drag_node) { - drag_node->disconnect("gui_input", callable_mp(this, &ScrollBar::_drag_node_input)); + drag_node->disconnect(SceneStringName(gui_input), callable_mp(this, &ScrollBar::_drag_node_input)); } drag_node = nullptr; } @@ -591,8 +591,8 @@ void ScrollBar::_drag_node_input(const Ref<InputEvent> &p_input) { void ScrollBar::set_drag_node(const NodePath &p_path) { if (is_inside_tree()) { if (drag_node) { - drag_node->disconnect("gui_input", callable_mp(this, &ScrollBar::_drag_node_input)); - drag_node->disconnect("tree_exiting", callable_mp(this, &ScrollBar::_drag_node_exit)); + drag_node->disconnect(SceneStringName(gui_input), callable_mp(this, &ScrollBar::_drag_node_input)); + drag_node->disconnect(SceneStringName(tree_exiting), callable_mp(this, &ScrollBar::_drag_node_exit)); } } @@ -606,8 +606,8 @@ void ScrollBar::set_drag_node(const NodePath &p_path) { } if (drag_node) { - drag_node->connect("gui_input", callable_mp(this, &ScrollBar::_drag_node_input)); - drag_node->connect("tree_exiting", callable_mp(this, &ScrollBar::_drag_node_exit), CONNECT_ONE_SHOT); + drag_node->connect(SceneStringName(gui_input), callable_mp(this, &ScrollBar::_drag_node_input)); + drag_node->connect(SceneStringName(tree_exiting), callable_mp(this, &ScrollBar::_drag_node_exit), CONNECT_ONE_SHOT); } } } diff --git a/scene/gui/spin_box.cpp b/scene/gui/spin_box.cpp index 70acaf7adf..bfea7b0fbe 100644 --- a/scene/gui/spin_box.cpp +++ b/scene/gui/spin_box.cpp @@ -409,9 +409,9 @@ SpinBox::SpinBox() { line_edit->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_LEFT); line_edit->connect("text_submitted", callable_mp(this, &SpinBox::_text_submitted), CONNECT_DEFERRED); - line_edit->connect("focus_entered", callable_mp(this, &SpinBox::_line_edit_focus_enter), CONNECT_DEFERRED); - line_edit->connect("focus_exited", callable_mp(this, &SpinBox::_line_edit_focus_exit), CONNECT_DEFERRED); - line_edit->connect("gui_input", callable_mp(this, &SpinBox::_line_edit_input)); + line_edit->connect(SceneStringName(focus_entered), callable_mp(this, &SpinBox::_line_edit_focus_enter), CONNECT_DEFERRED); + line_edit->connect(SceneStringName(focus_exited), callable_mp(this, &SpinBox::_line_edit_focus_exit), CONNECT_DEFERRED); + line_edit->connect(SceneStringName(gui_input), callable_mp(this, &SpinBox::_line_edit_input)); range_click_timer = memnew(Timer); range_click_timer->connect("timeout", callable_mp(this, &SpinBox::_range_click_timeout)); diff --git a/scene/gui/split_container.cpp b/scene/gui/split_container.cpp index 98b1db4a96..925600756a 100644 --- a/scene/gui/split_container.cpp +++ b/scene/gui/split_container.cpp @@ -39,7 +39,7 @@ void SplitContainerDragger::gui_input(const Ref<InputEvent> &p_event) { SplitContainer *sc = Object::cast_to<SplitContainer>(get_parent()); - if (sc->collapsed || !sc->get_containable_child(0) || !sc->get_containable_child(1) || sc->dragger_visibility != SplitContainer::DRAGGER_VISIBLE) { + if (sc->collapsed || !sc->_get_sortable_child(0) || !sc->_get_sortable_child(1) || sc->dragger_visibility != SplitContainer::DRAGGER_VISIBLE) { return; } @@ -122,12 +122,12 @@ void SplitContainerDragger::_notification(int p_what) { } } -Control *SplitContainer::get_containable_child(int p_idx) const { +Control *SplitContainer::_get_sortable_child(int p_idx) const { int idx = 0; for (int i = 0; i < get_child_count(false); i++) { - Control *c = Object::cast_to<Control>(get_child(i, false)); - if (!c || !c->is_visible() || c->is_set_as_top_level()) { + Control *c = as_sortable_control(get_child(i, false)); + if (!c) { continue; } @@ -154,8 +154,8 @@ Ref<Texture2D> SplitContainer::_get_grabber_icon() const { } void SplitContainer::_compute_middle_sep(bool p_clamp) { - Control *first = get_containable_child(0); - Control *second = get_containable_child(1); + Control *first = _get_sortable_child(0); + Control *second = _get_sortable_child(1); // Determine expanded children. bool first_expanded = (vertical ? first->get_v_size_flags() : first->get_h_size_flags()) & SIZE_EXPAND; @@ -196,8 +196,8 @@ void SplitContainer::_compute_middle_sep(bool p_clamp) { } void SplitContainer::_resort() { - Control *first = get_containable_child(0); - Control *second = get_containable_child(1); + Control *first = _get_sortable_child(0); + Control *second = _get_sortable_child(1); // If we have only one element. if (!first || !second) { @@ -258,7 +258,7 @@ Size2 SplitContainer::get_minimum_size() const { int sep = (dragger_visibility != DRAGGER_HIDDEN_COLLAPSED) ? MAX(theme_cache.separation, vertical ? g->get_height() : g->get_width()) : 0; for (int i = 0; i < 2; i++) { - if (!get_containable_child(i)) { + if (!_get_sortable_child(i)) { break; } @@ -270,7 +270,7 @@ Size2 SplitContainer::get_minimum_size() const { } } - Size2 ms = get_containable_child(i)->get_combined_minimum_size(); + Size2 ms = _get_sortable_child(i)->get_combined_minimum_size(); if (vertical) { minimum.height += ms.height; @@ -322,7 +322,7 @@ int SplitContainer::get_split_offset() const { } void SplitContainer::clamp_split_offset() { - if (!get_containable_child(0) || !get_containable_child(1)) { + if (!_get_sortable_child(0) || !_get_sortable_child(1)) { return; } diff --git a/scene/gui/split_container.h b/scene/gui/split_container.h index 0f45ef166d..95f26f5e0b 100644 --- a/scene/gui/split_container.h +++ b/scene/gui/split_container.h @@ -82,12 +82,11 @@ private: Ref<Texture2D> _get_grabber_icon() const; void _compute_middle_sep(bool p_clamp); void _resort(); + Control *_get_sortable_child(int p_idx) const; protected: bool is_fixed = false; - Control *get_containable_child(int p_idx) const; - void _notification(int p_what); void _validate_property(PropertyInfo &p_property) const; static void _bind_methods(); diff --git a/scene/gui/subviewport_container.cpp b/scene/gui/subviewport_container.cpp index f6cfe6ab18..c715aceb0b 100644 --- a/scene/gui/subviewport_container.cpp +++ b/scene/gui/subviewport_container.cpp @@ -287,7 +287,7 @@ void SubViewportContainer::_bind_methods() { ClassDB::bind_method(D_METHOD("get_stretch_shrink"), &SubViewportContainer::get_stretch_shrink); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "stretch"), "set_stretch", "is_stretch_enabled"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "stretch_shrink"), "set_stretch_shrink", "get_stretch_shrink"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "stretch_shrink", PROPERTY_HINT_RANGE, "1,32,1,or_greater"), "set_stretch_shrink", "get_stretch_shrink"); GDVIRTUAL_BIND(_propagate_input_event, "event"); } diff --git a/scene/gui/tab_bar.cpp b/scene/gui/tab_bar.cpp index 0e130d60af..ddc757c452 100644 --- a/scene/gui/tab_bar.cpp +++ b/scene/gui/tab_bar.cpp @@ -1868,6 +1868,7 @@ void TabBar::_bind_methods() { Tab defaults(true); base_property_helper.set_prefix("tab_"); + base_property_helper.set_array_length_getter(&TabBar::get_tab_count); base_property_helper.register_property(PropertyInfo(Variant::STRING, "title"), defaults.text, &TabBar::set_tab_title, &TabBar::get_tab_title); base_property_helper.register_property(PropertyInfo(Variant::STRING, "tooltip"), defaults.tooltip, &TabBar::set_tab_tooltip, &TabBar::get_tab_tooltip); base_property_helper.register_property(PropertyInfo(Variant::OBJECT, "icon", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), defaults.icon, &TabBar::set_tab_icon, &TabBar::get_tab_icon); @@ -1877,7 +1878,7 @@ void TabBar::_bind_methods() { TabBar::TabBar() { set_size(Size2(get_size().width, get_minimum_size().height)); set_focus_mode(FOCUS_ALL); - connect("mouse_exited", callable_mp(this, &TabBar::_on_mouse_exited)); + connect(SceneStringName(mouse_exited), callable_mp(this, &TabBar::_on_mouse_exited)); property_helper.setup_for_instance(base_property_helper, this); } diff --git a/scene/gui/tab_container.cpp b/scene/gui/tab_container.cpp index dc53cf82e6..d0c3f3d65e 100644 --- a/scene/gui/tab_container.cpp +++ b/scene/gui/tab_container.cpp @@ -554,7 +554,7 @@ void TabContainer::add_child_notify(Node *p_child) { } p_child->connect("renamed", callable_mp(this, &TabContainer::_refresh_tab_names)); - p_child->connect(SNAME("visibility_changed"), callable_mp(this, &TabContainer::_on_tab_visibility_changed).bind(c)); + p_child->connect(SceneStringName(visibility_changed), callable_mp(this, &TabContainer::_on_tab_visibility_changed).bind(c)); // TabBar won't emit the "tab_changed" signal when not inside the tree. if (!is_inside_tree()) { @@ -607,7 +607,7 @@ void TabContainer::remove_child_notify(Node *p_child) { p_child->remove_meta("_tab_index"); p_child->remove_meta("_tab_name"); p_child->disconnect("renamed", callable_mp(this, &TabContainer::_refresh_tab_names)); - p_child->disconnect(SNAME("visibility_changed"), callable_mp(this, &TabContainer::_on_tab_visibility_changed)); + p_child->disconnect(SceneStringName(visibility_changed), callable_mp(this, &TabContainer::_on_tab_visibility_changed)); // TabBar won't emit the "tab_changed" signal when not inside the tree. if (!is_inside_tree()) { @@ -1121,5 +1121,5 @@ TabContainer::TabContainer() { tab_bar->connect("tab_button_pressed", callable_mp(this, &TabContainer::_on_tab_button_pressed)); tab_bar->connect("active_tab_rearranged", callable_mp(this, &TabContainer::_on_active_tab_rearranged)); - connect("mouse_exited", callable_mp(this, &TabContainer::_on_mouse_exited)); + connect(SceneStringName(mouse_exited), callable_mp(this, &TabContainer::_on_mouse_exited)); } diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index 49cfa8a030..1dd00fab4d 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -558,8 +558,6 @@ void TextEdit::_notification(int p_what) { int visible_rows = get_visible_line_count() + 1; - Color color = !editable ? theme_cache.font_readonly_color : theme_cache.font_color; - if (theme_cache.background_color.a > 0.01) { RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2i(), get_size()), theme_cache.background_color); } @@ -734,7 +732,7 @@ void TextEdit::_notification(int p_what) { if (draw_minimap) { int minimap_visible_lines = get_minimap_visible_lines(); int minimap_line_height = (minimap_char_size.y + minimap_line_spacing); - int minimap_tab_size = minimap_char_size.x * text.get_tab_size(); + int tab_size = text.get_tab_size(); // Calculate viewport size and y offset. int viewport_height = (draw_amount - 1) * minimap_line_height; @@ -839,68 +837,74 @@ void TextEdit::_notification(int p_what) { } } - Color previous_color; + Color next_color = current_color; int characters = 0; - int tabs = 0; + int tab_alignment = 0; + int xpos = xmargin_end + 2 + indent_px; for (int j = 0; j < str.length(); j++) { - const Variant *color_data = color_map.getptr(last_wrap_column + j); - if (color_data != nullptr) { - current_color = (color_data->operator Dictionary()).get("color", theme_cache.font_color); - if (!editable) { - current_color.a = theme_cache.font_readonly_color.a; + bool next_is_whitespace = false; + bool next_is_tab = false; + // Get the number of characters to draw together. + for (characters = 0; j + characters < str.length(); characters++) { + int next_char_index = j + characters; + const Variant *color_data = color_map.getptr(last_wrap_column + next_char_index); + if (color_data != nullptr) { + next_color = (color_data->operator Dictionary()).get("color", theme_cache.font_color); + if (!editable) { + next_color.a = theme_cache.font_readonly_color.a; + } + next_color.a *= 0.6; } - } - color = current_color; - - if (j == 0) { - previous_color = color; - } - - int xpos = indent_px + ((xmargin_end + minimap_char_size.x) + (minimap_char_size.x * j)) + tabs; - bool out_of_bounds = (xpos >= xmargin_end + minimap_width); - - bool whitespace = is_whitespace(str[j]); - if (!whitespace) { - characters++; - - if (j < str.length() - 1 && color == previous_color && !out_of_bounds) { - continue; + if (characters == 0) { + current_color = next_color; } - - // 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--; - j--; - - if (str[j] == '\t') { - tabs -= minimap_tab_size; + if (next_color != current_color) { + break; + } + next_is_whitespace = is_whitespace(str[next_char_index]); + if (next_is_whitespace) { + if (str[next_char_index] == '\t') { + next_is_tab = true; } + break; + } + bool out_of_bounds = xpos + minimap_char_size.x * characters >= xmargin_end + minimap_width; + if (out_of_bounds) { + break; } } + if (!next_is_whitespace && characters == 0) { + break; + } if (characters > 0) { - previous_color.a *= 0.6; - // Take one for zero indexing, and if we hit whitespace / the end of a word. - int chars = MAX(0, (j - (characters - 1)) - (whitespace ? 1 : 0)) + 1; - int char_x_ofs = indent_px + ((xmargin_end + minimap_char_size.x) + (minimap_char_size.x * chars)) + tabs; if (rtl) { - RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2(size.width - char_x_ofs - minimap_char_size.x * characters, minimap_line_height * i), Point2(minimap_char_size.x * characters, minimap_char_size.y)), previous_color); + RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2(size.width - xpos - minimap_char_size.x * characters, minimap_line_height * i), Point2(minimap_char_size.x * characters, minimap_char_size.y)), current_color); } else { - RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2(char_x_ofs, minimap_line_height * i), Point2(minimap_char_size.x * characters, minimap_char_size.y)), previous_color); + RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2(xpos, minimap_line_height * i), Point2(minimap_char_size.x * characters, minimap_char_size.y)), current_color); } } - if (out_of_bounds) { - break; - } + j += characters - 1; + xpos += minimap_char_size.x * characters; + tab_alignment += characters; - if (str[j] == '\t') { - tabs += minimap_tab_size; + if (next_is_whitespace) { + if (next_is_tab) { + tab_alignment %= tab_size; + xpos += minimap_char_size.x * (tab_size - tab_alignment); + tab_alignment = 0; + } else { + xpos += minimap_char_size.x; + tab_alignment += 1; + } + j += 1; } - previous_color = color; - characters = 0; + if (xpos >= xmargin_end + minimap_width) { + // Out of bounds. + break; + } } } } @@ -999,23 +1003,12 @@ void TextEdit::_notification(int p_what) { } } - if (str.length() == 0) { - // Draw line background if empty as we won't loop at all. - if (caret_line_wrap_index_map.has(line) && caret_line_wrap_index_map[line].has(line_wrap_index) && highlight_current_line) { - if (rtl) { - RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(size.width - ofs_x - xmargin_end, ofs_y, xmargin_end, row_height), theme_cache.current_line_color); - } else { - RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(ofs_x, ofs_y, xmargin_end, row_height), theme_cache.current_line_color); - } - } - } else { - // If it has text, then draw current line marker in the margin, as line number etc will draw over it, draw the rest of line marker later. - if (caret_line_wrap_index_map.has(line) && caret_line_wrap_index_map[line].has(line_wrap_index) && highlight_current_line) { - if (rtl) { - RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(size.width - ofs_x - xmargin_end, ofs_y, xmargin_end, row_height), theme_cache.current_line_color); - } else { - RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(ofs_x, ofs_y, xmargin_end, row_height), theme_cache.current_line_color); - } + // Draw current line highlight. + if (highlight_current_line && caret_line_wrap_index_map.has(line) && caret_line_wrap_index_map[line].has(line_wrap_index)) { + if (rtl) { + RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(size.width - ofs_x - xmargin_end, ofs_y, xmargin_end, row_height), theme_cache.current_line_color); + } else { + RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(ofs_x, ofs_y, xmargin_end, row_height), theme_cache.current_line_color); } } @@ -1188,6 +1181,7 @@ void TextEdit::_notification(int p_what) { if (!clipped && lookup_symbol_word.length() != 0) { // Highlight word if (is_ascii_alphabet_char(lookup_symbol_word[0]) || lookup_symbol_word[0] == '_' || lookup_symbol_word[0] == '.') { + Color highlight_underline_color = !editable ? theme_cache.font_readonly_color : theme_cache.font_color; int lookup_symbol_word_col = _get_column_pos_of_word(lookup_symbol_word, str, SEARCH_MATCH_CASE | SEARCH_WHOLE_WORDS, 0); int lookup_symbol_word_len = lookup_symbol_word.length(); while (lookup_symbol_word_col != -1) { @@ -1205,7 +1199,7 @@ void TextEdit::_notification(int p_what) { } rect.position.y += ceil(TS->shaped_text_get_ascent(rid)) + ceil(theme_cache.font->get_underline_position(theme_cache.font_size)); rect.size.y = MAX(1, theme_cache.font->get_underline_thickness(theme_cache.font_size)); - draw_rect(rect, color); + draw_rect(rect, highlight_underline_color); } lookup_symbol_word_col = _get_column_pos_of_word(lookup_symbol_word, str, SEARCH_MATCH_CASE | SEARCH_WHOLE_WORDS, lookup_symbol_word_col + lookup_symbol_word_len); @@ -4243,8 +4237,11 @@ String TextEdit::get_word_at_pos(const Vector2 &p_pos) const { } Point2i TextEdit::get_line_column_at_pos(const Point2i &p_pos, bool p_allow_out_of_bounds) const { - float rows = p_pos.y; - rows -= theme_cache.style_normal->get_margin(SIDE_TOP); + float rows = p_pos.y - theme_cache.style_normal->get_margin(SIDE_TOP); + if (!editable) { + rows -= theme_cache.style_readonly->get_offset().y / 2; + rows += theme_cache.style_normal->get_offset().y / 2; + } rows /= get_line_height(); rows += _get_v_scroll_offset(); int first_vis_line = get_first_visible_line(); @@ -4275,6 +4272,10 @@ Point2i TextEdit::get_line_column_at_pos(const Point2i &p_pos, bool p_allow_out_ int col = 0; int colx = p_pos.x - (theme_cache.style_normal->get_margin(SIDE_LEFT) + gutters_width + gutter_padding); colx += first_visible_col; + if (!editable) { + colx -= theme_cache.style_readonly->get_offset().x / 2; + colx += theme_cache.style_normal->get_offset().x / 2; + } col = _get_char_pos_for_line(colx, row, wrap_index); if (get_line_wrapping_mode() != LineWrappingMode::LINE_WRAPPING_NONE && wrap_index < get_line_wrap_count(row)) { // Move back one if we are at the end of the row. @@ -7973,7 +7974,7 @@ void TextEdit::_update_minimap_click() { Point2 mp = get_local_mouse_pos(); int xmargin_end = get_size().width - theme_cache.style_normal->get_margin(SIDE_RIGHT); - if (!dragging_minimap && (mp.x < xmargin_end - minimap_width || mp.y > xmargin_end)) { + if (!dragging_minimap && (mp.x < xmargin_end - minimap_width || mp.x > xmargin_end)) { minimap_clicked = false; return; } diff --git a/scene/gui/texture_button.cpp b/scene/gui/texture_button.cpp index df90257e03..c267ff93c6 100644 --- a/scene/gui/texture_button.cpp +++ b/scene/gui/texture_button.cpp @@ -178,13 +178,14 @@ void TextureButton::_notification(int p_what) { texdraw = focused; } - if (texdraw.is_valid()) { - size = texdraw->get_size(); - _texture_region = Rect2(Point2(), texdraw->get_size()); + if (texdraw.is_valid() || click_mask.is_valid()) { + const Size2 texdraw_size = texdraw.is_valid() ? texdraw->get_size() : Size2(click_mask->get_size()); + + size = texdraw_size; + _texture_region = Rect2(Point2(), texdraw_size); _tile = false; switch (stretch_mode) { case STRETCH_KEEP: - size = texdraw->get_size(); break; case STRETCH_SCALE: size = get_size(); @@ -194,18 +195,17 @@ void TextureButton::_notification(int p_what) { _tile = true; break; case STRETCH_KEEP_CENTERED: - ofs = (get_size() - texdraw->get_size()) / 2; - size = texdraw->get_size(); + ofs = (get_size() - texdraw_size) / 2; break; case STRETCH_KEEP_ASPECT_CENTERED: case STRETCH_KEEP_ASPECT: { Size2 _size = get_size(); - float tex_width = texdraw->get_width() * _size.height / texdraw->get_height(); + float tex_width = texdraw_size.width * _size.height / texdraw_size.height; float tex_height = _size.height; if (tex_width > _size.width) { tex_width = _size.width; - tex_height = texdraw->get_height() * tex_width / texdraw->get_width(); + tex_height = texdraw_size.height * tex_width / texdraw_size.width; } if (stretch_mode == STRETCH_KEEP_ASPECT_CENTERED) { @@ -217,10 +217,9 @@ void TextureButton::_notification(int p_what) { } break; case STRETCH_KEEP_ASPECT_COVERED: { size = get_size(); - Size2 tex_size = texdraw->get_size(); - Size2 scale_size(size.width / tex_size.width, size.height / tex_size.height); + Size2 scale_size = size / texdraw_size; float scale = scale_size.width > scale_size.height ? scale_size.width : scale_size.height; - Size2 scaled_tex_size = tex_size * scale; + Size2 scaled_tex_size = texdraw_size * scale; Point2 ofs2 = ((scaled_tex_size - size) / scale).abs() / 2.0f; _texture_region = Rect2(ofs2, size / scale); } break; @@ -233,10 +232,12 @@ void TextureButton::_notification(int p_what) { if (draw_focus_only) { // Do nothing, we only needed to calculate the rectangle. - } else if (_tile) { - draw_texture_rect(texdraw, Rect2(ofs, size), _tile); - } else { - draw_texture_rect_region(texdraw, Rect2(ofs, size), _texture_region); + } else if (texdraw.is_valid()) { + if (_tile) { + draw_texture_rect(texdraw, Rect2(ofs, size), _tile); + } else { + draw_texture_rect_region(texdraw, Rect2(ofs, size), _texture_region); + } } } else { _position_rect = Rect2(); diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp index e2de585a69..fc5b942918 100644 --- a/scene/gui/tree.cpp +++ b/scene/gui/tree.cpp @@ -3152,8 +3152,12 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, int } void Tree::_text_editor_popup_modal_close() { + if (popup_edit_commited) { + return; // Already processed by LineEdit/TextEdit commit. + } + if (popup_editor->get_hide_reason() == Popup::HIDE_REASON_CANCELED) { - return; + return; // ESC pressed, app focus lost, or forced close from code. } if (value_editor->has_point(value_editor->get_local_mouse_position())) { @@ -3172,9 +3176,18 @@ void Tree::_text_editor_popup_modal_close() { } void Tree::_text_editor_gui_input(const Ref<InputEvent> &p_event) { + if (popup_edit_commited) { + return; // Already processed by _text_editor_popup_modal_close + } + + if (popup_editor->get_hide_reason() == Popup::HIDE_REASON_CANCELED) { + return; // ESC pressed, app focus lost, or forced close from code. + } + if (p_event->is_action_pressed("ui_text_newline_blank", true)) { accept_event(); } else if (p_event->is_action_pressed("ui_text_newline")) { + popup_edit_commited = true; // End edit popup processing. popup_editor->hide(); _apply_multiline_edit(); accept_event(); @@ -3205,6 +3218,15 @@ void Tree::_apply_multiline_edit() { } void Tree::_line_editor_submit(String p_text) { + if (popup_edit_commited) { + return; // Already processed by _text_editor_popup_modal_close + } + + if (popup_editor->get_hide_reason() == Popup::HIDE_REASON_CANCELED) { + return; // ESC pressed, app focus lost, or forced close from code. + } + + popup_edit_commited = true; // End edit popup processing. popup_editor->hide(); if (!popup_edited_item) { @@ -4072,6 +4094,7 @@ bool Tree::edit_selected(bool p_force_edit) { if (!popup_editor->is_embedded()) { popup_editor->set_content_scale_factor(popup_scale); } + popup_edit_commited = false; // Start edit popup processing. popup_editor->popup(); popup_editor->child_controls_changed(); @@ -4091,6 +4114,7 @@ bool Tree::edit_selected(bool p_force_edit) { if (!popup_editor->is_embedded()) { popup_editor->set_content_scale_factor(popup_scale); } + popup_edit_commited = false; // Start edit popup processing. popup_editor->popup(); popup_editor->child_controls_changed(); @@ -5795,7 +5819,7 @@ Tree::Tree() { h_scroll->connect("value_changed", callable_mp(this, &Tree::_scroll_moved)); v_scroll->connect("value_changed", callable_mp(this, &Tree::_scroll_moved)); line_editor->connect("text_submitted", callable_mp(this, &Tree::_line_editor_submit)); - text_editor->connect("gui_input", callable_mp(this, &Tree::_text_editor_gui_input)); + text_editor->connect(SceneStringName(gui_input), callable_mp(this, &Tree::_text_editor_gui_input)); popup_editor->connect("popup_hide", callable_mp(this, &Tree::_text_editor_popup_modal_close)); popup_menu->connect("id_pressed", callable_mp(this, &Tree::popup_select)); value_editor->connect("value_changed", callable_mp(this, &Tree::value_editor_changed)); diff --git a/scene/gui/tree.h b/scene/gui/tree.h index 311055a2f8..e9c93c6e03 100644 --- a/scene/gui/tree.h +++ b/scene/gui/tree.h @@ -479,6 +479,7 @@ private: VBoxContainer *popup_editor_vb = nullptr; + bool popup_edit_commited = true; Popup *popup_editor = nullptr; LineEdit *line_editor = nullptr; TextEdit *text_editor = nullptr; diff --git a/scene/gui/video_stream_player.cpp b/scene/gui/video_stream_player.cpp index 687a9e46a0..0b521f926d 100644 --- a/scene/gui/video_stream_player.cpp +++ b/scene/gui/video_stream_player.cpp @@ -31,7 +31,6 @@ #include "video_stream_player.h" #include "core/os/os.h" -#include "scene/scene_string_names.h" #include "servers/audio_server.h" int VideoStreamPlayer::sp_get_channel_count() const { @@ -163,7 +162,7 @@ void VideoStreamPlayer::_notification(int p_notification) { play(); return; } - emit_signal(SceneStringNames::get_singleton()->finished); + emit_signal(SceneStringName(finished)); } } break; @@ -460,7 +459,7 @@ StringName VideoStreamPlayer::get_bus() const { return bus; } } - return SceneStringNames::get_singleton()->Master; + return SceneStringName(Master); } void VideoStreamPlayer::_validate_property(PropertyInfo &p_property) const { |