diff options
Diffstat (limited to 'scene/gui')
61 files changed, 781 insertions, 686 deletions
diff --git a/scene/gui/base_button.cpp b/scene/gui/base_button.cpp index d252a4507c..bef1011364 100644 --- a/scene/gui/base_button.cpp +++ b/scene/gui/base_button.cpp @@ -52,7 +52,7 @@ void BaseButton::_unpress_group() { } } -void BaseButton::_gui_input(Ref<InputEvent> p_event) { +void BaseButton::gui_input(const Ref<InputEvent> &p_event) { ERR_FAIL_COND(p_event.is_null()); if (status.disabled) { // no interaction with disabled button @@ -121,17 +121,13 @@ void BaseButton::_notification(int p_what) { } void BaseButton::_pressed() { - if (get_script_instance()) { - get_script_instance()->call(SceneStringNames::get_singleton()->_pressed); - } + GDVIRTUAL_CALL(_pressed); pressed(); emit_signal(SNAME("pressed")); } void BaseButton::_toggled(bool p_pressed) { - if (get_script_instance()) { - get_script_instance()->call(SceneStringNames::get_singleton()->_toggled, p_pressed); - } + GDVIRTUAL_CALL(_toggled, p_pressed); toggled(p_pressed); emit_signal(SNAME("toggled"), p_pressed); } @@ -342,7 +338,7 @@ Ref<Shortcut> BaseButton::get_shortcut() const { return shortcut; } -void BaseButton::_unhandled_key_input(Ref<InputEvent> p_event) { +void BaseButton::unhandled_key_input(const Ref<InputEvent> &p_event) { ERR_FAIL_COND(p_event.is_null()); if (!_is_focus_owner_in_shorcut_context()) { @@ -411,8 +407,6 @@ bool BaseButton::_is_focus_owner_in_shorcut_context() const { } void BaseButton::_bind_methods() { - ClassDB::bind_method(D_METHOD("_gui_input"), &BaseButton::_gui_input); - ClassDB::bind_method(D_METHOD("_unhandled_key_input"), &BaseButton::_unhandled_key_input); ClassDB::bind_method(D_METHOD("set_pressed", "pressed"), &BaseButton::set_pressed); ClassDB::bind_method(D_METHOD("is_pressed"), &BaseButton::is_pressed); ClassDB::bind_method(D_METHOD("set_pressed_no_signal", "pressed"), &BaseButton::set_pressed_no_signal); @@ -440,8 +434,8 @@ void BaseButton::_bind_methods() { ClassDB::bind_method(D_METHOD("set_shortcut_context", "node"), &BaseButton::set_shortcut_context); ClassDB::bind_method(D_METHOD("get_shortcut_context"), &BaseButton::get_shortcut_context); - BIND_VMETHOD(MethodInfo("_pressed")); - BIND_VMETHOD(MethodInfo("_toggled", PropertyInfo(Variant::BOOL, "button_pressed"))); + GDVIRTUAL_BIND(_pressed); + GDVIRTUAL_BIND(_toggled, "button_pressed"); ADD_SIGNAL(MethodInfo("pressed")); ADD_SIGNAL(MethodInfo("button_up")); diff --git a/scene/gui/base_button.h b/scene/gui/base_button.h index d86b35daf0..cd6e78464f 100644 --- a/scene/gui/base_button.h +++ b/scene/gui/base_button.h @@ -75,12 +75,15 @@ protected: virtual void pressed(); virtual void toggled(bool p_pressed); static void _bind_methods(); - virtual void _gui_input(Ref<InputEvent> p_event); - virtual void _unhandled_key_input(Ref<InputEvent> p_event); + virtual void gui_input(const Ref<InputEvent> &p_event) override; + virtual void unhandled_key_input(const Ref<InputEvent> &p_event) override; void _notification(int p_what); bool _is_focus_owner_in_shorcut_context() const; + GDVIRTUAL0(_pressed) + GDVIRTUAL1(_toggled, bool) + public: enum DrawMode { DRAW_NORMAL, diff --git a/scene/gui/box_container.cpp b/scene/gui/box_container.cpp index a2f1d2b15a..cf2df4e1a2 100644 --- a/scene/gui/box_container.cpp +++ b/scene/gui/box_container.cpp @@ -351,11 +351,11 @@ MarginContainer *VBoxContainer::add_margin_child(const String &p_label, Control Label *l = memnew(Label); l->set_theme_type_variation("HeaderSmall"); l->set_text(p_label); - add_child(l); + add_child(l, false, INTERNAL_MODE_FRONT); MarginContainer *mc = memnew(MarginContainer); mc->add_theme_constant_override("margin_left", 0); mc->add_child(p_control); - add_child(mc); + add_child(mc, false, INTERNAL_MODE_FRONT); if (p_expand) { mc->set_v_size_flags(SIZE_EXPAND_FILL); } diff --git a/scene/gui/check_box.cpp b/scene/gui/check_box.cpp index d93107df2d..411fb2e1f0 100644 --- a/scene/gui/check_box.cpp +++ b/scene/gui/check_box.cpp @@ -34,11 +34,13 @@ Size2 CheckBox::get_icon_size() const { Ref<Texture2D> checked = Control::get_theme_icon(SNAME("checked")); - Ref<Texture2D> checked_disabled = Control::get_theme_icon(SNAME("checked_disabled")); Ref<Texture2D> unchecked = Control::get_theme_icon(SNAME("unchecked")); - Ref<Texture2D> unchecked_disabled = Control::get_theme_icon(SNAME("unchecked_disabled")); Ref<Texture2D> radio_checked = Control::get_theme_icon(SNAME("radio_checked")); Ref<Texture2D> radio_unchecked = Control::get_theme_icon(SNAME("radio_unchecked")); + Ref<Texture2D> checked_disabled = Control::get_theme_icon(SNAME("checked_disabled")); + Ref<Texture2D> unchecked_disabled = Control::get_theme_icon(SNAME("unchecked_disabled")); + Ref<Texture2D> radio_checked_disabled = Control::get_theme_icon(SNAME("radio_checked_disabled")); + Ref<Texture2D> radio_unchecked_disabled = Control::get_theme_icon(SNAME("radio_unchecked_disabled")); Size2 tex_size = Size2(0, 0); if (!checked.is_null()) { @@ -53,6 +55,18 @@ Size2 CheckBox::get_icon_size() const { if (!radio_unchecked.is_null()) { tex_size = Size2(MAX(tex_size.width, radio_unchecked->get_width()), MAX(tex_size.height, radio_unchecked->get_height())); } + if (!checked_disabled.is_null()) { + tex_size = Size2(MAX(tex_size.width, checked_disabled->get_width()), MAX(tex_size.height, checked_disabled->get_height())); + } + if (!unchecked_disabled.is_null()) { + tex_size = Size2(MAX(tex_size.width, unchecked_disabled->get_width()), MAX(tex_size.height, unchecked_disabled->get_height())); + } + if (!radio_checked_disabled.is_null()) { + tex_size = Size2(MAX(tex_size.width, radio_checked_disabled->get_width()), MAX(tex_size.height, radio_checked_disabled->get_height())); + } + if (!radio_unchecked_disabled.is_null()) { + tex_size = Size2(MAX(tex_size.width, radio_unchecked_disabled->get_width()), MAX(tex_size.height, radio_unchecked_disabled->get_height())); + } return tex_size; } diff --git a/scene/gui/code_edit.cpp b/scene/gui/code_edit.cpp index 08dd7f28eb..d05762b6c0 100644 --- a/scene/gui/code_edit.cpp +++ b/scene/gui/code_edit.cpp @@ -248,7 +248,7 @@ void CodeEdit::_notification(int p_what) { } } -void CodeEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { +void CodeEdit::gui_input(const Ref<InputEvent> &p_gui_input) { Ref<InputEventMouseButton> mb = p_gui_input; if (mb.is_valid()) { @@ -354,7 +354,7 @@ void CodeEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { Ref<InputEventKey> k = p_gui_input; bool update_code_completion = false; if (!k.is_valid()) { - TextEdit::_gui_input(p_gui_input); + TextEdit::gui_input(p_gui_input); return; } @@ -450,7 +450,7 @@ void CodeEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { } if (k->is_action("ui_text_backspace", true)) { backspace(); - _filter_code_completion_candidates(); + _filter_code_completion_candidates_impl(); accept_event(); return; } @@ -519,10 +519,10 @@ void CodeEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { set_code_hint(""); } - TextEdit::_gui_input(p_gui_input); + TextEdit::gui_input(p_gui_input); if (update_code_completion) { - _filter_code_completion_candidates(); + _filter_code_completion_candidates_impl(); } } @@ -557,7 +557,7 @@ Control::CursorShape CodeEdit::get_cursor_shape(const Point2 &p_pos) const { /* Text manipulation */ // Overridable actions -void CodeEdit::_handle_unicode_input(const uint32_t p_unicode) { +void CodeEdit::_handle_unicode_input_internal(const uint32_t p_unicode) { bool had_selection = has_selection(); if (had_selection) { begin_complex_operation(); @@ -609,7 +609,7 @@ void CodeEdit::_handle_unicode_input(const uint32_t p_unicode) { } } -void CodeEdit::_backspace() { +void CodeEdit::_backspace_internal() { if (!is_editable()) { return; } @@ -1400,7 +1400,8 @@ void CodeEdit::fold_line(int p_line) { } /* Find the last line to be hidden. */ - int end_line = get_line_count(); + const int line_count = get_line_count() - 1; + int end_line = line_count; int in_comment = is_in_comment(p_line); int in_string = (in_comment == -1) ? is_in_string(p_line) : -1; @@ -1408,7 +1409,7 @@ void CodeEdit::fold_line(int p_line) { end_line = get_delimiter_end_position(p_line, get_line(p_line).size() - 1).y; /* End line is the same therefore we have a block. */ if (end_line == p_line) { - for (int i = p_line + 1; i < get_line_count(); i++) { + for (int i = p_line + 1; i <= line_count; i++) { if ((in_string != -1 && is_in_string(i) == -1) || (in_comment != -1 && is_in_comment(i) == -1)) { end_line = i - 1; break; @@ -1417,14 +1418,27 @@ void CodeEdit::fold_line(int p_line) { } } else { int start_indent = get_indent_level(p_line); - for (int i = p_line + 1; i < get_line_count(); i++) { + for (int i = p_line + 1; i <= line_count; i++) { if (get_line(p_line).strip_edges().size() == 0 || is_in_string(i) != -1 || is_in_comment(i) != -1) { end_line = i; continue; } - if (get_indent_level(i) <= start_indent && get_line(i).strip_edges().size() != 0) { + if (i == line_count) { + /* Do not fold empty last line of script if any */ + end_line = i; + if (get_line(i).strip_edges().size() == 0) { + end_line--; + } + break; + } + + if ((get_indent_level(i) <= start_indent && get_line(i).strip_edges().size() != 0)) { + /* Keep an empty line unfolded if any */ end_line = i - 1; + if (get_line(i - 1).strip_edges().size() == 0 && i - 2 > p_line) { + end_line = i - 2; + } break; } } @@ -1739,9 +1753,7 @@ String CodeEdit::get_text_for_code_completion() const { } void CodeEdit::request_code_completion(bool p_force) { - ScriptInstance *si = get_script_instance(); - if (si && si->has_method("_request_code_completion")) { - si->call("_request_code_completion", p_force); + if (GDVIRTUAL_CALL(_request_code_completion, p_force)) { return; } @@ -1798,7 +1810,7 @@ void CodeEdit::update_code_completion_options(bool p_forced) { code_completion_forced = p_forced; code_completion_option_sources = code_completion_option_submitted; code_completion_option_submitted.clear(); - _filter_code_completion_candidates(); + _filter_code_completion_candidates_impl(); } TypedArray<Dictionary> CodeEdit::get_code_completion_options() const { @@ -1855,11 +1867,10 @@ void CodeEdit::confirm_code_completion(bool p_replace) { return; } - ScriptInstance *si = get_script_instance(); - if (si && si->has_method("_confirm_code_completion")) { - si->call("_confirm_code_completion", p_replace); + if (GDVIRTUAL_CALL(_confirm_code_completion, p_replace)) { return; } + begin_complex_operation(); int caret_line = get_caret_line(); @@ -1940,7 +1951,7 @@ void CodeEdit::confirm_code_completion(bool p_replace) { if (pre_brace_pair == -1 && post_brace_pair == -1 && get_caret_column() > 0 && get_caret_column() < get_line(caret_line).length()) { pre_brace_pair = _get_auto_brace_pair_open_at_pos(caret_line, get_caret_column() + 1); - if (pre_brace_pair == _get_auto_brace_pair_close_at_pos(caret_line, get_caret_column() - 1)) { + if (pre_brace_pair != -1 && pre_brace_pair == _get_auto_brace_pair_close_at_pos(caret_line, get_caret_column() - 1)) { remove_text(caret_line, get_caret_column() - 2, caret_line, get_caret_column()); if (_get_auto_brace_pair_close_at_pos(caret_line, get_caret_column() - 1) != pre_brace_pair) { set_caret_column(get_caret_column() - 1); @@ -2179,9 +2190,10 @@ void CodeEdit::_bind_methods() { ClassDB::bind_method(D_METHOD("get_code_comletion_prefixes"), &CodeEdit::get_code_completion_prefixes); // Overridable - BIND_VMETHOD(MethodInfo("_confirm_code_completion", PropertyInfo(Variant::BOOL, "replace"))); - BIND_VMETHOD(MethodInfo("_request_code_completion", PropertyInfo(Variant::BOOL, "force"))); - BIND_VMETHOD(MethodInfo(Variant::ARRAY, "_filter_code_completion_candidates", PropertyInfo(Variant::ARRAY, "candidates"))); + + GDVIRTUAL_BIND(_confirm_code_completion, "replace") + GDVIRTUAL_BIND(_request_code_completion, "force") + GDVIRTUAL_BIND(_filter_code_completion_candidates, "candidates") /* Line length guidelines */ ClassDB::bind_method(D_METHOD("set_line_length_guidelines", "guideline_columns"), &CodeEdit::set_line_length_guidelines); @@ -2650,11 +2662,10 @@ TypedArray<String> CodeEdit::_get_delimiters(DelimiterType p_type) const { } /* Code Completion */ -void CodeEdit::_filter_code_completion_candidates() { - ScriptInstance *si = get_script_instance(); +void CodeEdit::_filter_code_completion_candidates_impl() { int line_height = get_line_height(); - if (si && si->has_method("_filter_code_completion_candidates")) { + if (GDVIRTUAL_IS_OVERRIDDEN(_filter_code_completion_candidates)) { code_completion_options.clear(); code_completion_base = ""; @@ -2674,7 +2685,9 @@ void CodeEdit::_filter_code_completion_candidates() { i++; } - TypedArray<Dictionary> completion_options = si->call("_filter_code_completion_candidates", completion_options_sources); + Array completion_options; + + GDVIRTUAL_CALL(_filter_code_completion_candidates, completion_options_sources, completion_options); /* No options to complete, cancel. */ if (completion_options.size() == 0) { @@ -2745,7 +2758,7 @@ void CodeEdit::_filter_code_completion_candidates() { /* If we have a space, previous word might be a keyword. eg "func |". */ } else if (cofs > 0 && line[cofs - 1] == ' ') { int ofs = cofs - 1; - while (ofs >= 0 && line[ofs] == ' ') { + while (ofs > 0 && line[ofs] == ' ') { ofs--; } prev_is_word = _is_char(line[ofs]); diff --git a/scene/gui/code_edit.h b/scene/gui/code_edit.h index 76ac15f553..4fbb5194e6 100644 --- a/scene/gui/code_edit.h +++ b/scene/gui/code_edit.h @@ -219,7 +219,7 @@ private: List<ScriptCodeCompletionOption> code_completion_option_sources; String code_completion_base; - void _filter_code_completion_candidates(); + void _filter_code_completion_candidates_impl(); /* Line length guidelines */ TypedArray<int> line_length_guideline_columns; @@ -248,7 +248,7 @@ private: void _text_changed(); protected: - void _gui_input(const Ref<InputEvent> &p_gui_input) override; + void gui_input(const Ref<InputEvent> &p_gui_input) override; void _notification(int p_what); static void _bind_methods(); @@ -256,8 +256,12 @@ protected: /* Text manipulation */ // Overridable actions - virtual void _handle_unicode_input(const uint32_t p_unicode) override; - virtual void _backspace() override; + virtual void _handle_unicode_input_internal(const uint32_t p_unicode) override; + virtual void _backspace_internal() override; + + GDVIRTUAL1(_confirm_code_completion, bool) + GDVIRTUAL1(_request_code_completion, bool) + GDVIRTUAL1RC(Array, _filter_code_completion_candidates, TypedArray<Dictionary>) public: /* General overrides */ diff --git a/scene/gui/color_picker.cpp b/scene/gui/color_picker.cpp index 261480bcdd..1afb0b8e9d 100644 --- a/scene/gui/color_picker.cpp +++ b/scene/gui/color_picker.cpp @@ -46,13 +46,13 @@ void ColorPicker::_notification(int p_what) { switch (p_what) { case NOTIFICATION_THEME_CHANGED: { btn_pick->set_icon(get_theme_icon(SNAME("screen_picker"), SNAME("ColorPicker"))); - bt_add_preset->set_icon(get_theme_icon(SNAME("add_preset"))); - + btn_add_preset->set_icon(get_theme_icon(SNAME("add_preset"))); + _update_presets(); _update_controls(); } break; case NOTIFICATION_ENTER_TREE: { btn_pick->set_icon(get_theme_icon(SNAME("screen_picker"), SNAME("ColorPicker"))); - bt_add_preset->set_icon(get_theme_icon(SNAME("add_preset"))); + btn_add_preset->set_icon(get_theme_icon(SNAME("add_preset"))); _update_controls(); _update_color(); @@ -69,7 +69,6 @@ void ColorPicker::_notification(int p_what) { for (int i = 0; i < preset_cache.size(); i++) { presets.push_back(preset_cache[i]); } - preset->update(); } #endif } break; @@ -98,6 +97,8 @@ Ref<Shader> ColorPicker::circle_shader; void ColorPicker::init_shaders() { wheel_shader.instantiate(); wheel_shader->set_code(R"( +// ColorPicker wheel shader. + shader_type canvas_item; void fragment() { @@ -120,6 +121,8 @@ void fragment() { circle_shader.instantiate(); circle_shader->set_code(R"( +// ColorPicker circle shader. + shader_type canvas_item; uniform float v = 1.0; @@ -372,22 +375,23 @@ void ColorPicker::_update_color(bool p_update_sliders) { } void ColorPicker::_update_presets() { - return; - //presets should be shown using buttons or something else, this method is not a good idea - - presets_per_row = 10; - Size2 size = bt_add_preset->get_size(); - Size2 preset_size = Size2(MIN(size.width * presets.size(), presets_per_row * size.width), size.height * (Math::ceil((float)presets.size() / presets_per_row))); - preset->set_custom_minimum_size(preset_size); - preset_container->set_custom_minimum_size(preset_size); - preset->draw_rect(Rect2(Point2(), preset_size), Color(1, 1, 1, 0)); - - for (int i = 0; i < presets.size(); i++) { - int x = (i % presets_per_row) * size.width; - int y = (Math::floor((float)i / presets_per_row)) * size.height; - preset->draw_rect(Rect2(Point2(x, y), size), presets[i]); + int preset_size = _get_preset_size(); + // Only update the preset button size if it has changed. + if (preset_size != prev_preset_size) { + prev_preset_size = preset_size; + btn_add_preset->set_custom_minimum_size(Size2(preset_size, preset_size)); + for (int i = 1; i < preset_container->get_child_count(); i++) { + ColorPresetButton *cpb = Object::cast_to<ColorPresetButton>(preset_container->get_child(i)); + cpb->set_custom_minimum_size(Size2(preset_size, preset_size)); + } + } + // Only load preset buttons when the only child is the add-preset button. + if (preset_container->get_child_count() == 1) { + for (int i = 0; i < preset_cache.size(); i++) { + _add_preset_button(preset_size, preset_cache[i]); + } + _notification(NOTIFICATION_VISIBILITY_CHANGED); } - _notification(NOTIFICATION_VISIBILITY_CHANGED); } void ColorPicker::_text_type_toggled() { @@ -422,14 +426,37 @@ ColorPicker::PickerShapeType ColorPicker::get_picker_shape() const { return picker_type; } +inline int ColorPicker::_get_preset_size() { + return (int(get_minimum_size().width) - (preset_container->get_theme_constant(SNAME("hseparation")) * (preset_column_count - 1))) / preset_column_count; +} + +void ColorPicker::_add_preset_button(int p_size, const Color &p_color) { + ColorPresetButton *btn_preset = memnew(ColorPresetButton(p_color)); + btn_preset->set_preset_color(p_color); + btn_preset->set_custom_minimum_size(Size2(p_size, p_size)); + btn_preset->connect("gui_input", callable_mp(this, &ColorPicker::_preset_input), varray(p_color)); + btn_preset->set_tooltip(vformat(RTR("Color: #%s\nLMB: Apply color\nRMB: Remove preset"), p_color.to_html(p_color.a < 1))); + preset_container->add_child(btn_preset); +} + void ColorPicker::add_preset(const Color &p_color) { if (presets.find(p_color)) { presets.move_to_back(presets.find(p_color)); + + // Find button to move to the end. + for (int i = 1; i < preset_container->get_child_count(); i++) { + ColorPresetButton *current_btn = Object::cast_to<ColorPresetButton>(preset_container->get_child(i)); + if (current_btn && p_color == current_btn->get_preset_color()) { + preset_container->move_child(current_btn, preset_container->get_child_count() - 1); + break; + } + } } else { presets.push_back(p_color); preset_cache.push_back(p_color); + + _add_preset_button(_get_preset_size(), p_color); } - preset->update(); #ifdef TOOLS_ENABLED if (Engine::get_singleton()->is_editor_hint()) { @@ -443,7 +470,15 @@ void ColorPicker::erase_preset(const Color &p_color) { if (presets.find(p_color)) { presets.erase(presets.find(p_color)); preset_cache.erase(preset_cache.find(p_color)); - preset->update(); + + // Find preset button to remove. + for (int i = 1; i < preset_container->get_child_count(); i++) { + ColorPresetButton *current_btn = Object::cast_to<ColorPresetButton>(preset_container->get_child(i)); + if (current_btn && p_color == current_btn->get_preset_color()) { + current_btn->queue_delete(); + break; + } + } #ifdef TOOLS_ENABLED if (Engine::get_singleton()->is_editor_hint()) { @@ -560,7 +595,7 @@ void ColorPicker::_sample_draw() { const Rect2 rect_old = Rect2(Point2(), Size2(sample->get_size().width * 0.5, sample->get_size().height * 0.95)); if (display_old_color && old_color.a < 1.0) { - sample->draw_texture_rect(get_theme_icon(SNAME("preset_bg"), SNAME("ColorPicker")), rect_old, true); + sample->draw_texture_rect(get_theme_icon(SNAME("sample_bg"), SNAME("ColorPicker")), rect_old, true); } sample->draw_rect(rect_old, old_color); @@ -574,7 +609,7 @@ void ColorPicker::_sample_draw() { } if (color.a < 1.0) { - sample->draw_texture_rect(get_theme_icon(SNAME("preset_bg"), SNAME("ColorPicker")), rect_new, true); + sample->draw_texture_rect(get_theme_icon(SNAME("sample_bg"), SNAME("ColorPicker")), rect_new, true); } sample->draw_rect(rect_new, color); @@ -734,7 +769,7 @@ void ColorPicker::_slider_draw(int p_which) { #endif if (p_which == 3) { - scroll[p_which]->draw_texture_rect(get_theme_icon(SNAME("preset_bg"), SNAME("ColorPicker")), Rect2(Point2(0, margin), Size2(size.x, margin)), true); + scroll[p_which]->draw_texture_rect(get_theme_icon(SNAME("sample_bg"), SNAME("ColorPicker")), Rect2(Point2(0, margin), Size2(size.x, margin)), true); left_color = color; left_color.a = 0; @@ -932,43 +967,19 @@ void ColorPicker::_w_input(const Ref<InputEvent> &p_event) { } } -void ColorPicker::_preset_input(const Ref<InputEvent> &p_event) { +void ColorPicker::_preset_input(const Ref<InputEvent> &p_event, const Color &p_color) { Ref<InputEventMouseButton> bev = p_event; if (bev.is_valid()) { - int index = 0; if (bev->is_pressed() && bev->get_button_index() == MOUSE_BUTTON_LEFT) { - for (int i = 0; i < presets.size(); i++) { - int x = (i % presets_per_row) * bt_add_preset->get_size().x; - int y = (Math::floor((float)i / presets_per_row)) * bt_add_preset->get_size().y; - if (bev->get_position().x > x && bev->get_position().x < x + preset->get_size().x && bev->get_position().y > y && bev->get_position().y < y + preset->get_size().y) { - index = i; - } - } - set_pick_color(presets[index]); + set_pick_color(p_color); _update_color(); - emit_signal(SNAME("color_changed"), color); + emit_signal(SNAME("color_changed"), p_color); } else if (bev->is_pressed() && bev->get_button_index() == MOUSE_BUTTON_RIGHT && presets_enabled) { - index = bev->get_position().x / (preset->get_size().x / presets.size()); - Color clicked_preset = presets[index]; - erase_preset(clicked_preset); - emit_signal(SNAME("preset_removed"), clicked_preset); - bt_add_preset->show(); + erase_preset(p_color); + emit_signal(SNAME("preset_removed"), p_color); } } - - Ref<InputEventMouseMotion> mev = p_event; - - if (mev.is_valid()) { - int index = mev->get_position().x * presets.size(); - if (preset->get_size().x != 0) { - index /= preset->get_size().x; - } - if (index < 0 || index >= presets.size()) { - return; - } - preset->set_tooltip(vformat(RTR("Color: #%s\nLMB: Set color\nRMB: Remove preset"), presets[index].to_html(presets[index].a < 1))); - } } void ColorPicker::_screen_input(const Ref<InputEvent> &p_event) { @@ -1064,11 +1075,11 @@ void ColorPicker::_html_focus_exit() { void ColorPicker::set_presets_enabled(bool p_enabled) { presets_enabled = p_enabled; if (!p_enabled) { - bt_add_preset->set_disabled(true); - bt_add_preset->set_focus_mode(FOCUS_NONE); + btn_add_preset->set_disabled(true); + btn_add_preset->set_focus_mode(FOCUS_NONE); } else { - bt_add_preset->set_disabled(false); - bt_add_preset->set_focus_mode(FOCUS_ALL); + btn_add_preset->set_disabled(false); + btn_add_preset->set_focus_mode(FOCUS_ALL); } } @@ -1080,7 +1091,6 @@ void ColorPicker::set_presets_visible(bool p_visible) { presets_visible = p_visible; preset_separator->set_visible(p_visible); preset_container->set_visible(p_visible); - preset_container2->set_visible(p_visible); } bool ColorPicker::are_presets_visible() const { @@ -1129,7 +1139,7 @@ void ColorPicker::_bind_methods() { ColorPicker::ColorPicker() : BoxContainer(true) { HBoxContainer *hb_edit = memnew(HBoxContainer); - add_child(hb_edit); + add_child(hb_edit, false, INTERNAL_MODE_FRONT); hb_edit->set_v_size_flags(SIZE_EXPAND_FILL); hb_edit->add_child(uv_edit); @@ -1141,7 +1151,7 @@ ColorPicker::ColorPicker() : uv_edit->connect("draw", callable_mp(this, &ColorPicker::_hsv_draw), make_binds(0, uv_edit)); HBoxContainer *hb_smpl = memnew(HBoxContainer); - add_child(hb_smpl); + add_child(hb_smpl, false, INTERNAL_MODE_FRONT); hb_smpl->add_child(sample); sample->set_h_size_flags(SIZE_EXPAND_FILL); @@ -1155,12 +1165,12 @@ ColorPicker::ColorPicker() : btn_pick->connect("pressed", callable_mp(this, &ColorPicker::_screen_pick_pressed)); VBoxContainer *vbl = memnew(VBoxContainer); - add_child(vbl); + add_child(vbl, false, INTERNAL_MODE_FRONT); - add_child(memnew(HSeparator)); + add_child(memnew(HSeparator), false, INTERNAL_MODE_FRONT); VBoxContainer *vbr = memnew(VBoxContainer); - add_child(vbr); + add_child(vbr, false, INTERNAL_MODE_FRONT); vbr->set_h_size_flags(SIZE_EXPAND_FILL); for (int i = 0; i < 4; i++) { @@ -1263,20 +1273,16 @@ ColorPicker::ColorPicker() : set_pick_color(Color(1, 1, 1)); - add_child(preset_separator); + add_child(preset_separator, false, INTERNAL_MODE_FRONT); preset_container->set_h_size_flags(SIZE_EXPAND_FILL); - add_child(preset_container); + preset_container->set_columns(preset_column_count); + add_child(preset_container, false, INTERNAL_MODE_FRONT); - preset_container->add_child(preset); - preset->connect("gui_input", callable_mp(this, &ColorPicker::_preset_input)); - preset->connect("draw", callable_mp(this, &ColorPicker::_update_presets)); - - preset_container2->set_h_size_flags(SIZE_EXPAND_FILL); - add_child(preset_container2); - preset_container2->add_child(bt_add_preset); - bt_add_preset->set_tooltip(RTR("Add current color as a preset.")); - bt_add_preset->connect("pressed", callable_mp(this, &ColorPicker::_add_preset_pressed)); + btn_add_preset->set_icon_align(Button::ALIGN_CENTER); + btn_add_preset->set_tooltip(RTR("Add current color as a preset.")); + btn_add_preset->connect("pressed", callable_mp(this, &ColorPicker::_add_preset_pressed)); + preset_container->add_child(btn_add_preset); } ///////////////// @@ -1303,6 +1309,7 @@ void ColorPickerButton::pressed() { _update_picker(); popup->set_as_minsize(); + picker->_update_presets(); Rect2i usable_rect = popup->get_usable_parent_rect(); //let's try different positions to see which one we can use @@ -1398,7 +1405,7 @@ void ColorPickerButton::_update_picker() { picker = memnew(ColorPicker); picker->set_anchors_and_offsets_preset(PRESET_WIDE); popup->add_child(picker); - add_child(popup); + add_child(popup, false, INTERNAL_MODE_FRONT); 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)); @@ -1428,3 +1435,64 @@ void ColorPickerButton::_bind_methods() { ColorPickerButton::ColorPickerButton() { set_toggle_mode(true); } + +///////////////// + +void ColorPresetButton::_notification(int p_what) { + switch (p_what) { + case NOTIFICATION_DRAW: { + const Rect2 r = Rect2(Point2(0, 0), get_size()); + Ref<StyleBox> sb_raw = get_theme_stylebox(SNAME("preset_fg"), SNAME("ColorPresetButton"))->duplicate(); + Ref<StyleBoxFlat> sb_flat = sb_raw; + Ref<StyleBoxTexture> sb_texture = sb_raw; + + if (sb_flat.is_valid()) { + if (preset_color.a < 1) { + // Draw a background pattern when the color is transparent. + sb_flat->set_bg_color(Color(1, 1, 1)); + sb_flat->draw(get_canvas_item(), r); + + Rect2 bg_texture_rect = r.grow_side(SIDE_LEFT, -sb_flat->get_margin(SIDE_LEFT)); + bg_texture_rect = bg_texture_rect.grow_side(SIDE_RIGHT, -sb_flat->get_margin(SIDE_RIGHT)); + bg_texture_rect = bg_texture_rect.grow_side(SIDE_TOP, -sb_flat->get_margin(SIDE_TOP)); + bg_texture_rect = bg_texture_rect.grow_side(SIDE_BOTTOM, -sb_flat->get_margin(SIDE_BOTTOM)); + + draw_texture_rect(get_theme_icon(SNAME("preset_bg"), SNAME("ColorPresetButton")), bg_texture_rect, true); + sb_flat->set_bg_color(preset_color); + } + sb_flat->set_bg_color(preset_color); + sb_flat->draw(get_canvas_item(), r); + } else if (sb_texture.is_valid()) { + if (preset_color.a < 1) { + // Draw a background pattern when the color is transparent. + bool use_tile_texture = (sb_texture->get_h_axis_stretch_mode() == StyleBoxTexture::AxisStretchMode::AXIS_STRETCH_MODE_TILE) || (sb_texture->get_h_axis_stretch_mode() == StyleBoxTexture::AxisStretchMode::AXIS_STRETCH_MODE_TILE_FIT); + draw_texture_rect(get_theme_icon(SNAME("preset_bg"), SNAME("ColorPresetButton")), r, use_tile_texture); + } + sb_texture->set_modulate(preset_color); + sb_texture->draw(get_canvas_item(), r); + } else { + WARN_PRINT("Unsupported StyleBox used for ColorPresetButton. Use StyleBoxFlat or StyleBoxTexture instead."); + } + if (preset_color.r > 1 || preset_color.g > 1 || preset_color.b > 1) { + // Draw an indicator to denote that the color is "overbright" and can't be displayed accurately in the preview + draw_texture(Control::get_theme_icon(SNAME("overbright_indicator"), SNAME("ColorPresetButton")), Vector2(0, 0)); + } + + } break; + } +} + +void ColorPresetButton::set_preset_color(const Color &p_color) { + preset_color = p_color; +} + +Color ColorPresetButton::get_preset_color() const { + return preset_color; +} + +ColorPresetButton::ColorPresetButton(Color p_color) { + preset_color = p_color; +} + +ColorPresetButton::~ColorPresetButton() { +} diff --git a/scene/gui/color_picker.h b/scene/gui/color_picker.h index 60da3957aa..67ca007eb5 100644 --- a/scene/gui/color_picker.h +++ b/scene/gui/color_picker.h @@ -35,6 +35,7 @@ #include "scene/gui/box_container.h" #include "scene/gui/button.h" #include "scene/gui/check_button.h" +#include "scene/gui/grid_container.h" #include "scene/gui/label.h" #include "scene/gui/line_edit.h" #include "scene/gui/popup.h" @@ -43,6 +44,22 @@ #include "scene/gui/spin_box.h" #include "scene/gui/texture_rect.h" +class ColorPresetButton : public BaseButton { + GDCLASS(ColorPresetButton, BaseButton); + + Color preset_color; + +protected: + void _notification(int); + +public: + void set_preset_color(const Color &p_color); + Color get_preset_color() const; + + ColorPresetButton(Color p_color); + ~ColorPresetButton(); +}; + class ColorPicker : public BoxContainer { GDCLASS(ColorPicker, BoxContainer); @@ -69,12 +86,9 @@ private: Control *wheel = memnew(Control); Control *wheel_uv = memnew(Control); TextureRect *sample = memnew(TextureRect); - TextureRect *preset = memnew(TextureRect); - HBoxContainer *preset_container = memnew(HBoxContainer); - HBoxContainer *preset_container2 = memnew(HBoxContainer); + GridContainer *preset_container = memnew(GridContainer); HSeparator *preset_separator = memnew(HSeparator); - Button *bt_add_preset = memnew(Button); - List<Color> presets; + Button *btn_add_preset = memnew(Button); Button *btn_pick = memnew(Button); CheckButton *btn_hsv = memnew(CheckButton); CheckButton *btn_raw = memnew(CheckButton); @@ -83,14 +97,19 @@ private: Label *labels[4]; Button *text_type = memnew(Button); LineEdit *c_text = memnew(LineEdit); + bool edit_alpha = true; Size2i ms; bool text_is_constructor = false; - int presets_per_row = 0; PickerShapeType picker_type = SHAPE_HSV_WHEEL; + const int preset_column_count = 9; + int prev_preset_size = 0; + List<Color> presets; + Color color; Color old_color; + bool display_old_color = false; bool raw_mode_enabled = false; bool hsv_mode_enabled = false; @@ -100,6 +119,7 @@ private: bool spinning = false; bool presets_enabled = true; bool presets_visible = true; + float h = 0.0; float s = 0.0; float v = 0.0; @@ -109,7 +129,6 @@ private: void _value_changed(double); void _update_controls(); void _update_color(bool p_update_sliders = true); - void _update_presets(); void _update_text_value(); void _text_type_toggled(); void _sample_input(const Ref<InputEvent> &p_event); @@ -119,7 +138,7 @@ private: void _uv_input(const Ref<InputEvent> &p_event, Control *c); void _w_input(const Ref<InputEvent> &p_event); - void _preset_input(const Ref<InputEvent> &p_event); + void _preset_input(const Ref<InputEvent> &p_event, const Color &p_color); void _screen_input(const Ref<InputEvent> &p_event); void _add_preset_pressed(); void _screen_pick_pressed(); @@ -127,6 +146,9 @@ private: void _focus_exit(); void _html_focus_exit(); + inline int _get_preset_size(); + void _add_preset_button(int p_size, const Color &p_color); + protected: void _notification(int); static void _bind_methods(); @@ -152,6 +174,7 @@ public: void add_preset(const Color &p_color); void erase_preset(const Color &p_color); PackedColorArray get_presets() const; + void _update_presets(); void set_hsv_mode(bool p_enabled); bool is_hsv_mode() const; diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp index f114e06c75..81411d5844 100644 --- a/scene/gui/control.cpp +++ b/scene/gui/control.cpp @@ -30,6 +30,7 @@ #include "control.h" +#include "container.h" #include "core/config/project_settings.h" #include "core/math/geometry_2d.h" #include "core/object/message_queue.h" @@ -168,6 +169,20 @@ Size2 Control::_edit_get_minimum_size() const { } #endif +String Control::properties_managed_by_container[] = { + "offset_left", + "offset_top", + "offset_right", + "offset_bottom", + "anchor_left", + "anchor_top", + "anchor_right", + "anchor_bottom", + "rect_position", + "rect_scale", + "rect_size" +}; + void Control::accept_event() { if (is_inside_tree()) { get_viewport()->_gui_accept_event(); @@ -442,6 +457,20 @@ void Control::_validate_property(PropertyInfo &property) const { property.hint_string = hint_string; } + if (!Object::cast_to<Container>(get_parent())) { + return; + } + // Disable the property if it's managed by the parent container. + bool property_is_managed_by_container = false; + for (unsigned i = 0; i < properties_managed_by_container_count; i++) { + property_is_managed_by_container = properties_managed_by_container[i] == property.name; + if (property_is_managed_by_container) { + break; + } + } + if (property_is_managed_by_container) { + property.usage |= PROPERTY_USAGE_READ_ONLY; + } } Control *Control::get_parent_control() const { @@ -730,14 +759,9 @@ Variant Control::get_drag_data(const Point2 &p_point) { } } - if (get_script_instance()) { - Variant v = p_point; - const Variant *p = &v; - Callable::CallError ce; - Variant ret = get_script_instance()->call(SceneStringNames::get_singleton()->_get_drag_data, &p, 1, ce); - if (ce.error == Callable::CallError::CALL_OK) { - return ret; - } + Variant dd; + if (GDVIRTUAL_CALL(_get_drag_data, p_point, dd)) { + return dd; } return Variant(); @@ -752,16 +776,10 @@ bool Control::can_drop_data(const Point2 &p_point, const Variant &p_data) const } } - if (get_script_instance()) { - Variant v = p_point; - const Variant *p[2] = { &v, &p_data }; - Callable::CallError ce; - Variant ret = get_script_instance()->call(SceneStringNames::get_singleton()->_can_drop_data, p, 2, ce); - if (ce.error == Callable::CallError::CALL_OK) { - return ret; - } + bool ret; + if (GDVIRTUAL_CALL(_can_drop_data, p_point, p_data, ret)) { + return ret; } - return false; } @@ -775,15 +793,7 @@ void Control::drop_data(const Point2 &p_point, const Variant &p_data) { } } - if (get_script_instance()) { - Variant v = p_point; - const Variant *p[2] = { &v, &p_data }; - Callable::CallError ce; - Variant ret = get_script_instance()->call(SceneStringNames::get_singleton()->_drop_data, p, 2, ce); - if (ce.error == Callable::CallError::CALL_OK) { - return; - } - } + GDVIRTUAL_CALL(_drop_data, p_point, p_data); } void Control::force_drag(const Variant &p_data, Control *p_control) { @@ -799,16 +809,26 @@ void Control::set_drag_preview(Control *p_control) { get_viewport()->_gui_set_drag_preview(this, p_control); } +void Control::_call_gui_input(const Ref<InputEvent> &p_event) { + 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) + if (!is_inside_tree() || get_viewport()->is_input_handled()) { + return; //input was handled, abort + } + GDVIRTUAL_CALL(_gui_input, p_event); + if (!is_inside_tree() || get_viewport()->is_input_handled()) { + return; //input was handled, abort + } + gui_input(p_event); +} +void Control::gui_input(const Ref<InputEvent> &p_event) { +} + Size2 Control::get_minimum_size() const { - ScriptInstance *si = const_cast<Control *>(this)->get_script_instance(); - if (si) { - Callable::CallError ce; - Variant s = si->call(SceneStringNames::get_singleton()->_get_minimum_size, nullptr, 0, ce); - if (ce.error == Callable::CallError::CALL_OK) { - return s; - } + Vector2 ms; + if (GDVIRTUAL_CALL(_get_minimum_size, ms)) { + return ms; } - return Size2(); + return Vector2(); } template <class T> @@ -2123,8 +2143,9 @@ String Control::get_tooltip(const Point2 &p_pos) const { } Control *Control::make_custom_tooltip(const String &p_text) const { - if (get_script_instance()) { - return const_cast<Control *>(this)->call("_make_custom_tooltip", p_text); + Object *ret = nullptr; + if (GDVIRTUAL_CALL(_make_custom_tooltip, p_text, ret)) { + return Object::cast_to<Control>(ret); } return nullptr; } @@ -2499,14 +2520,11 @@ Vector<Vector2i> Control::structured_text_parser(StructuredTextParser p_theme_ty } } break; case STRUCTURED_TEXT_CUSTOM: { - if (get_script_instance()) { - Variant data = get_script_instance()->call(SceneStringNames::get_singleton()->_structured_text_parser, p_args, p_text); - if (data.get_type() == Variant::ARRAY) { - Array _data = data; - for (int i = 0; i < _data.size(); i++) { - if (_data[i].get_type() == Variant::VECTOR2I) { - ret.push_back(Vector2i(_data[i])); - } + Array r; + if (GDVIRTUAL_CALL(_structured_text_parser, p_args, p_text, r)) { + for (int i = 0; i < r.size(); i++) { + if (r[i].get_type() == Variant::VECTOR2I) { + ret.push_back(Vector2i(r[i])); } } } @@ -2823,21 +2841,6 @@ void Control::_bind_methods() { ClassDB::bind_method(D_METHOD("set_auto_translate", "enable"), &Control::set_auto_translate); ClassDB::bind_method(D_METHOD("is_auto_translating"), &Control::is_auto_translating); - BIND_VMETHOD(MethodInfo("_structured_text_parser", PropertyInfo(Variant::ARRAY, "args"), PropertyInfo(Variant::STRING, "text"))); - - BIND_VMETHOD(MethodInfo("_gui_input", PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent"))); - BIND_VMETHOD(MethodInfo(Variant::VECTOR2, "_get_minimum_size")); - - MethodInfo get_drag_data = MethodInfo("_get_drag_data", PropertyInfo(Variant::VECTOR2, "position")); - get_drag_data.return_val.usage |= PROPERTY_USAGE_NIL_IS_VARIANT; - BIND_VMETHOD(get_drag_data); - - BIND_VMETHOD(MethodInfo(Variant::BOOL, "_can_drop_data", PropertyInfo(Variant::VECTOR2, "position"), PropertyInfo(Variant::NIL, "data"))); - BIND_VMETHOD(MethodInfo("_drop_data", PropertyInfo(Variant::VECTOR2, "position"), PropertyInfo(Variant::NIL, "data"))); - BIND_VMETHOD(MethodInfo( - PropertyInfo(Variant::OBJECT, "control", PROPERTY_HINT_RESOURCE_TYPE, "Control"), - "_make_custom_tooltip", PropertyInfo(Variant::STRING, "for_text"))); - ADD_GROUP("Anchor", "anchor_"); ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anchor_left", PROPERTY_HINT_RANGE, "0,1,0.001,or_lesser,or_greater"), "_set_anchor", "get_anchor", SIDE_LEFT); ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anchor_top", PROPERTY_HINT_RANGE, "0,1,0.001,or_lesser,or_greater"), "_set_anchor", "get_anchor", SIDE_TOP); @@ -2994,5 +2997,14 @@ void Control::_bind_methods() { ADD_SIGNAL(MethodInfo("minimum_size_changed")); ADD_SIGNAL(MethodInfo("theme_changed")); - GDVIRTUAL_BIND(_has_point); + GDVIRTUAL_BIND(_has_point, "position"); + GDVIRTUAL_BIND(_structured_text_parser, "args", "text"); + GDVIRTUAL_BIND(_get_minimum_size); + + GDVIRTUAL_BIND(_get_drag_data, "at_position"); + GDVIRTUAL_BIND(_can_drop_data, "at_position", "data"); + GDVIRTUAL_BIND(_drop_data, "at_position", "data"); + GDVIRTUAL_BIND(_make_custom_tooltip, "for_text"); + + GDVIRTUAL_BIND(_gui_input, "event"); } diff --git a/scene/gui/control.h b/scene/gui/control.h index a871a8e9fb..9cec5d6e8d 100644 --- a/scene/gui/control.h +++ b/scene/gui/control.h @@ -31,10 +31,10 @@ #ifndef CONTROL_H #define CONTROL_H +#include "core/input/shortcut.h" #include "core/math/transform_2d.h" #include "core/object/gdvirtual.gen.inc" #include "core/templates/rid.h" -#include "scene/gui/shortcut.h" #include "scene/main/canvas_item.h" #include "scene/main/node.h" #include "scene/main/timer.h" @@ -230,6 +230,9 @@ private: } data; + static constexpr unsigned properties_managed_by_container_count = 11; + static String properties_managed_by_container[properties_managed_by_container_count]; + // used internally Control *_find_control_at_pos(CanvasItem *p_node, const Point2 &p_pos, const Transform2D &p_xform, Transform2D &r_inv_xform); @@ -263,6 +266,8 @@ private: friend class Viewport; + void _call_gui_input(const Ref<InputEvent> &p_event); + void _update_minimum_size_cache(); friend class Window; static void _propagate_theme_changed(Node *p_at, Control *p_owner, Window *p_owner_window, bool p_assign = true); @@ -272,7 +277,6 @@ private: static bool has_theme_item_in_types(Control *p_theme_owner, Window *p_theme_owner_window, Theme::DataType p_data_type, const StringName &p_name, List<StringName> p_theme_types); _FORCE_INLINE_ void _get_theme_type_dependencies(const StringName &p_theme_type, List<StringName> *p_list) const; - GDVIRTUAL1RC(bool, _has_point, Vector2) protected: virtual void add_child_notify(Node *p_child) override; virtual void remove_child_notify(Node *p_child) override; @@ -291,6 +295,17 @@ protected: //bind helpers + GDVIRTUAL1RC(bool, _has_point, Vector2) + GDVIRTUAL2RC(Array, _structured_text_parser, Array, String) + GDVIRTUAL0RC(Vector2, _get_minimum_size) + + GDVIRTUAL1RC(Variant, _get_drag_data, Vector2) + GDVIRTUAL2RC(bool, _can_drop_data, Vector2, Variant) + GDVIRTUAL2(_drop_data, Vector2, Variant) + GDVIRTUAL1RC(Object *, _make_custom_tooltip, String) + + GDVIRTUAL1(_gui_input, Ref<InputEvent>) + public: enum { /* NOTIFICATION_DRAW=30, @@ -333,6 +348,8 @@ public: virtual Size2 _edit_get_minimum_size() const override; #endif + virtual void gui_input(const Ref<InputEvent> &p_event); + void accept_event(); virtual Size2 get_minimum_size() const; diff --git a/scene/gui/dialogs.cpp b/scene/gui/dialogs.cpp index da858e8e83..5d98aaa698 100644 --- a/scene/gui/dialogs.cpp +++ b/scene/gui/dialogs.cpp @@ -319,7 +319,7 @@ AcceptDialog::AcceptDialog() { set_clamp_to_embedder(true); bg = memnew(Panel); - add_child(bg); + add_child(bg, false, INTERNAL_MODE_FRONT); hbc = memnew(HBoxContainer); @@ -331,9 +331,9 @@ AcceptDialog::AcceptDialog() { label->set_anchor(SIDE_BOTTOM, Control::ANCHOR_END); label->set_begin(Point2(margin, margin)); label->set_end(Point2(-margin, -button_margin - 10)); - add_child(label); + add_child(label, false, INTERNAL_MODE_FRONT); - add_child(hbc); + add_child(hbc, false, INTERNAL_MODE_FRONT); hbc->add_spacer(); ok = memnew(Button); diff --git a/scene/gui/file_dialog.cpp b/scene/gui/file_dialog.cpp index 2e4204e171..973b72973d 100644 --- a/scene/gui/file_dialog.cpp +++ b/scene/gui/file_dialog.cpp @@ -95,7 +95,7 @@ void FileDialog::_notification(int p_what) { } } -void FileDialog::_unhandled_input(const Ref<InputEvent> &p_event) { +void FileDialog::unhandled_input(const Ref<InputEvent> &p_event) { ERR_FAIL_COND(p_event.is_null()); Ref<InputEventKey> k = p_event; @@ -854,8 +854,6 @@ void FileDialog::_update_drives() { bool FileDialog::default_show_hidden_files = false; void FileDialog::_bind_methods() { - ClassDB::bind_method(D_METHOD("_unhandled_input"), &FileDialog::_unhandled_input); - ClassDB::bind_method(D_METHOD("_cancel_pressed"), &FileDialog::_cancel_pressed); ClassDB::bind_method(D_METHOD("clear_filters"), &FileDialog::clear_filters); @@ -926,7 +924,7 @@ FileDialog::FileDialog() { show_hidden_files = default_show_hidden_files; vbox = memnew(VBoxContainer); - add_child(vbox); + add_child(vbox, false, INTERNAL_MODE_FRONT); vbox->connect("theme_changed", callable_mp(this, &FileDialog::_theme_changed)); mode = FILE_MODE_SAVE_FILE; @@ -1025,8 +1023,7 @@ FileDialog::FileDialog() { filter->connect("item_selected", callable_mp(this, &FileDialog::_filter_selected)); confirm_save = memnew(ConfirmationDialog); - // confirm_save->set_as_top_level(true); - add_child(confirm_save); + add_child(confirm_save, false, INTERNAL_MODE_FRONT); confirm_save->connect("confirmed", callable_mp(this, &FileDialog::_save_confirm_pressed)); @@ -1038,16 +1035,16 @@ FileDialog::FileDialog() { makedirname = memnew(LineEdit); makedirname->set_structured_text_bidi_override(Control::STRUCTURED_TEXT_FILE); makevb->add_margin_child(TTRC("Name:"), makedirname); - add_child(makedialog); + add_child(makedialog, false, INTERNAL_MODE_FRONT); makedialog->register_text_enter(makedirname); makedialog->connect("confirmed", callable_mp(this, &FileDialog::_make_dir_confirm)); mkdirerr = memnew(AcceptDialog); mkdirerr->set_text(TTRC("Could not create folder.")); - add_child(mkdirerr); + add_child(mkdirerr, false, INTERNAL_MODE_FRONT); exterr = memnew(AcceptDialog); exterr->set_text(TTRC("Must use a valid extension.")); - add_child(exterr); + add_child(exterr, false, INTERNAL_MODE_FRONT); update_filters(); update_dir(); diff --git a/scene/gui/file_dialog.h b/scene/gui/file_dialog.h index 7fbafc4bb4..b5190bdab1 100644 --- a/scene/gui/file_dialog.h +++ b/scene/gui/file_dialog.h @@ -132,7 +132,7 @@ private: void _update_drives(); - void _unhandled_input(const Ref<InputEvent> &p_event); + virtual void unhandled_input(const Ref<InputEvent> &p_event) override; bool _is_open_should_be_disabled(); diff --git a/scene/gui/gradient_edit.cpp b/scene/gui/gradient_edit.cpp index 635f3c51b9..56b8a936e1 100644 --- a/scene/gui/gradient_edit.cpp +++ b/scene/gui/gradient_edit.cpp @@ -48,7 +48,7 @@ GradientEdit::GradientEdit() { picker = memnew(ColorPicker); popup->add_child(picker); - add_child(popup); + add_child(popup, false, INTERNAL_MODE_FRONT); } int GradientEdit::_get_point_from_pos(int x) { @@ -88,7 +88,7 @@ void GradientEdit::_show_color_picker() { GradientEdit::~GradientEdit() { } -void GradientEdit::_gui_input(const Ref<InputEvent> &p_event) { +void GradientEdit::gui_input(const Ref<InputEvent> &p_event) { ERR_FAIL_COND(p_event.is_null()); Ref<InputEventKey> k = p_event; @@ -458,6 +458,5 @@ Vector<Gradient::Point> &GradientEdit::get_points() { } void GradientEdit::_bind_methods() { - ClassDB::bind_method(D_METHOD("_gui_input"), &GradientEdit::_gui_input); ADD_SIGNAL(MethodInfo("ramp_changed")); } diff --git a/scene/gui/gradient_edit.h b/scene/gui/gradient_edit.h index b0ee2c4abb..a173631963 100644 --- a/scene/gui/gradient_edit.h +++ b/scene/gui/gradient_edit.h @@ -52,7 +52,7 @@ class GradientEdit : public Control { void _show_color_picker(); protected: - void _gui_input(const Ref<InputEvent> &p_event); + virtual void gui_input(const Ref<InputEvent> &p_event) override; void _notification(int p_what); static void _bind_methods(); diff --git a/scene/gui/graph_edit.cpp b/scene/gui/graph_edit.cpp index fcecbb5fca..cabae9feb2 100644 --- a/scene/gui/graph_edit.cpp +++ b/scene/gui/graph_edit.cpp @@ -51,10 +51,6 @@ GraphEditFilter::GraphEditFilter(GraphEdit *p_edit) { ge = p_edit; } -void GraphEditMinimap::_bind_methods() { - ClassDB::bind_method(D_METHOD("_gui_input"), &GraphEditMinimap::_gui_input); -} - GraphEditMinimap::GraphEditMinimap(GraphEdit *p_edit) { ge = p_edit; @@ -148,7 +144,7 @@ Vector2 GraphEditMinimap::_convert_to_graph_position(const Vector2 &p_position) return graph_position; } -void GraphEditMinimap::_gui_input(const Ref<InputEvent> &p_ev) { +void GraphEditMinimap::gui_input(const Ref<InputEvent> &p_ev) { ERR_FAIL_COND(p_ev.is_null()); if (!ge->is_minimap_enabled()) { @@ -370,7 +366,6 @@ void GraphEdit::_graph_node_raised(Node *p_gn) { } move_child(connections_layer, first_not_comment); - top_layer->raise(); emit_signal(SNAME("node_selected"), p_gn); } @@ -805,68 +800,36 @@ bool GraphEdit::is_in_hot_zone(const Vector2 &pos, const Vector2 &p_mouse_pos, c return true; } -template <class Vector2> -static _FORCE_INLINE_ Vector2 _bezier_interp(real_t t, Vector2 start, Vector2 control_1, Vector2 control_2, Vector2 end) { - /* Formula from Wikipedia article on Bezier curves. */ - real_t omt = (1.0 - t); - real_t omt2 = omt * omt; - real_t omt3 = omt2 * omt; - real_t t2 = t * t; - real_t t3 = t2 * t; - - return start * omt3 + control_1 * omt2 * t * 3.0 + control_2 * omt * t2 * 3.0 + end * t3; -} - -void GraphEdit::_bake_segment2d(Vector<Vector2> &points, Vector<Color> &colors, float p_begin, float p_end, const Vector2 &p_a, const Vector2 &p_out, const Vector2 &p_b, const Vector2 &p_in, int p_depth, int p_min_depth, int p_max_depth, float p_tol, const Color &p_color, const Color &p_to_color, int &lines) const { - float mp = p_begin + (p_end - p_begin) * 0.5; - Vector2 beg = _bezier_interp(p_begin, p_a, p_a + p_out, p_b + p_in, p_b); - Vector2 mid = _bezier_interp(mp, p_a, p_a + p_out, p_b + p_in, p_b); - Vector2 end = _bezier_interp(p_end, p_a, p_a + p_out, p_b + p_in, p_b); - - Vector2 na = (mid - beg).normalized(); - Vector2 nb = (end - mid).normalized(); - float dp = Math::rad2deg(Math::acos(na.dot(nb))); - - if (p_depth >= p_min_depth && (dp < p_tol || p_depth >= p_max_depth)) { - points.push_back((beg + end) * 0.5); - colors.push_back(p_color.lerp(p_to_color, mp)); - lines++; - } else { - _bake_segment2d(points, colors, p_begin, mp, p_a, p_out, p_b, p_in, p_depth + 1, p_min_depth, p_max_depth, p_tol, p_color, p_to_color, lines); - _bake_segment2d(points, colors, mp, p_end, p_a, p_out, p_b, p_in, p_depth + 1, p_min_depth, p_max_depth, p_tol, p_color, p_to_color, lines); +PackedVector2Array GraphEdit::get_connection_line(const Vector2 &p_from, const Vector2 &p_to) { + Vector<Vector2> ret; + if (GDVIRTUAL_CALL(_get_connection_line, p_from, p_to, ret)) { + return ret; } -} -void GraphEdit::_draw_cos_line(CanvasItem *p_where, const Vector2 &p_from, const Vector2 &p_to, const Color &p_color, const Color &p_to_color, float p_width, float p_bezier_ratio) { - //cubic bezier code - float diff = p_to.x - p_from.x; - float cp_offset; - int cp_len = get_theme_constant(SNAME("bezier_len_pos")) * p_bezier_ratio; - int cp_neg_len = get_theme_constant(SNAME("bezier_len_neg")) * p_bezier_ratio; - - if (diff > 0) { - cp_offset = MIN(cp_len, diff * 0.5); - } else { - cp_offset = MAX(MIN(cp_len - diff, cp_neg_len), -diff * 0.5); - } - - Vector2 c1 = Vector2(cp_offset * zoom, 0); - Vector2 c2 = Vector2(-cp_offset * zoom, 0); - - int lines = 0; + Curve2D curve; + Vector<Color> colors; + curve.add_point(p_from); + curve.set_point_out(0, Vector2(60, 0)); + curve.add_point(p_to); + curve.set_point_in(1, Vector2(-60, 0)); + return curve.tessellate(); +} - Vector<Point2> points; +void GraphEdit::_draw_connection_line(CanvasItem *p_where, const Vector2 &p_from, const Vector2 &p_to, const Color &p_color, const Color &p_to_color, float p_width, float p_zoom) { + Vector<Vector2> points = get_connection_line(p_from / p_zoom, p_to / p_zoom); + Vector<Vector2> scaled_points; Vector<Color> colors; - points.push_back(p_from); - colors.push_back(p_color); - _bake_segment2d(points, colors, 0, 1, p_from, c1, p_to, c2, 0, 3, 9, 3, p_color, p_to_color, lines); - points.push_back(p_to); - colors.push_back(p_to_color); + float length = (p_from / p_zoom).distance_to(p_to / p_zoom); + for (int i = 0; i < points.size(); i++) { + float d = (p_from / p_zoom).distance_to(points[i]) / length; + colors.push_back(p_color.lerp(p_to_color, d)); + scaled_points.push_back(points[i] * p_zoom); + } #ifdef TOOLS_ENABLED - p_where->draw_polyline_colors(points, colors, Math::floor(p_width * EDSCALE), lines_antialiased); + p_where->draw_polyline_colors(scaled_points, colors, Math::floor(p_width * EDSCALE), lines_antialiased); #else - p_where->draw_polyline_colors(points, colors, p_width, lines_antialiased); + p_where->draw_polyline_colors(scaled_points, colors, p_width, lines_antialiased); #endif } @@ -913,7 +876,7 @@ void GraphEdit::_connections_layer_draw() { color = color.lerp(activity_color, E->get().activity); tocolor = tocolor.lerp(activity_color, E->get().activity); } - _draw_cos_line(connections_layer, frompos, topos, color, tocolor, lines_thickness); + _draw_connection_line(connections_layer, frompos, topos, color, tocolor, lines_thickness, zoom); } while (to_erase.size()) { @@ -952,7 +915,7 @@ void GraphEdit::_top_layer_draw() { if (!connecting_out) { SWAP(pos, topos); } - _draw_cos_line(top_layer, pos, topos, col, col, lines_thickness); + _draw_connection_line(top_layer, pos, topos, col, col, lines_thickness, zoom); } if (box_selecting) { @@ -1056,7 +1019,7 @@ void GraphEdit::_minimap_draw() { from_color = from_color.lerp(activity_color, E.activity); to_color = to_color.lerp(activity_color, E.activity); } - _draw_cos_line(minimap, from_position, to_position, from_color, to_color, 1.0, 0.5); + _draw_connection_line(minimap, from_position, to_position, from_color, to_color, 0.1, minimap->_convert_from_graph_position(Vector2(zoom, zoom)).length()); } // Draw the "camera" viewport. @@ -1080,7 +1043,7 @@ void GraphEdit::set_selected(Node *p_child) { } } -void GraphEdit::_gui_input(const Ref<InputEvent> &p_ev) { +void GraphEdit::gui_input(const Ref<InputEvent> &p_ev) { ERR_FAIL_COND(p_ev.is_null()); Ref<InputEventMouseMotion> mm = p_ev; @@ -2048,7 +2011,6 @@ void GraphEdit::arrange_nodes() { if (gn->is_selected()) { selected_nodes.insert(gn->get_name()); - origin = origin < gn->get_position_offset() ? origin : gn->get_position_offset(); Set<StringName> s; for (List<Connection>::Element *E = connections.front(); E; E = E->next()) { GraphNode *p_from = Object::cast_to<GraphNode>(node_names[E->get().from]); @@ -2072,6 +2034,11 @@ void GraphEdit::arrange_nodes() { } } + if (!selected_nodes.size()) { + arranging_graph = false; + return; + } + HashMap<int, Vector<StringName>> layers = _layering(selected_nodes, upper_neighbours); _crossing_minimisation(layers, upper_neighbours); @@ -2098,16 +2065,16 @@ void GraphEdit::arrange_nodes() { for (const Set<StringName>::Element *E = block_heads.front(); E; E = E->next()) { _place_block(E->get(), gap_v, layers, root, align, node_names, inner_shift, sink, shift, new_positions); } + origin.y = Object::cast_to<GraphNode>(node_names[layers[0][0]])->get_position_offset().y - (new_positions[layers[0][0]].y + (float)inner_shift[layers[0][0]]); + origin.x = Object::cast_to<GraphNode>(node_names[layers[0][0]])->get_position_offset().x; for (const Set<StringName>::Element *E = block_heads.front(); E; E = E->next()) { StringName u = E->get(); - StringName prev = u; float start_from = origin.y + new_positions[E->get()].y; do { Vector2 cal_pos; cal_pos.y = start_from + (real_t)inner_shift[u]; new_positions.set(u, cal_pos); - prev = u; u = align[u]; } while (u != E->get()); } @@ -2130,10 +2097,11 @@ void GraphEdit::arrange_nodes() { if (current_node_size == largest_node_size) { cal_pos.x = start_from; } else { - float current_node_start_pos; - if (current_node_size >= largest_node_size / 2) { - current_node_start_pos = start_from; - } else { + float current_node_start_pos = start_from; + if (current_node_size < largest_node_size / 2) { + if (!(i || j)) { + start_from -= (largest_node_size - current_node_size); + } current_node_start_pos = start_from + largest_node_size - current_node_size; } cal_pos.x = current_node_start_pos; @@ -2179,6 +2147,7 @@ void GraphEdit::_bind_methods() { ClassDB::bind_method(D_METHOD("add_valid_connection_type", "from_type", "to_type"), &GraphEdit::add_valid_connection_type); ClassDB::bind_method(D_METHOD("remove_valid_connection_type", "from_type", "to_type"), &GraphEdit::remove_valid_connection_type); ClassDB::bind_method(D_METHOD("is_valid_connection_type", "from_type", "to_type"), &GraphEdit::is_valid_connection_type); + ClassDB::bind_method(D_METHOD("get_connection_line", "from", "to"), &GraphEdit::get_connection_line); ClassDB::bind_method(D_METHOD("set_zoom", "zoom"), &GraphEdit::set_zoom); ClassDB::bind_method(D_METHOD("get_zoom"), &GraphEdit::get_zoom); @@ -2218,7 +2187,6 @@ void GraphEdit::_bind_methods() { ClassDB::bind_method(D_METHOD("set_right_disconnects", "enable"), &GraphEdit::set_right_disconnects); ClassDB::bind_method(D_METHOD("is_right_disconnects_enabled"), &GraphEdit::is_right_disconnects_enabled); - ClassDB::bind_method(D_METHOD("_gui_input"), &GraphEdit::_gui_input); ClassDB::bind_method(D_METHOD("_update_scroll_offset"), &GraphEdit::_update_scroll_offset); ClassDB::bind_method(D_METHOD("get_zoom_hbox"), &GraphEdit::get_zoom_hbox); @@ -2227,6 +2195,8 @@ void GraphEdit::_bind_methods() { ClassDB::bind_method(D_METHOD("set_selected", "node"), &GraphEdit::set_selected); + GDVIRTUAL_BIND(_get_connection_line, "from", "to") + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "right_disconnects"), "set_right_disconnects", "is_right_disconnects_enabled"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "scroll_offset"), "set_scroll_ofs", "get_scroll_ofs"); ADD_PROPERTY(PropertyInfo(Variant::INT, "snap_distance"), "set_snap", "get_snap"); @@ -2275,14 +2245,14 @@ GraphEdit::GraphEdit() { zoom_max = (1 * Math::pow(zoom_step, 4)); top_layer = memnew(GraphEditFilter(this)); - add_child(top_layer); + add_child(top_layer, false, INTERNAL_MODE_BACK); top_layer->set_mouse_filter(MOUSE_FILTER_PASS); top_layer->set_anchors_and_offsets_preset(Control::PRESET_WIDE); top_layer->connect("draw", callable_mp(this, &GraphEdit::_top_layer_draw)); top_layer->connect("gui_input", callable_mp(this, &GraphEdit::_top_layer_input)); connections_layer = memnew(Control); - add_child(connections_layer); + add_child(connections_layer, false, INTERNAL_MODE_FRONT); connections_layer->connect("draw", callable_mp(this, &GraphEdit::_connections_layer_draw)); connections_layer->set_name("CLAYER"); connections_layer->set_disable_visibility_clip(true); // so it can draw freely and be offset diff --git a/scene/gui/graph_edit.h b/scene/gui/graph_edit.h index 9fd7cbef22..44e50aa3c2 100644 --- a/scene/gui/graph_edit.h +++ b/scene/gui/graph_edit.h @@ -62,8 +62,6 @@ class GraphEditMinimap : public Control { GraphEdit *ge; protected: - static void _bind_methods(); - public: GraphEditMinimap(GraphEdit *p_edit); @@ -88,7 +86,7 @@ private: Vector2 _convert_from_graph_position(const Vector2 &p_position); Vector2 _convert_to_graph_position(const Vector2 &p_position); - void _gui_input(const Ref<InputEvent> &p_ev); + virtual void gui_input(const Ref<InputEvent> &p_ev) override; void _adjust_graph_scroll(const Vector2 &p_offset); }; @@ -169,9 +167,8 @@ private: float lines_thickness = 2.0f; bool lines_antialiased = true; - void _bake_segment2d(Vector<Vector2> &points, Vector<Color> &colors, float p_begin, float p_end, const Vector2 &p_a, const Vector2 &p_out, const Vector2 &p_b, const Vector2 &p_in, int p_depth, int p_min_depth, int p_max_depth, float p_tol, const Color &p_color, const Color &p_to_color, int &lines) const; - - void _draw_cos_line(CanvasItem *p_where, const Vector2 &p_from, const Vector2 &p_to, const Color &p_color, const Color &p_to_color, float p_width, float p_bezier_ratio = 1.0); + PackedVector2Array get_connection_line(const Vector2 &p_from, const Vector2 &p_to); + void _draw_connection_line(CanvasItem *p_where, const Vector2 &p_from, const Vector2 &p_to, const Color &p_color, const Color &p_to_color, float p_width, float p_zoom); void _graph_node_raised(Node *p_gn); void _graph_node_moved(Node *p_gn); @@ -179,7 +176,7 @@ private: void _update_scroll(); void _scroll_moved(double); - void _gui_input(const Ref<InputEvent> &p_ev); + virtual void gui_input(const Ref<InputEvent> &p_ev) override; Control *connections_layer; GraphEditFilter *top_layer; @@ -256,6 +253,8 @@ protected: virtual void remove_child_notify(Node *p_child) override; void _notification(int p_what); + GDVIRTUAL2RC(Vector<Vector2>, _get_connection_line, Vector2, Vector2) + public: Error connect_node(const StringName &p_from, int p_from_port, const StringName &p_to, int p_to_port); bool is_node_connected(const StringName &p_from, int p_from_port, const StringName &p_to, int p_to_port); diff --git a/scene/gui/graph_node.cpp b/scene/gui/graph_node.cpp index e85cefcb7b..08c8c60d7a 100644 --- a/scene/gui/graph_node.cpp +++ b/scene/gui/graph_node.cpp @@ -863,7 +863,7 @@ Color GraphNode::get_connection_output_color(int p_idx) { return conn_output_cache[p_idx].color; } -void GraphNode::_gui_input(const Ref<InputEvent> &p_ev) { +void GraphNode::gui_input(const Ref<InputEvent> &p_ev) { ERR_FAIL_COND(p_ev.is_null()); Ref<InputEventMouseButton> mb = p_ev; @@ -946,8 +946,6 @@ void GraphNode::_bind_methods() { ClassDB::bind_method(D_METHOD("set_language", "language"), &GraphNode::set_language); ClassDB::bind_method(D_METHOD("get_language"), &GraphNode::get_language); - ClassDB::bind_method(D_METHOD("_gui_input"), &GraphNode::_gui_input); - ClassDB::bind_method(D_METHOD("set_slot", "idx", "enable_left", "type_left", "color_left", "enable_right", "type_right", "color_right", "custom_left", "custom_right"), &GraphNode::set_slot, DEFVAL(Ref<Texture2D>()), DEFVAL(Ref<Texture2D>())); ClassDB::bind_method(D_METHOD("clear_slot", "idx"), &GraphNode::clear_slot); ClassDB::bind_method(D_METHOD("clear_all_slots"), &GraphNode::clear_all_slots); diff --git a/scene/gui/graph_node.h b/scene/gui/graph_node.h index c70f616b47..c7c7006bfc 100644 --- a/scene/gui/graph_node.h +++ b/scene/gui/graph_node.h @@ -99,7 +99,7 @@ private: Overlay overlay = OVERLAY_DISABLED; protected: - void _gui_input(const Ref<InputEvent> &p_ev); + virtual void gui_input(const Ref<InputEvent> &p_ev) override; void _notification(int p_what); static void _bind_methods(); diff --git a/scene/gui/item_list.cpp b/scene/gui/item_list.cpp index 258d65112a..d10ad90c1f 100644 --- a/scene/gui/item_list.cpp +++ b/scene/gui/item_list.cpp @@ -48,6 +48,8 @@ void ItemList::_shape(int p_idx) { } else { item.text_buf->set_flags(TextServer::BREAK_NONE); } + item.text_buf->set_text_overrun_behavior(text_overrun_behavior); + item.text_buf->set_max_lines_visible(max_text_lines); } int ItemList::add_item(const String &p_item, const Ref<Texture2D> &p_texture, bool p_selectable) { @@ -453,6 +455,7 @@ void ItemList::set_max_text_lines(int p_lines) { for (int i = 0; i < items.size(); i++) { if (icon_mode == ICON_MODE_TOP && max_text_lines > 0) { items.write[i].text_buf->set_flags(TextServer::BREAK_MANDATORY | TextServer::BREAK_WORD_BOUND | TextServer::BREAK_GRAPHEME_BOUND); + items.write[i].text_buf->set_max_lines_visible(p_lines); } else { items.write[i].text_buf->set_flags(TextServer::BREAK_NONE); } @@ -534,7 +537,7 @@ Size2 ItemList::Item::get_icon_size() const { return size_result; } -void ItemList::_gui_input(const Ref<InputEvent> &p_event) { +void ItemList::gui_input(const Ref<InputEvent> &p_event) { ERR_FAIL_COND(p_event.is_null()); double prev_scroll = scroll_bar->get_value(); @@ -930,8 +933,14 @@ void ItemList::_notification(int p_what) { } if (items[i].text != "") { + int max_width = -1; + if (fixed_column_width) { + max_width = fixed_column_width; + } else if (same_column_width) { + max_width = items[i].rect_cache.size.x; + } + items.write[i].text_buf->set_width(max_width); Size2 s = items[i].text_buf->get_size(); - //s.width=MIN(s.width,fixed_column_width); if (icon_mode == ICON_MODE_TOP) { minsize.x = MAX(minsize.x, s.width); @@ -1139,11 +1148,8 @@ void ItemList::_notification(int p_what) { if (icon_mode == ICON_MODE_TOP) { pos.x += Math::floor((items[i].rect_cache.size.width - icon_size.width) / 2); - pos.y += MIN( - Math::floor((items[i].rect_cache.size.height - icon_size.height) / 2), - items[i].rect_cache.size.height - items[i].min_rect_cache.size.height); - text_ofs.y = icon_size.height + icon_margin; - text_ofs.y += items[i].rect_cache.size.height - items[i].min_rect_cache.size.height; + pos.y += icon_margin; + text_ofs.y = icon_size.height + icon_margin * 2; } else { pos.y += Math::floor((items[i].rect_cache.size.height - icon_size.height) / 2); text_ofs.x = icon_size.width + icon_margin; @@ -1210,7 +1216,6 @@ void ItemList::_notification(int p_what) { text_ofs.x = size.width - text_ofs.x - max_len; } - items.write[i].text_buf->set_width(max_len); items.write[i].text_buf->set_align(HALIGN_CENTER); if (outline_size > 0 && font_outline_color.a > 0) { @@ -1488,6 +1493,21 @@ bool ItemList::has_auto_height() const { return auto_height; } +void ItemList::set_text_overrun_behavior(TextParagraph::OverrunBehavior p_behavior) { + if (text_overrun_behavior != p_behavior) { + text_overrun_behavior = p_behavior; + for (int i = 0; i < items.size(); i++) { + items.write[i].text_buf->set_text_overrun_behavior(p_behavior); + } + shape_changed = true; + update(); + } +} + +TextParagraph::OverrunBehavior ItemList::get_text_overrun_behavior() const { + return text_overrun_behavior; +} + void ItemList::_bind_methods() { ClassDB::bind_method(D_METHOD("add_item", "text", "icon", "selectable"), &ItemList::add_item, DEFVAL(Variant()), DEFVAL(true)); ClassDB::bind_method(D_METHOD("add_icon_item", "icon", "selectable"), &ItemList::add_icon_item, DEFVAL(true)); @@ -1594,11 +1614,12 @@ void ItemList::_bind_methods() { ClassDB::bind_method(D_METHOD("get_v_scroll"), &ItemList::get_v_scroll); - ClassDB::bind_method(D_METHOD("_gui_input"), &ItemList::_gui_input); - ClassDB::bind_method(D_METHOD("_set_items"), &ItemList::_set_items); ClassDB::bind_method(D_METHOD("_get_items"), &ItemList::_get_items); + ClassDB::bind_method(D_METHOD("set_text_overrun_behavior", "overrun_behavior"), &ItemList::set_text_overrun_behavior); + ClassDB::bind_method(D_METHOD("get_text_overrun_behavior"), &ItemList::get_text_overrun_behavior); + ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "items", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_items", "_get_items"); ADD_PROPERTY(PropertyInfo(Variant::INT, "select_mode", PROPERTY_HINT_ENUM, "Single,Multi"), "set_select_mode", "get_select_mode"); @@ -1606,6 +1627,7 @@ void ItemList::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "allow_rmb_select"), "set_allow_rmb_select", "get_allow_rmb_select"); ADD_PROPERTY(PropertyInfo(Variant::INT, "max_text_lines", PROPERTY_HINT_RANGE, "1,10,1,or_greater"), "set_max_text_lines", "get_max_text_lines"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "auto_height"), "set_auto_height", "has_auto_height"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "text_overrun_behavior", PROPERTY_HINT_ENUM, "Trim Nothing,Trim Characters,Trim Words,Ellipsis,Word Ellipsis"), "set_text_overrun_behavior", "get_text_overrun_behavior"); ADD_GROUP("Columns", ""); ADD_PROPERTY(PropertyInfo(Variant::INT, "max_columns", PROPERTY_HINT_RANGE, "0,10,1,or_greater"), "set_max_columns", "get_max_columns"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "same_column_width"), "set_same_column_width", "is_same_column_width"); @@ -1634,7 +1656,7 @@ void ItemList::_bind_methods() { ItemList::ItemList() { scroll_bar = memnew(VScrollBar); - add_child(scroll_bar); + add_child(scroll_bar, false, INTERNAL_MODE_FRONT); scroll_bar->connect("value_changed", callable_mp(this, &ItemList::_scroll_changed)); diff --git a/scene/gui/item_list.h b/scene/gui/item_list.h index 86a0174a20..148fa7ba9f 100644 --- a/scene/gui/item_list.h +++ b/scene/gui/item_list.h @@ -95,6 +95,7 @@ private: SelectMode select_mode = SELECT_SINGLE; IconMode icon_mode = ICON_MODE_LEFT; VScrollBar *scroll_bar; + TextParagraph::OverrunBehavior text_overrun_behavior = TextParagraph::OVERRUN_NO_TRIMMING; uint64_t search_time_msec = 0; String search_string; @@ -122,7 +123,6 @@ private: void _set_items(const Array &p_items); void _scroll_changed(double); - void _gui_input(const Ref<InputEvent> &p_event); void _shape(int p_idx); protected: @@ -130,6 +130,8 @@ protected: static void _bind_methods(); public: + virtual void gui_input(const Ref<InputEvent> &p_event) override; + int add_item(const String &p_item, const Ref<Texture2D> &p_texture = Ref<Texture2D>(), bool p_selectable = true); int add_icon_item(const Ref<Texture2D> &p_item, bool p_selectable = true); @@ -182,6 +184,9 @@ public: void set_item_custom_fg_color(int p_idx, const Color &p_custom_fg_color); Color get_item_custom_fg_color(int p_idx) const; + void set_text_overrun_behavior(TextParagraph::OverrunBehavior p_behavior); + TextParagraph::OverrunBehavior get_text_overrun_behavior() const; + void select(int p_idx, bool p_single = true); void deselect(int p_idx); void deselect_all(); diff --git a/scene/gui/label.cpp b/scene/gui/label.cpp index 50db1fc3ce..3f87003423 100644 --- a/scene/gui/label.cpp +++ b/scene/gui/label.cpp @@ -66,11 +66,11 @@ bool Label::is_uppercase() const { int Label::get_line_height(int p_line) const { Ref<Font> font = get_theme_font(SNAME("font")); if (p_line >= 0 && p_line < lines_rid.size()) { - return TS->shaped_text_get_size(lines_rid[p_line]).y + font->get_spacing(Font::SPACING_TOP) + font->get_spacing(Font::SPACING_BOTTOM); + return TS->shaped_text_get_size(lines_rid[p_line]).y + font->get_spacing(TextServer::SPACING_TOP) + font->get_spacing(TextServer::SPACING_BOTTOM); } else if (lines_rid.size() > 0) { int h = 0; for (int i = 0; i < lines_rid.size(); i++) { - h = MAX(h, TS->shaped_text_get_size(lines_rid[i]).y) + font->get_spacing(Font::SPACING_TOP) + font->get_spacing(Font::SPACING_BOTTOM); + h = MAX(h, TS->shaped_text_get_size(lines_rid[i]).y) + font->get_spacing(TextServer::SPACING_TOP) + font->get_spacing(TextServer::SPACING_BOTTOM); } return h; } else { @@ -89,7 +89,10 @@ void Label::_shape() { } else { TS->shaped_text_set_direction(text_rid, (TextServer::Direction)text_direction); } - TS->shaped_text_add_string(text_rid, (uppercase) ? xl_text.to_upper() : xl_text, get_theme_font(SNAME("font"))->get_rids(), get_theme_font_size(SNAME("font_size")), opentype_features, (language != "") ? language : TranslationServer::get_singleton()->get_tool_locale()); + const Ref<Font> &font = get_theme_font(SNAME("font")); + int font_size = get_theme_font_size(SNAME("font_size")); + ERR_FAIL_COND(font.is_null()); + TS->shaped_text_add_string(text_rid, (uppercase) ? xl_text.to_upper() : xl_text, font->get_rids(), font_size, opentype_features, (language != "") ? language : TranslationServer::get_singleton()->get_tool_locale()); TS->shaped_text_set_bidi_override(text_rid, structured_text_parser(st_parser, st_args, xl_text)); dirty = false; lines_dirty = true; @@ -217,7 +220,7 @@ void Label::_update_visible() { minsize.height = 0; int last_line = MIN(lines_rid.size(), lines_visible + lines_skipped); for (int64_t i = lines_skipped; i < last_line; i++) { - minsize.height += TS->shaped_text_get_size(lines_rid[i]).y + font->get_spacing(Font::SPACING_TOP) + font->get_spacing(Font::SPACING_BOTTOM) + line_spacing; + minsize.height += TS->shaped_text_get_size(lines_rid[i]).y + font->get_spacing(TextServer::SPACING_TOP) + font->get_spacing(TextServer::SPACING_BOTTOM) + line_spacing; if (minsize.height > (get_size().height - style->get_minimum_size().height + line_spacing)) { break; } @@ -286,7 +289,7 @@ void Label::_notification(int p_what) { // Get number of lines to fit to the height. for (int64_t i = lines_skipped; i < lines_rid.size(); i++) { - total_h += TS->shaped_text_get_size(lines_rid[i]).y + font->get_spacing(Font::SPACING_TOP) + font->get_spacing(Font::SPACING_BOTTOM) + line_spacing; + total_h += TS->shaped_text_get_size(lines_rid[i]).y + font->get_spacing(TextServer::SPACING_TOP) + font->get_spacing(TextServer::SPACING_BOTTOM) + line_spacing; if (total_h > (get_size().height - style->get_minimum_size().height + line_spacing)) { break; } @@ -302,7 +305,7 @@ void Label::_notification(int p_what) { // Get real total height. total_h = 0; for (int64_t i = lines_skipped; i < last_line; i++) { - total_h += TS->shaped_text_get_size(lines_rid[i]).y + font->get_spacing(Font::SPACING_TOP) + font->get_spacing(Font::SPACING_BOTTOM) + line_spacing; + total_h += TS->shaped_text_get_size(lines_rid[i]).y + font->get_spacing(TextServer::SPACING_TOP) + font->get_spacing(TextServer::SPACING_BOTTOM) + line_spacing; } total_h += style->get_margin(SIDE_TOP) + style->get_margin(SIDE_BOTTOM); @@ -357,7 +360,7 @@ void Label::_notification(int p_what) { for (int i = lines_skipped; i < last_line; i++) { Size2 line_size = TS->shaped_text_get_size(lines_rid[i]); ofs.x = 0; - ofs.y += TS->shaped_text_get_ascent(lines_rid[i]) + font->get_spacing(Font::SPACING_TOP); + ofs.y += TS->shaped_text_get_ascent(lines_rid[i]) + font->get_spacing(TextServer::SPACING_TOP); switch (align) { case ALIGN_FILL: if (rtl && autowrap_mode != AUTOWRAP_OFF) { @@ -433,7 +436,7 @@ void Label::_notification(int p_what) { } } } - ofs.y += TS->shaped_text_get_descent(lines_rid[i]) + vsep + line_spacing + font->get_spacing(Font::SPACING_BOTTOM); + ofs.y += TS->shaped_text_get_descent(lines_rid[i]) + vsep + line_spacing + font->get_spacing(TextServer::SPACING_BOTTOM); } } @@ -455,7 +458,7 @@ Size2 Label::get_minimum_size() const { Size2 min_size = minsize; Ref<Font> font = get_theme_font(SNAME("font")); - min_size.height = MAX(min_size.height, font->get_height(get_theme_font_size(SNAME("font_size"))) + font->get_spacing(Font::SPACING_TOP) + font->get_spacing(Font::SPACING_BOTTOM)); + min_size.height = MAX(min_size.height, font->get_height(get_theme_font_size(SNAME("font_size"))) + font->get_spacing(TextServer::SPACING_TOP) + font->get_spacing(TextServer::SPACING_BOTTOM)); Size2 min_style = get_theme_stylebox(SNAME("normal"))->get_minimum_size(); if (autowrap_mode != AUTOWRAP_OFF) { @@ -486,7 +489,7 @@ int Label::get_visible_line_count() const { int lines_visible = 0; float total_h = 0.0; for (int64_t i = lines_skipped; i < lines_rid.size(); i++) { - total_h += TS->shaped_text_get_size(lines_rid[i]).y + font->get_spacing(Font::SPACING_TOP) + font->get_spacing(Font::SPACING_BOTTOM) + line_spacing; + total_h += TS->shaped_text_get_size(lines_rid[i]).y + font->get_spacing(TextServer::SPACING_TOP) + font->get_spacing(TextServer::SPACING_BOTTOM) + line_spacing; if (total_h > (get_size().height - style->get_minimum_size().height + line_spacing)) { break; } diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp index 11e08b231e..d9acbeb828 100644 --- a/scene/gui/line_edit.cpp +++ b/scene/gui/line_edit.cpp @@ -216,7 +216,7 @@ void LineEdit::_delete(bool p_word, bool p_all_to_right) { } } -void LineEdit::_gui_input(Ref<InputEvent> p_event) { +void LineEdit::gui_input(const Ref<InputEvent> &p_event) { ERR_FAIL_COND(p_event.is_null()); Ref<InputEventMouseButton> b = p_event; @@ -641,7 +641,7 @@ void LineEdit::_notification(int p_what) { int x_ofs = 0; bool using_placeholder = text.is_empty() && ime_text.is_empty(); float text_width = TS->shaped_text_get_size(text_rid).x; - float text_height = TS->shaped_text_get_size(text_rid).y + font->get_spacing(Font::SPACING_TOP) + font->get_spacing(Font::SPACING_BOTTOM); + float text_height = TS->shaped_text_get_size(text_rid).y + font->get_spacing(TextServer::SPACING_TOP) + font->get_spacing(TextServer::SPACING_BOTTOM); switch (align) { case ALIGN_FILL: @@ -674,7 +674,7 @@ void LineEdit::_notification(int p_what) { int y_ofs = style->get_offset().y + (y_area - text_height) / 2; Color selection_color = get_theme_color(SNAME("selection_color")); - Color font_color = is_editable() ? get_theme_color(SNAME("font_color")) : get_theme_color(SNAME("font_uneditable_color")); + Color font_color = get_theme_color(is_editable() ? SNAME("font_color") : SNAME("font_uneditable_color")); Color font_selected_color = get_theme_color(SNAME("font_selected_color")); Color caret_color = get_theme_color(SNAME("caret_color")); @@ -1531,7 +1531,7 @@ Size2 LineEdit::get_minimum_size() const { min_size.width = MAX(min_size.width, full_width + em_space_size); } - min_size.height = MAX(TS->shaped_text_get_size(text_rid).y + font->get_spacing(Font::SPACING_TOP) + font->get_spacing(Font::SPACING_BOTTOM), font->get_height(font_size)); + min_size.height = MAX(TS->shaped_text_get_size(text_rid).y + font->get_spacing(TextServer::SPACING_TOP) + font->get_spacing(TextServer::SPACING_BOTTOM), font->get_height(font_size)); // Take icons into account. bool using_placeholder = text.is_empty() && ime_text.is_empty(); @@ -1941,6 +1941,7 @@ void LineEdit::_shape() { const Ref<Font> &font = get_theme_font(SNAME("font")); int font_size = get_theme_font_size(SNAME("font_size")); + ERR_FAIL_COND(font.is_null()); TS->shaped_text_add_string(text_rid, t, font->get_rids(), font_size, opentype_features, (language != "") ? language : TranslationServer::get_singleton()->get_tool_locale()); TS->shaped_text_set_bidi_override(text_rid, structured_text_parser(st_parser, st_args, t)); @@ -2084,7 +2085,6 @@ void LineEdit::_bind_methods() { ClassDB::bind_method(D_METHOD("set_align", "align"), &LineEdit::set_align); ClassDB::bind_method(D_METHOD("get_align"), &LineEdit::get_align); - ClassDB::bind_method(D_METHOD("_gui_input"), &LineEdit::_gui_input); ClassDB::bind_method(D_METHOD("clear"), &LineEdit::clear); ClassDB::bind_method(D_METHOD("select", "from", "to"), &LineEdit::select, DEFVAL(0), DEFVAL(-1)); ClassDB::bind_method(D_METHOD("select_all"), &LineEdit::select_all); @@ -2220,7 +2220,7 @@ void LineEdit::_bind_methods() { void LineEdit::_ensure_menu() { if (!menu) { menu = memnew(PopupMenu); - add_child(menu); + add_child(menu, false, INTERNAL_MODE_FRONT); menu_dir = memnew(PopupMenu); menu_dir->set_name("DirMenu"); @@ -2305,7 +2305,7 @@ LineEdit::LineEdit() { set_mouse_filter(MOUSE_FILTER_STOP); caret_blink_timer = memnew(Timer); - add_child(caret_blink_timer); + add_child(caret_blink_timer, false, INTERNAL_MODE_FRONT); caret_blink_timer->set_wait_time(0.65); caret_blink_timer->connect("timeout", callable_mp(this, &LineEdit::_toggle_draw_caret)); set_caret_blink_enabled(false); diff --git a/scene/gui/line_edit.h b/scene/gui/line_edit.h index 0e9c032e88..e364a79c83 100644 --- a/scene/gui/line_edit.h +++ b/scene/gui/line_edit.h @@ -202,7 +202,7 @@ private: protected: void _notification(int p_what); static void _bind_methods(); - void _gui_input(Ref<InputEvent> p_event); + virtual void gui_input(const Ref<InputEvent> &p_event) override; bool _set(const StringName &p_name, const Variant &p_value); bool _get(const StringName &p_name, Variant &r_ret) const; diff --git a/scene/gui/link_button.cpp b/scene/gui/link_button.cpp index 419d49bccf..925e6f5b97 100644 --- a/scene/gui/link_button.cpp +++ b/scene/gui/link_button.cpp @@ -41,12 +41,16 @@ void LinkButton::_shape() { } else { text_buf->set_direction((TextServer::Direction)text_direction); } - TS->shaped_text_set_bidi_override(text_buf->get_rid(), structured_text_parser(st_parser, st_args, text)); - text_buf->add_string(text, font, font_size, opentype_features, (language != "") ? language : TranslationServer::get_singleton()->get_tool_locale()); + TS->shaped_text_set_bidi_override(text_buf->get_rid(), structured_text_parser(st_parser, st_args, xl_text)); + text_buf->add_string(xl_text, font, font_size, opentype_features, (language != "") ? language : TranslationServer::get_singleton()->get_tool_locale()); } void LinkButton::set_text(const String &p_text) { + if (text == p_text) { + return; + } text = p_text; + xl_text = atr(text); _shape(); minimum_size_changed(); update(); @@ -141,7 +145,13 @@ Size2 LinkButton::get_minimum_size() const { void LinkButton::_notification(int p_what) { switch (p_what) { - case NOTIFICATION_TRANSLATION_CHANGED: + case NOTIFICATION_TRANSLATION_CHANGED: { + xl_text = atr(text); + _shape(); + + minimum_size_changed(); + update(); + } break; case NOTIFICATION_LAYOUT_DIRECTION_CHANGED: { update(); } break; diff --git a/scene/gui/link_button.h b/scene/gui/link_button.h index 7eaa9f88b6..231543c63c 100644 --- a/scene/gui/link_button.h +++ b/scene/gui/link_button.h @@ -47,6 +47,7 @@ public: private: String text; + String xl_text; Ref<TextLine> text_buf; UnderlineMode underline_mode = UNDERLINE_MODE_ALWAYS; diff --git a/scene/gui/menu_button.cpp b/scene/gui/menu_button.cpp index dc6c7fec28..737ba84617 100644 --- a/scene/gui/menu_button.cpp +++ b/scene/gui/menu_button.cpp @@ -33,7 +33,7 @@ #include "core/os/keyboard.h" #include "scene/main/window.h" -void MenuButton::_unhandled_key_input(Ref<InputEvent> p_event) { +void MenuButton::unhandled_key_input(const Ref<InputEvent> &p_event) { ERR_FAIL_COND(p_event.is_null()); if (!_is_focus_owner_in_shorcut_context()) { @@ -100,8 +100,8 @@ void MenuButton::pressed() { popup->popup(); } -void MenuButton::_gui_input(Ref<InputEvent> p_event) { - BaseButton::_gui_input(p_event); +void MenuButton::gui_input(const Ref<InputEvent> &p_event) { + BaseButton::gui_input(p_event); } PopupMenu *MenuButton::get_popup() const { @@ -172,7 +172,7 @@ MenuButton::MenuButton() { popup = memnew(PopupMenu); popup->hide(); - add_child(popup); + add_child(popup, false, INTERNAL_MODE_FRONT); popup->connect("about_to_popup", callable_mp(this, &MenuButton::_popup_visibility_changed), varray(true)); popup->connect("popup_hide", callable_mp(this, &MenuButton::_popup_visibility_changed), varray(false)); } diff --git a/scene/gui/menu_button.h b/scene/gui/menu_button.h index cc2ca117c4..730495b65d 100644 --- a/scene/gui/menu_button.h +++ b/scene/gui/menu_button.h @@ -47,14 +47,14 @@ class MenuButton : public Button { Array _get_items() const; void _set_items(const Array &p_items); - void _gui_input(Ref<InputEvent> p_event) override; + virtual void gui_input(const Ref<InputEvent> &p_event) override; void _popup_visibility_changed(bool p_visible); protected: void _notification(int p_what); static void _bind_methods(); - virtual void _unhandled_key_input(Ref<InputEvent> p_event) override; + virtual void unhandled_key_input(const Ref<InputEvent> &p_event) override; public: virtual void pressed() override; diff --git a/scene/gui/option_button.cpp b/scene/gui/option_button.cpp index cd55f258b3..d16e96dbec 100644 --- a/scene/gui/option_button.cpp +++ b/scene/gui/option_button.cpp @@ -351,7 +351,7 @@ OptionButton::OptionButton() { popup = memnew(PopupMenu); popup->hide(); - add_child(popup); + add_child(popup, false, INTERNAL_MODE_FRONT); popup->connect("index_pressed", callable_mp(this, &OptionButton::_selected)); popup->connect("id_focused", callable_mp(this, &OptionButton::_focused)); popup->connect("popup_hide", callable_mp((BaseButton *)this, &BaseButton::set_pressed), varray(false)); diff --git a/scene/gui/popup.cpp b/scene/gui/popup.cpp index f7e7e1cd60..e9414598a2 100644 --- a/scene/gui/popup.cpp +++ b/scene/gui/popup.cpp @@ -255,5 +255,5 @@ void PopupPanel::_notification(int p_what) { PopupPanel::PopupPanel() { panel = memnew(Panel); - add_child(panel); + add_child(panel, false, INTERNAL_MODE_FRONT); } diff --git a/scene/gui/popup_menu.cpp b/scene/gui/popup_menu.cpp index aff367e398..c0a559e624 100644 --- a/scene/gui/popup_menu.cpp +++ b/scene/gui/popup_menu.cpp @@ -228,6 +228,7 @@ void PopupMenu::_activate_submenu(int p_over) { // Set autohide areas PopupMenu *submenu_pum = Object::cast_to<PopupMenu>(submenu_popup); if (submenu_pum) { + submenu_pum->take_mouse_focus(); // Make the position of the parent popup relative to submenu popup this_rect.position = this_rect.position - submenu_pum->get_position(); @@ -251,7 +252,7 @@ void PopupMenu::_submenu_timeout() { submenu_over = -1; } -void PopupMenu::_gui_input(const Ref<InputEvent> &p_event) { +void PopupMenu::gui_input(const Ref<InputEvent> &p_event) { ERR_FAIL_COND(p_event.is_null()); if (p_event->is_action("ui_down") && p_event->is_pressed()) { @@ -1581,8 +1582,6 @@ void PopupMenu::take_mouse_focus() { } void PopupMenu::_bind_methods() { - ClassDB::bind_method(D_METHOD("_gui_input"), &PopupMenu::_gui_input); - ClassDB::bind_method(D_METHOD("add_item", "label", "id", "accel"), &PopupMenu::add_item, DEFVAL(-1), DEFVAL(0)); ClassDB::bind_method(D_METHOD("add_icon_item", "texture", "label", "id", "accel"), &PopupMenu::add_icon_item, DEFVAL(-1), DEFVAL(0)); ClassDB::bind_method(D_METHOD("add_check_item", "label", "id", "accel"), &PopupMenu::add_check_item, DEFVAL(-1), DEFVAL(0)); @@ -1691,7 +1690,7 @@ PopupMenu::PopupMenu() { // Margin Container margin_container = memnew(MarginContainer); margin_container->set_anchors_and_offsets_preset(Control::PRESET_WIDE); - add_child(margin_container); + add_child(margin_container, false, INTERNAL_MODE_FRONT); margin_container->connect("draw", callable_mp(this, &PopupMenu::_draw_background)); // Scroll Container @@ -1705,22 +1704,22 @@ PopupMenu::PopupMenu() { control->set_anchors_and_offsets_preset(Control::PRESET_WIDE); control->set_h_size_flags(Control::SIZE_EXPAND_FILL); control->set_v_size_flags(Control::SIZE_EXPAND_FILL); - scroll_container->add_child(control); + scroll_container->add_child(control, false, INTERNAL_MODE_FRONT); control->connect("draw", callable_mp(this, &PopupMenu::_draw_items)); - connect("window_input", callable_mp(this, &PopupMenu::_gui_input)); + connect("window_input", callable_mp(this, &PopupMenu::gui_input)); submenu_timer = memnew(Timer); submenu_timer->set_wait_time(0.3); submenu_timer->set_one_shot(true); submenu_timer->connect("timeout", callable_mp(this, &PopupMenu::_submenu_timeout)); - add_child(submenu_timer); + add_child(submenu_timer, false, INTERNAL_MODE_FRONT); minimum_lifetime_timer = memnew(Timer); minimum_lifetime_timer->set_wait_time(0.3); minimum_lifetime_timer->set_one_shot(true); minimum_lifetime_timer->connect("timeout", callable_mp(this, &PopupMenu::_minimum_lifetime_timeout)); - add_child(minimum_lifetime_timer); + add_child(minimum_lifetime_timer, false, INTERNAL_MODE_FRONT); } PopupMenu::~PopupMenu() { diff --git a/scene/gui/popup_menu.h b/scene/gui/popup_menu.h index aedc5d0155..5c427e43bc 100644 --- a/scene/gui/popup_menu.h +++ b/scene/gui/popup_menu.h @@ -31,10 +31,10 @@ #ifndef POPUP_MENU_H #define POPUP_MENU_H +#include "core/input/shortcut.h" #include "scene/gui/margin_container.h" #include "scene/gui/popup.h" #include "scene/gui/scroll_container.h" -#include "scene/gui/shortcut.h" #include "scene/resources/text_line.h" class PopupMenu : public Popup { @@ -107,7 +107,7 @@ class PopupMenu : public Popup { void _shape_item(int p_item); - void _gui_input(const Ref<InputEvent> &p_event); + virtual void gui_input(const Ref<InputEvent> &p_event); void _activate_submenu(int p_over); void _submenu_timeout(); diff --git a/scene/gui/rich_text_effect.cpp b/scene/gui/rich_text_effect.cpp index 39718a269a..236d106af8 100644 --- a/scene/gui/rich_text_effect.cpp +++ b/scene/gui/rich_text_effect.cpp @@ -32,8 +32,15 @@ #include "core/object/script_language.h" -void RichTextEffect::_bind_methods() { - BIND_VMETHOD(MethodInfo(Variant::BOOL, "_process_custom_fx", PropertyInfo(Variant::OBJECT, "char_fx", PROPERTY_HINT_RESOURCE_TYPE, "CharFXTransform"))); +CharFXTransform::CharFXTransform() { +} + +CharFXTransform::~CharFXTransform() { + environment.clear(); +} + +void RichTextEffect::_bind_methods(){ + GDVIRTUAL_BIND(_process_custom_fx, "char_fx") } Variant RichTextEffect::get_bbcode() const { @@ -49,15 +56,10 @@ Variant RichTextEffect::get_bbcode() const { bool RichTextEffect::_process_effect_impl(Ref<CharFXTransform> p_cfx) { bool return_value = false; - if (get_script_instance()) { - Variant v = get_script_instance()->call("_process_custom_fx", p_cfx); - if (v.get_type() != Variant::BOOL) { - return_value = false; - } else { - return_value = (bool)v; - } + if (GDVIRTUAL_CALL(_process_custom_fx, p_cfx, return_value)) { + return return_value; } - return return_value; + return false; } RichTextEffect::RichTextEffect() { @@ -101,10 +103,3 @@ void CharFXTransform::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "glyph_index"), "set_glyph_index", "get_glyph_index"); ADD_PROPERTY(PropertyInfo(Variant::RID, "font"), "set_font", "get_font"); } - -CharFXTransform::CharFXTransform() { -} - -CharFXTransform::~CharFXTransform() { - environment.clear(); -} diff --git a/scene/gui/rich_text_effect.h b/scene/gui/rich_text_effect.h index 67323e7f93..f5506542bb 100644 --- a/scene/gui/rich_text_effect.h +++ b/scene/gui/rich_text_effect.h @@ -32,20 +32,8 @@ #define RICH_TEXT_EFFECT_H #include "core/io/resource.h" - -class RichTextEffect : public Resource { - GDCLASS(RichTextEffect, Resource); - OBJ_SAVE_TYPE(RichTextEffect); - -protected: - static void _bind_methods(); - -public: - Variant get_bbcode() const; - bool _process_effect_impl(Ref<class CharFXTransform> p_cfx); - - RichTextEffect(); -}; +#include "core/object/gdvirtual.gen.inc" +#include "core/object/script_language.h" class CharFXTransform : public RefCounted { GDCLASS(CharFXTransform, RefCounted); @@ -61,7 +49,7 @@ public: Color color; double elapsed_time = 0.0f; Dictionary environment; - uint32_t glpyh_index = 0; + uint32_t glyph_index = 0; RID font; CharFXTransform(); @@ -80,8 +68,8 @@ public: Color get_color() { return color; } void set_color(Color p_color) { color = p_color; } - uint32_t get_glyph_index() const { return glpyh_index; }; - void set_glyph_index(uint32_t p_glpyh_index) { glpyh_index = p_glpyh_index; }; + uint32_t get_glyph_index() const { return glyph_index; }; + void set_glyph_index(uint32_t p_glyph_index) { glyph_index = p_glyph_index; }; RID get_font() const { return font; }; void set_font(RID p_font) { font = p_font; }; @@ -89,4 +77,20 @@ public: void set_environment(Dictionary p_environment) { environment = p_environment; } }; +class RichTextEffect : public Resource { + GDCLASS(RichTextEffect, Resource); + OBJ_SAVE_TYPE(RichTextEffect); + +protected: + static void _bind_methods(); + + GDVIRTUAL1RC(bool, _process_custom_fx, Ref<CharFXTransform>) + +public: + Variant get_bbcode() const; + bool _process_effect_impl(Ref<class CharFXTransform> p_cfx); + + RichTextEffect(); +}; + #endif // RICH_TEXT_EFFECT_H diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp index 75c2da7ef9..aeadfd78ee 100644 --- a/scene/gui/rich_text_label.cpp +++ b/scene/gui/rich_text_label.cpp @@ -874,7 +874,7 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o charfx->visibility = visible; charfx->outline = true; charfx->font = frid; - charfx->glpyh_index = gl; + charfx->glyph_index = gl; charfx->offset = fx_offset; charfx->color = font_color; @@ -884,7 +884,7 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o fx_offset += charfx->offset; font_color = charfx->color; frid = charfx->font; - gl = charfx->glpyh_index; + gl = charfx->glyph_index; visible &= charfx->visibility; } } else if (item_fx->type == ITEM_SHAKE) { @@ -1026,7 +1026,7 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o charfx->visibility = visible; charfx->outline = false; charfx->font = frid; - charfx->glpyh_index = gl; + charfx->glyph_index = gl; charfx->offset = fx_offset; charfx->color = font_color; @@ -1036,7 +1036,7 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o fx_offset += charfx->offset; font_color = charfx->color; frid = charfx->font; - gl = charfx->glpyh_index; + gl = charfx->glyph_index; visible &= charfx->visibility; } } else if (item_fx->type == ITEM_SHAKE) { @@ -1451,7 +1451,7 @@ void RichTextLabel::_notification(int p_what) { Control::CursorShape RichTextLabel::get_cursor_shape(const Point2 &p_pos) const { if (!underline_meta) { - return CURSOR_ARROW; + return get_default_cursor_shape(); } if (selection.click_item) { @@ -1459,11 +1459,11 @@ Control::CursorShape RichTextLabel::get_cursor_shape(const Point2 &p_pos) const } if (main->first_invalid_line < main->lines.size()) { - return CURSOR_ARROW; //invalid + return get_default_cursor_shape(); //invalid } if (main->first_resized_line < main->lines.size()) { - return CURSOR_ARROW; //invalid + return get_default_cursor_shape(); //invalid } Item *item = nullptr; @@ -1474,10 +1474,10 @@ Control::CursorShape RichTextLabel::get_cursor_shape(const Point2 &p_pos) const return CURSOR_POINTING_HAND; } - return CURSOR_ARROW; + return get_default_cursor_shape(); } -void RichTextLabel::_gui_input(Ref<InputEvent> p_event) { +void RichTextLabel::gui_input(const Ref<InputEvent> &p_event) { ERR_FAIL_COND(p_event.is_null()); Ref<InputEventMouseButton> b = p_event; @@ -3946,24 +3946,15 @@ float RichTextLabel::get_percent_visible() const { return percent_visible; } -void RichTextLabel::set_effects(const Vector<Variant> &effects) { - custom_effects.clear(); - for (int i = 0; i < effects.size(); i++) { - Ref<RichTextEffect> effect = Ref<RichTextEffect>(effects[i]); - custom_effects.push_back(effect); - } - +void RichTextLabel::set_effects(Array p_effects) { + custom_effects = p_effects; if ((bbcode != "") && use_bbcode) { parse_bbcode(bbcode); } } -Vector<Variant> RichTextLabel::get_effects() { - Vector<Variant> r; - for (int i = 0; i < custom_effects.size(); i++) { - r.push_back(custom_effects[i]); - } - return r; +Array RichTextLabel::get_effects() { + return custom_effects; } void RichTextLabel::install_effect(const Variant effect) { @@ -3993,7 +3984,6 @@ void RichTextLabel::_validate_property(PropertyInfo &property) const { } void RichTextLabel::_bind_methods() { - ClassDB::bind_method(D_METHOD("_gui_input"), &RichTextLabel::_gui_input); ClassDB::bind_method(D_METHOD("get_text"), &RichTextLabel::get_text); ClassDB::bind_method(D_METHOD("add_text", "text"), &RichTextLabel::add_text); ClassDB::bind_method(D_METHOD("set_text", "text"), &RichTextLabel::set_text); @@ -4280,12 +4270,13 @@ void RichTextLabel::_draw_fbg_boxes(RID p_ci, RID p_rid, Vector2 line_off, Item Ref<RichTextEffect> RichTextLabel::_get_custom_effect_by_code(String p_bbcode_identifier) { for (int i = 0; i < custom_effects.size(); i++) { - if (!custom_effects[i].is_valid()) { + Ref<RichTextEffect> effect = custom_effects[i]; + if (!effect.is_valid()) { continue; } - if (custom_effects[i]->get_bbcode() == p_bbcode_identifier) { - return custom_effects[i]; + if (effect->get_bbcode() == p_bbcode_identifier) { + return effect; } } @@ -4362,7 +4353,7 @@ RichTextLabel::RichTextLabel() { current_frame = main; vscroll = memnew(VScrollBar); - add_child(vscroll); + add_child(vscroll, false, INTERNAL_MODE_FRONT); vscroll->set_drag_node(String("..")); vscroll->set_step(1); vscroll->set_anchor_and_offset(SIDE_TOP, ANCHOR_BEGIN, 0); diff --git a/scene/gui/rich_text_label.h b/scene/gui/rich_text_label.h index 28dfe74b08..f25a8bf193 100644 --- a/scene/gui/rich_text_label.h +++ b/scene/gui/rich_text_label.h @@ -363,7 +363,7 @@ private: ItemMeta *meta_hovering = nullptr; Variant current_meta; - Vector<Ref<RichTextEffect>> custom_effects; + Array custom_effects; void _invalidate_current_line(ItemFrame *p_frame); void _validate_line_caches(ItemFrame *p_frame); @@ -443,7 +443,7 @@ private: void _update_fx(ItemFrame *p_frame, double p_delta_time); void _scroll_changed(double); - void _gui_input(Ref<InputEvent> p_event); + virtual void gui_input(const Ref<InputEvent> &p_event) override; Item *_get_next_item(Item *p_item, bool p_free = false) const; Item *_get_prev_item(Item *p_item, bool p_free = false) const; @@ -577,8 +577,8 @@ public: void set_percent_visible(float p_percent); float get_percent_visible() const; - void set_effects(const Vector<Variant> &effects); - Vector<Variant> get_effects(); + void set_effects(Array p_effects); + Array get_effects(); void install_effect(const Variant effect); diff --git a/scene/gui/scroll_bar.cpp b/scene/gui/scroll_bar.cpp index ce04a0204b..08bcb0bdda 100644 --- a/scene/gui/scroll_bar.cpp +++ b/scene/gui/scroll_bar.cpp @@ -41,7 +41,7 @@ void ScrollBar::set_can_focus_by_default(bool p_can_focus) { focus_by_default = p_can_focus; } -void ScrollBar::_gui_input(Ref<InputEvent> p_event) { +void ScrollBar::gui_input(const Ref<InputEvent> &p_event) { ERR_FAIL_COND(p_event.is_null()); Ref<InputEventMouseMotion> m = p_event; @@ -597,7 +597,6 @@ bool ScrollBar::is_smooth_scroll_enabled() const { } void ScrollBar::_bind_methods() { - ClassDB::bind_method(D_METHOD("_gui_input"), &ScrollBar::_gui_input); ClassDB::bind_method(D_METHOD("set_custom_step", "step"), &ScrollBar::set_custom_step); ClassDB::bind_method(D_METHOD("get_custom_step"), &ScrollBar::get_custom_step); diff --git a/scene/gui/scroll_bar.h b/scene/gui/scroll_bar.h index 24b3b33e82..fbc035397f 100644 --- a/scene/gui/scroll_bar.h +++ b/scene/gui/scroll_bar.h @@ -86,7 +86,7 @@ class ScrollBar : public Range { void _drag_node_exit(); void _drag_node_input(const Ref<InputEvent> &p_input); - void _gui_input(Ref<InputEvent> p_event); + virtual void gui_input(const Ref<InputEvent> &p_event) override; protected: void _notification(int p_what); diff --git a/scene/gui/scroll_container.cpp b/scene/gui/scroll_container.cpp index eb5fc924da..0c051f61e2 100644 --- a/scene/gui/scroll_container.cpp +++ b/scene/gui/scroll_container.cpp @@ -83,7 +83,7 @@ void ScrollContainer::_cancel_drag() { } } -void ScrollContainer::_gui_input(const Ref<InputEvent> &p_gui_input) { +void ScrollContainer::gui_input(const Ref<InputEvent> &p_gui_input) { ERR_FAIL_COND(p_gui_input.is_null()); double prev_v_scroll = v_scroll->get_value(); @@ -228,9 +228,6 @@ void ScrollContainer::_update_scrollbar_position() { v_scroll->set_anchor_and_offset(SIDE_TOP, ANCHOR_BEGIN, 0); v_scroll->set_anchor_and_offset(SIDE_BOTTOM, ANCHOR_END, 0); - h_scroll->raise(); - v_scroll->raise(); - _updating_scrollbars = false; } @@ -568,7 +565,6 @@ VScrollBar *ScrollContainer::get_v_scrollbar() { } void ScrollContainer::_bind_methods() { - ClassDB::bind_method(D_METHOD("_gui_input"), &ScrollContainer::_gui_input); ClassDB::bind_method(D_METHOD("_update_scrollbar_position"), &ScrollContainer::_update_scrollbar_position); ClassDB::bind_method(D_METHOD("set_h_scroll", "value"), &ScrollContainer::set_h_scroll); @@ -619,12 +615,12 @@ void ScrollContainer::_bind_methods() { ScrollContainer::ScrollContainer() { h_scroll = memnew(HScrollBar); h_scroll->set_name("_h_scroll"); - add_child(h_scroll); + add_child(h_scroll, false, INTERNAL_MODE_BACK); h_scroll->connect("value_changed", callable_mp(this, &ScrollContainer::_scroll_moved)); v_scroll = memnew(VScrollBar); v_scroll->set_name("_v_scroll"); - add_child(v_scroll); + add_child(v_scroll, false, INTERNAL_MODE_BACK); v_scroll->connect("value_changed", callable_mp(this, &ScrollContainer::_scroll_moved)); deadzone = GLOBAL_GET("gui/common/default_scroll_deadzone"); diff --git a/scene/gui/scroll_container.h b/scene/gui/scroll_container.h index 4733fdabca..9f4ec558dc 100644 --- a/scene/gui/scroll_container.h +++ b/scene/gui/scroll_container.h @@ -68,7 +68,7 @@ class ScrollContainer : public Container { protected: Size2 get_minimum_size() const override; - void _gui_input(const Ref<InputEvent> &p_gui_input); + virtual void gui_input(const Ref<InputEvent> &p_gui_input) override; void _gui_focus_changed(Control *p_control); void _update_dimensions(); void _notification(int p_what); diff --git a/scene/gui/shortcut.cpp b/scene/gui/shortcut.cpp deleted file mode 100644 index d0cb08724e..0000000000 --- a/scene/gui/shortcut.cpp +++ /dev/null @@ -1,76 +0,0 @@ -/*************************************************************************/ -/* shortcut.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "shortcut.h" -#include "core/os/keyboard.h" - -void Shortcut::set_event(const Ref<InputEvent> &p_event) { - ERR_FAIL_COND_MSG(Object::cast_to<InputEventShortcut>(*p_event), "Cannot set a shortcut event to an instance of InputEventShortcut."); - event = p_event; - emit_changed(); -} - -Ref<InputEvent> Shortcut::get_event() const { - return event; -} - -bool Shortcut::matches_event(const Ref<InputEvent> &p_event) const { - Ref<InputEventShortcut> ies = p_event; - if (ies.is_valid()) { - if (ies->get_shortcut().ptr() == this) { - return true; - } - } - return event.is_valid() && event->is_match(p_event, true); -} - -String Shortcut::get_as_text() const { - if (event.is_valid()) { - return event->as_text(); - } else { - return "None"; - } -} - -bool Shortcut::has_valid_event() const { - return event.is_valid(); -} - -void Shortcut::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_event", "event"), &Shortcut::set_event); - ClassDB::bind_method(D_METHOD("get_event"), &Shortcut::get_event); - - ClassDB::bind_method(D_METHOD("has_valid_event"), &Shortcut::has_valid_event); - - ClassDB::bind_method(D_METHOD("matches_event", "event"), &Shortcut::matches_event); - ClassDB::bind_method(D_METHOD("get_as_text"), &Shortcut::get_as_text); - - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent"), "set_event", "get_event"); -} diff --git a/scene/gui/shortcut.h b/scene/gui/shortcut.h deleted file mode 100644 index 249dd1971f..0000000000 --- a/scene/gui/shortcut.h +++ /dev/null @@ -1,54 +0,0 @@ -/*************************************************************************/ -/* shortcut.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifndef SHORTCUT_H -#define SHORTCUT_H - -#include "core/input/input_event.h" -#include "core/io/resource.h" - -class Shortcut : public Resource { - GDCLASS(Shortcut, Resource); - - Ref<InputEvent> event; - -protected: - static void _bind_methods(); - -public: - void set_event(const Ref<InputEvent> &p_shortcut); - Ref<InputEvent> get_event() const; - bool matches_event(const Ref<InputEvent> &p_event) const; - bool has_valid_event() const; - - String get_as_text() const; -}; - -#endif // SHORTCUT_H diff --git a/scene/gui/slider.cpp b/scene/gui/slider.cpp index 61b5325175..352f87954e 100644 --- a/scene/gui/slider.cpp +++ b/scene/gui/slider.cpp @@ -45,7 +45,7 @@ Size2 Slider::get_minimum_size() const { } } -void Slider::_gui_input(Ref<InputEvent> p_event) { +void Slider::gui_input(const Ref<InputEvent> &p_event) { ERR_FAIL_COND(p_event.is_null()); if (!editable) { @@ -253,7 +253,6 @@ bool Slider::is_scrollable() const { } void Slider::_bind_methods() { - ClassDB::bind_method(D_METHOD("_gui_input"), &Slider::_gui_input); ClassDB::bind_method(D_METHOD("set_ticks", "count"), &Slider::set_ticks); ClassDB::bind_method(D_METHOD("get_ticks"), &Slider::get_ticks); diff --git a/scene/gui/slider.h b/scene/gui/slider.h index 65a4036cd1..46fa08bbf0 100644 --- a/scene/gui/slider.h +++ b/scene/gui/slider.h @@ -50,7 +50,7 @@ class Slider : public Range { bool scrollable = true; protected: - void _gui_input(Ref<InputEvent> p_event); + virtual void gui_input(const Ref<InputEvent> &p_event) override; void _notification(int p_what); static void _bind_methods(); bool ticks_on_borders = false; diff --git a/scene/gui/spin_box.cpp b/scene/gui/spin_box.cpp index 3f0368a4e2..1074d0d8a0 100644 --- a/scene/gui/spin_box.cpp +++ b/scene/gui/spin_box.cpp @@ -99,7 +99,7 @@ void SpinBox::_release_mouse() { } } -void SpinBox::_gui_input(const Ref<InputEvent> &p_event) { +void SpinBox::gui_input(const Ref<InputEvent> &p_event) { ERR_FAIL_COND(p_event.is_null()); if (!is_editable()) { @@ -258,7 +258,7 @@ void SpinBox::apply() { void SpinBox::_bind_methods() { //ClassDB::bind_method(D_METHOD("_value_changed"),&SpinBox::_value_changed); - ClassDB::bind_method(D_METHOD("_gui_input"), &SpinBox::_gui_input); + ClassDB::bind_method(D_METHOD("set_align", "align"), &SpinBox::set_align); ClassDB::bind_method(D_METHOD("get_align"), &SpinBox::get_align); ClassDB::bind_method(D_METHOD("set_suffix", "suffix"), &SpinBox::set_suffix); @@ -278,7 +278,7 @@ void SpinBox::_bind_methods() { SpinBox::SpinBox() { line_edit = memnew(LineEdit); - add_child(line_edit); + add_child(line_edit, false, INTERNAL_MODE_FRONT); line_edit->set_anchors_and_offsets_preset(Control::PRESET_WIDE); line_edit->set_mouse_filter(MOUSE_FILTER_PASS); @@ -291,5 +291,5 @@ SpinBox::SpinBox() { range_click_timer = memnew(Timer); range_click_timer->connect("timeout", callable_mp(this, &SpinBox::_range_click_timeout)); - add_child(range_click_timer); + add_child(range_click_timer, false, INTERNAL_MODE_FRONT); } diff --git a/scene/gui/spin_box.h b/scene/gui/spin_box.h index fb10379296..9ec3885f1f 100644 --- a/scene/gui/spin_box.h +++ b/scene/gui/spin_box.h @@ -65,7 +65,7 @@ class SpinBox : public Range { inline void _adjust_width_for_icon(const Ref<Texture2D> &icon); protected: - void _gui_input(const Ref<InputEvent> &p_event); + virtual void gui_input(const Ref<InputEvent> &p_event) override; void _notification(int p_what); diff --git a/scene/gui/split_container.cpp b/scene/gui/split_container.cpp index 3114e5b7c0..4736a1ad37 100644 --- a/scene/gui/split_container.cpp +++ b/scene/gui/split_container.cpp @@ -206,7 +206,7 @@ void SplitContainer::_notification(int p_what) { } } -void SplitContainer::_gui_input(const Ref<InputEvent> &p_event) { +void SplitContainer::gui_input(const Ref<InputEvent> &p_event) { ERR_FAIL_COND(p_event.is_null()); if (collapsed || !_getch(0) || !_getch(1) || dragger_visibility != DRAGGER_VISIBLE) { @@ -337,8 +337,6 @@ bool SplitContainer::is_collapsed() const { } void SplitContainer::_bind_methods() { - ClassDB::bind_method(D_METHOD("_gui_input"), &SplitContainer::_gui_input); - ClassDB::bind_method(D_METHOD("set_split_offset", "offset"), &SplitContainer::set_split_offset); ClassDB::bind_method(D_METHOD("get_split_offset"), &SplitContainer::get_split_offset); ClassDB::bind_method(D_METHOD("clamp_split_offset"), &SplitContainer::clamp_split_offset); diff --git a/scene/gui/split_container.h b/scene/gui/split_container.h index 6cb94d6ecf..47fd30a122 100644 --- a/scene/gui/split_container.h +++ b/scene/gui/split_container.h @@ -60,7 +60,7 @@ private: void _resort(); protected: - void _gui_input(const Ref<InputEvent> &p_event); + virtual void gui_input(const Ref<InputEvent> &p_event) override; void _notification(int p_what); static void _bind_methods(); diff --git a/scene/gui/subviewport_container.cpp b/scene/gui/subviewport_container.cpp index bfc7e29f9c..53ea32e1b7 100644 --- a/scene/gui/subviewport_container.cpp +++ b/scene/gui/subviewport_container.cpp @@ -139,7 +139,7 @@ void SubViewportContainer::_notification(int p_what) { } } -void SubViewportContainer::_input(const Ref<InputEvent> &p_event) { +void SubViewportContainer::input(const Ref<InputEvent> &p_event) { ERR_FAIL_COND(p_event.is_null()); if (Engine::get_singleton()->is_editor_hint()) { @@ -162,11 +162,11 @@ void SubViewportContainer::_input(const Ref<InputEvent> &p_event) { continue; } - c->input(ev); + c->push_input(ev); } } -void SubViewportContainer::_unhandled_input(const Ref<InputEvent> &p_event) { +void SubViewportContainer::unhandled_input(const Ref<InputEvent> &p_event) { ERR_FAIL_COND(p_event.is_null()); if (Engine::get_singleton()->is_editor_hint()) { @@ -189,13 +189,11 @@ void SubViewportContainer::_unhandled_input(const Ref<InputEvent> &p_event) { continue; } - c->unhandled_input(ev); + c->push_unhandled_input(ev); } } void SubViewportContainer::_bind_methods() { - ClassDB::bind_method(D_METHOD("_unhandled_input", "event"), &SubViewportContainer::_unhandled_input); - ClassDB::bind_method(D_METHOD("_input", "event"), &SubViewportContainer::_input); ClassDB::bind_method(D_METHOD("set_stretch", "enable"), &SubViewportContainer::set_stretch); ClassDB::bind_method(D_METHOD("is_stretch_enabled"), &SubViewportContainer::is_stretch_enabled); diff --git a/scene/gui/subviewport_container.h b/scene/gui/subviewport_container.h index 77cf4c16b3..7853f1590e 100644 --- a/scene/gui/subviewport_container.h +++ b/scene/gui/subviewport_container.h @@ -47,8 +47,8 @@ public: void set_stretch(bool p_enable); bool is_stretch_enabled() const; - void _input(const Ref<InputEvent> &p_event); - void _unhandled_input(const Ref<InputEvent> &p_event); + virtual void input(const Ref<InputEvent> &p_event) override; + virtual void unhandled_input(const Ref<InputEvent> &p_event) override; void set_stretch_shrink(int p_shrink); int get_stretch_shrink() const; diff --git a/scene/gui/tab_container.cpp b/scene/gui/tab_container.cpp index 53a2fe4d93..137ce7e96f 100644 --- a/scene/gui/tab_container.cpp +++ b/scene/gui/tab_container.cpp @@ -71,7 +71,7 @@ int TabContainer::_get_top_margin() const { return tab_height + content_height; } -void TabContainer::_gui_input(const Ref<InputEvent> &p_event) { +void TabContainer::gui_input(const Ref<InputEvent> &p_event) { ERR_FAIL_COND(p_event.is_null()); Ref<InputEventMouseButton> mb = p_event; @@ -434,14 +434,14 @@ void TabContainer::_notification(int p_what) { } int tab_width = tab_widths[i]; - if (get_tab_disabled(index)) { + if (index == current) { + x_current = x; + } else if (get_tab_disabled(index)) { if (rtl) { _draw_tab(tab_disabled, font_disabled_color, index, size.width - (tabs_ofs_cache + x) - tab_width); } else { _draw_tab(tab_disabled, font_disabled_color, index, tabs_ofs_cache + x); } - } else if (index == current) { - x_current = x; } else { if (rtl) { _draw_tab(tab_unselected, font_unselected_color, index, size.width - (tabs_ofs_cache + x) - tab_width); @@ -459,12 +459,13 @@ void TabContainer::_notification(int p_what) { panel->draw(canvas, Rect2(0, header_height, size.width, size.height - header_height)); } - // Draw selected tab in front. only draw selected tab when it's in visible range. + // Draw selected tab in front. Only draw selected tab when it's in visible range. if (tabs.size() > 0 && current - first_tab_cache < tab_widths.size() && current >= first_tab_cache) { + Ref<StyleBox> current_style_box = get_tab_disabled(current) ? tab_disabled : tab_selected; if (rtl) { - _draw_tab(tab_selected, font_selected_color, current, size.width - (tabs_ofs_cache + x_current) - tab_widths[current]); + _draw_tab(current_style_box, font_selected_color, current, size.width - (tabs_ofs_cache + x_current) - tab_widths[current]); } else { - _draw_tab(tab_selected, font_selected_color, current, tabs_ofs_cache + x_current); + _draw_tab(current_style_box, font_selected_color, current, tabs_ofs_cache + x_current); } } @@ -640,8 +641,8 @@ void TabContainer::_on_mouse_exited() { int TabContainer::_get_tab_width(int p_index) const { ERR_FAIL_INDEX_V(p_index, get_tab_count(), 0); - Control *control = Object::cast_to<Control>(_get_tabs()[p_index]); - if (!control || control->is_set_as_top_level() || get_tab_hidden(p_index)) { + Control *control = get_tab_control(p_index); + if (!control || get_tab_hidden(p_index)) { return 0; } @@ -905,7 +906,7 @@ void TabContainer::drop_data(const Point2 &p_point, const Variant &p_data) { if (from_tabc && from_tabc->get_tabs_rearrange_group() == get_tabs_rearrange_group()) { Control *moving_tabc = from_tabc->get_tab_control(tab_from_id); from_tabc->remove_child(moving_tabc); - add_child(moving_tabc); + add_child(moving_tabc, false, INTERNAL_MODE_FRONT); if (hover_now < 0) { hover_now = get_tab_count() - 1; } @@ -1193,7 +1194,6 @@ bool TabContainer::get_use_hidden_tabs_for_min_size() const { } void TabContainer::_bind_methods() { - ClassDB::bind_method(D_METHOD("_gui_input"), &TabContainer::_gui_input); ClassDB::bind_method(D_METHOD("get_tab_count"), &TabContainer::get_tab_count); ClassDB::bind_method(D_METHOD("set_current_tab", "tab_idx"), &TabContainer::set_current_tab); ClassDB::bind_method(D_METHOD("get_current_tab"), &TabContainer::get_current_tab); @@ -1212,6 +1212,7 @@ void TabContainer::_bind_methods() { ClassDB::bind_method(D_METHOD("get_tab_icon", "tab_idx"), &TabContainer::get_tab_icon); ClassDB::bind_method(D_METHOD("set_tab_disabled", "tab_idx", "disabled"), &TabContainer::set_tab_disabled); ClassDB::bind_method(D_METHOD("get_tab_disabled", "tab_idx"), &TabContainer::get_tab_disabled); + ClassDB::bind_method(D_METHOD("get_tab_idx_at_point", "point"), &TabContainer::get_tab_idx_at_point); ClassDB::bind_method(D_METHOD("set_popup", "popup"), &TabContainer::set_popup); ClassDB::bind_method(D_METHOD("get_popup"), &TabContainer::get_popup); ClassDB::bind_method(D_METHOD("set_drag_to_rearrange_enabled", "enabled"), &TabContainer::set_drag_to_rearrange_enabled); diff --git a/scene/gui/tab_container.h b/scene/gui/tab_container.h index 35f18eff8e..fe96df25e8 100644 --- a/scene/gui/tab_container.h +++ b/scene/gui/tab_container.h @@ -76,7 +76,7 @@ private: protected: void _child_renamed_callback(); - void _gui_input(const Ref<InputEvent> &p_event); + virtual void gui_input(const Ref<InputEvent> &p_event) override; void _notification(int p_what); virtual void add_child_notify(Node *p_child) override; virtual void move_child_notify(Node *p_child) override; diff --git a/scene/gui/tabs.cpp b/scene/gui/tabs.cpp index 103860ad78..3ca2d1c1e9 100644 --- a/scene/gui/tabs.cpp +++ b/scene/gui/tabs.cpp @@ -90,7 +90,7 @@ Size2 Tabs::get_minimum_size() const { return ms; } -void Tabs::_gui_input(const Ref<InputEvent> &p_event) { +void Tabs::gui_input(const Ref<InputEvent> &p_event) { ERR_FAIL_COND(p_event.is_null()); Ref<InputEventMouseMotion> mm = p_event; @@ -1107,7 +1107,6 @@ bool Tabs::get_select_with_rmb() const { } void Tabs::_bind_methods() { - ClassDB::bind_method(D_METHOD("_gui_input"), &Tabs::_gui_input); ClassDB::bind_method(D_METHOD("_update_hover"), &Tabs::_update_hover); ClassDB::bind_method(D_METHOD("get_tab_count"), &Tabs::get_tab_count); ClassDB::bind_method(D_METHOD("set_current_tab", "tab_idx"), &Tabs::set_current_tab); diff --git a/scene/gui/tabs.h b/scene/gui/tabs.h index 61c9a5d96a..b044453803 100644 --- a/scene/gui/tabs.h +++ b/scene/gui/tabs.h @@ -112,7 +112,7 @@ private: void _shape(int p_tab); protected: - void _gui_input(const Ref<InputEvent> &p_event); + virtual void gui_input(const Ref<InputEvent> &p_event) override; void _notification(int p_what); static void _bind_methods(); diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index 87f06445ac..b9e9a4d450 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -557,13 +557,25 @@ void TextEdit::_notification(int p_what) { } int minimap_draw_amount = minimap_visible_lines + get_line_wrap_count(minimap_line + 1); - // draw the minimap - Color viewport_color = (background_color.get_v() < 0.5) ? Color(1, 1, 1, 0.1) : Color(0, 0, 0, 0.1); + // Draw the minimap. + + // Add visual feedback when dragging or hovering the the visible area rectangle. + float viewport_alpha; + if (dragging_minimap) { + viewport_alpha = 0.25; + } else if (hovering_minimap) { + viewport_alpha = 0.175; + } else { + viewport_alpha = 0.1; + } + + const Color viewport_color = (background_color.get_v() < 0.5) ? Color(1, 1, 1, viewport_alpha) : Color(0, 0, 0, viewport_alpha); if (rtl) { RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(size.width - (xmargin_end + 2) - minimap_width, viewport_offset_y, minimap_width, viewport_height), viewport_color); } else { RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2((xmargin_end + 2), viewport_offset_y, minimap_width, viewport_height), viewport_color); } + for (int i = 0; i < minimap_draw_amount; i++) { minimap_line++; @@ -888,7 +900,7 @@ void TextEdit::_notification(int p_what) { // Draw line. RID rid = ldata->get_line_rid(line_wrap_index); - float text_height = TS->shaped_text_get_size(rid).y + font->get_spacing(Font::SPACING_TOP) + font->get_spacing(Font::SPACING_BOTTOM); + float text_height = TS->shaped_text_get_size(rid).y + font->get_spacing(TextServer::SPACING_TOP) + font->get_spacing(TextServer::SPACING_BOTTOM); if (rtl) { char_margin = size.width - char_margin - TS->shaped_text_get_size(rid).x; @@ -1305,7 +1317,7 @@ void TextEdit::_notification(int p_what) { } } -void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { +void TextEdit::gui_input(const Ref<InputEvent> &p_gui_input) { ERR_FAIL_COND(p_gui_input.is_null()); double prev_v_scroll = v_scroll->get_value(); @@ -1549,6 +1561,10 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { } } + if (draw_minimap && !dragging_selection) { + _update_minimap_hover(); + } + if (v_scroll->get_value() != prev_v_scroll || h_scroll->get_value() != prev_h_scroll) { accept_event(); // Accept event if scroll changed. } @@ -2150,7 +2166,6 @@ void TextEdit::_delete(bool p_word, bool p_all_to_right) { next_column = column; } else { // Delete one character - next_column = caret.column < curline_len ? (caret.column + 1) : 0; if (caret_mid_grapheme_enabled) { next_column = caret.column < curline_len ? (caret.column + 1) : 0; } else { @@ -2768,48 +2783,38 @@ Point2i TextEdit::get_next_visible_line_index_offset_from(int p_line_from, int p // Overridable actions void TextEdit::handle_unicode_input(const uint32_t p_unicode) { - ScriptInstance *si = get_script_instance(); - if (si && si->has_method("_handle_unicode_input")) { - si->call("_handle_unicode_input", p_unicode); + if (GDVIRTUAL_CALL(_handle_unicode_input, p_unicode)) { return; } - _handle_unicode_input(p_unicode); + _handle_unicode_input_internal(p_unicode); } void TextEdit::backspace() { - ScriptInstance *si = get_script_instance(); - if (si && si->has_method("_backspace")) { - si->call("_backspace"); + if (GDVIRTUAL_CALL(_backspace)) { return; } - _backspace(); + _backspace_internal(); } void TextEdit::cut() { - ScriptInstance *si = get_script_instance(); - if (si && si->has_method("_cut")) { - si->call("_cut"); + if (GDVIRTUAL_CALL(_cut)) { return; } - _cut(); + _cut_internal(); } void TextEdit::copy() { - ScriptInstance *si = get_script_instance(); - if (si && si->has_method("_copy")) { - si->call("_copy"); + if (GDVIRTUAL_CALL(_copy)) { return; } - _copy(); + _copy_internal(); } void TextEdit::paste() { - ScriptInstance *si = get_script_instance(); - if (si && si->has_method("_paste")) { - si->call("_paste"); + if (GDVIRTUAL_CALL(_paste)) { return; } - _paste(); + _paste_internal(); } // Context menu. @@ -4377,7 +4382,7 @@ bool TextEdit::is_drawing_spaces() const { void TextEdit::_bind_methods() { /*Internal. */ - ClassDB::bind_method(D_METHOD("_gui_input"), &TextEdit::_gui_input); + ClassDB::bind_method(D_METHOD("_text_changed_emit"), &TextEdit::_text_changed_emit); /* Text */ @@ -4452,12 +4457,11 @@ void TextEdit::_bind_methods() { ClassDB::bind_method(D_METHOD("copy"), &TextEdit::copy); ClassDB::bind_method(D_METHOD("paste"), &TextEdit::paste); - BIND_VMETHOD(MethodInfo("_handle_unicode_input", PropertyInfo(Variant::INT, "unicode"))) - BIND_VMETHOD(MethodInfo("_backspace")); - - BIND_VMETHOD(MethodInfo("_cut")); - BIND_VMETHOD(MethodInfo("_copy")); - BIND_VMETHOD(MethodInfo("_paste")); + GDVIRTUAL_BIND(_handle_unicode_input, "unicode_char") + GDVIRTUAL_BIND(_backspace) + GDVIRTUAL_BIND(_cut) + GDVIRTUAL_BIND(_copy) + GDVIRTUAL_BIND(_paste) // Context Menu BIND_ENUM_CONSTANT(MENU_CUT); @@ -4884,7 +4888,7 @@ void TextEdit::_set_symbol_lookup_word(const String &p_symbol) { /* Text manipulation */ // Overridable actions -void TextEdit::_handle_unicode_input(const uint32_t p_unicode) { +void TextEdit::_handle_unicode_input_internal(const uint32_t p_unicode) { if (!editable) { return; } @@ -4915,7 +4919,7 @@ void TextEdit::_handle_unicode_input(const uint32_t p_unicode) { } } -void TextEdit::_backspace() { +void TextEdit::_backspace_internal() { if (!editable) { return; } @@ -4946,7 +4950,7 @@ void TextEdit::_backspace() { set_caret_column(prev_column); } -void TextEdit::_cut() { +void TextEdit::_cut_internal() { if (!editable) { return; } @@ -4976,7 +4980,7 @@ void TextEdit::_cut() { cut_copy_line = clipboard; } -void TextEdit::_copy() { +void TextEdit::_copy_internal() { if (has_selection()) { DisplayServer::get_singleton()->clipboard_set(get_selected_text()); cut_copy_line = ""; @@ -4991,7 +4995,7 @@ void TextEdit::_copy() { } } -void TextEdit::_paste() { +void TextEdit::_paste_internal() { if (!editable) { return; } @@ -5016,7 +5020,7 @@ void TextEdit::_paste() { void TextEdit::_generate_context_menu() { if (!menu) { menu = memnew(PopupMenu); - add_child(menu); + add_child(menu, false, INTERNAL_MODE_FRONT); menu_dir = memnew(PopupMenu); menu_dir->set_name("DirMenu"); @@ -5024,7 +5028,7 @@ void TextEdit::_generate_context_menu() { menu_dir->add_radio_check_item(RTR("Auto-detect direction"), MENU_DIR_AUTO); menu_dir->add_radio_check_item(RTR("Left-to-right"), MENU_DIR_LTR); menu_dir->add_radio_check_item(RTR("Right-to-left"), MENU_DIR_RTL); - menu->add_child(menu_dir); + menu->add_child(menu_dir, false, INTERNAL_MODE_FRONT); menu_ctl = memnew(PopupMenu); menu_ctl->set_name("CTLMenu"); @@ -5046,7 +5050,7 @@ void TextEdit::_generate_context_menu() { menu_ctl->add_item(RTR("Zero width non-joiner (ZWNJ)"), MENU_INSERT_ZWNJ); menu_ctl->add_item(RTR("Word joiner (WJ)"), MENU_INSERT_WJ); menu_ctl->add_item(RTR("Soft hyphen (SHY)"), MENU_INSERT_SHY); - menu->add_child(menu_ctl); + menu->add_child(menu_ctl, false, INTERNAL_MODE_FRONT); menu->connect("id_pressed", callable_mp(this, &TextEdit::menu_option)); menu_dir->connect("id_pressed", callable_mp(this, &TextEdit::menu_option)); @@ -5656,6 +5660,33 @@ void TextEdit::_scroll_lines_down() { } // Minimap + +void TextEdit::_update_minimap_hover() { + const Point2 mp = get_local_mouse_pos(); + const int xmargin_end = get_size().width - style_normal->get_margin(SIDE_RIGHT); + + const bool hovering_sidebar = mp.x > xmargin_end - minimap_width && mp.x < xmargin_end; + if (!hovering_sidebar) { + if (hovering_minimap) { + // Only redraw if the hovering status changed. + hovering_minimap = false; + update(); + } + + // Return early to avoid running the operations below when not needed. + return; + } + + const int row = get_minimap_line_at_pos(Point2i(mp.x, mp.y)); + + const bool new_hovering_minimap = row >= get_first_visible_line() && row <= get_last_full_visible_line(); + if (new_hovering_minimap != hovering_minimap) { + // Only redraw if the hovering status changed. + hovering_minimap = new_hovering_minimap; + update(); + } +} + void TextEdit::_update_minimap_click() { Point2 mp = get_local_mouse_pos(); @@ -5960,8 +5991,8 @@ TextEdit::TextEdit() { h_scroll = memnew(HScrollBar); v_scroll = memnew(VScrollBar); - add_child(h_scroll); - add_child(v_scroll); + add_child(h_scroll, false, INTERNAL_MODE_FRONT); + add_child(v_scroll, false, INTERNAL_MODE_FRONT); h_scroll->connect("value_changed", callable_mp(this, &TextEdit::_scroll_moved)); v_scroll->connect("value_changed", callable_mp(this, &TextEdit::_scroll_moved)); @@ -5970,19 +6001,19 @@ TextEdit::TextEdit() { /* Caret. */ caret_blink_timer = memnew(Timer); - add_child(caret_blink_timer); + add_child(caret_blink_timer, false, INTERNAL_MODE_FRONT); caret_blink_timer->set_wait_time(0.65); caret_blink_timer->connect("timeout", callable_mp(this, &TextEdit::_toggle_draw_caret)); set_caret_blink_enabled(false); /* Selection. */ click_select_held = memnew(Timer); - add_child(click_select_held); + add_child(click_select_held, false, INTERNAL_MODE_FRONT); click_select_held->set_wait_time(0.05); click_select_held->connect("timeout", callable_mp(this, &TextEdit::_click_selection_held)); idle_detect = memnew(Timer); - add_child(idle_detect); + add_child(idle_detect, false, INTERNAL_MODE_FRONT); idle_detect->set_one_shot(true); idle_detect->set_wait_time(GLOBAL_GET("gui/timers/text_edit_idle_detect_sec")); idle_detect->connect("timeout", callable_mp(this, &TextEdit::_push_current_op)); diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h index 69468978ab..07999c2442 100644 --- a/scene/gui/text_edit.h +++ b/scene/gui/text_edit.h @@ -446,12 +446,14 @@ private: // minimap scroll bool minimap_clicked = false; + bool hovering_minimap = false; bool dragging_minimap = false; bool can_drag_minimap = false; double minimap_scroll_ratio = 0.0; double minimap_scroll_click_pos = 0.0; + void _update_minimap_hover(); void _update_minimap_click(); void _update_minimap_drag(); @@ -528,7 +530,7 @@ private: protected: void _notification(int p_what); - virtual void _gui_input(const Ref<InputEvent> &p_gui_input); + virtual void gui_input(const Ref<InputEvent> &p_gui_input) override; static void _bind_methods(); @@ -562,12 +564,18 @@ protected: /* Text manipulation */ // Overridable actions - virtual void _handle_unicode_input(const uint32_t p_unicode); - virtual void _backspace(); - - virtual void _cut(); - virtual void _copy(); - virtual void _paste(); + virtual void _handle_unicode_input_internal(const uint32_t p_unicode); + virtual void _backspace_internal(); + + virtual void _cut_internal(); + virtual void _copy_internal(); + virtual void _paste_internal(); + + GDVIRTUAL1(_handle_unicode_input, int) + GDVIRTUAL0(_backspace) + GDVIRTUAL0(_cut) + GDVIRTUAL0(_copy) + GDVIRTUAL0(_paste) public: /* General overrides. */ diff --git a/scene/gui/texture_progress_bar.cpp b/scene/gui/texture_progress_bar.cpp index 5e5dec3579..286f01ee33 100644 --- a/scene/gui/texture_progress_bar.cpp +++ b/scene/gui/texture_progress_bar.cpp @@ -100,6 +100,15 @@ Ref<Texture2D> TextureProgressBar::get_progress_texture() const { return progress; } +void TextureProgressBar::set_progress_offset(Point2 p_offset) { + progress_offset = p_offset; + update(); +} + +Point2 TextureProgressBar::get_progress_offset() const { + return progress_offset; +} + void TextureProgressBar::set_tint_under(const Color &p_tint) { tint_under = p_tint; update(); @@ -360,6 +369,9 @@ void TextureProgressBar::draw_nine_patch_stretched(const Ref<Texture2D> &p_textu } } + if (p_texture == progress) { + dst_rect.position += progress_offset; + } p_texture->get_rect_region(dst_rect, src_rect, dst_rect, src_rect); RID ci = get_canvas_item(); @@ -403,20 +415,24 @@ void TextureProgressBar::_notification(int p_what) { Size2 s = progress->get_size(); switch (mode) { case FILL_LEFT_TO_RIGHT: { - Rect2 region = Rect2(Point2(), Size2(s.x * get_as_ratio(), s.y)); - draw_texture_rect_region(progress, region, region, tint_progress); + Rect2 region = Rect2(progress_offset, Size2(s.x * get_as_ratio(), s.y)); + Rect2 source = Rect2(Point2(), Size2(s.x * get_as_ratio(), s.y)); + draw_texture_rect_region(progress, region, source, tint_progress); } break; case FILL_RIGHT_TO_LEFT: { - Rect2 region = Rect2(Point2(s.x - s.x * get_as_ratio(), 0), Size2(s.x * get_as_ratio(), s.y)); - draw_texture_rect_region(progress, region, region, tint_progress); + Rect2 region = Rect2(progress_offset + Point2(s.x - s.x * get_as_ratio(), 0), Size2(s.x * get_as_ratio(), s.y)); + Rect2 source = Rect2(Point2(s.x - s.x * get_as_ratio(), 0), Size2(s.x * get_as_ratio(), s.y)); + draw_texture_rect_region(progress, region, source, tint_progress); } break; case FILL_TOP_TO_BOTTOM: { - Rect2 region = Rect2(Point2(), Size2(s.x, s.y * get_as_ratio())); - draw_texture_rect_region(progress, region, region, tint_progress); + Rect2 region = Rect2(progress_offset + Point2(), Size2(s.x, s.y * get_as_ratio())); + Rect2 source = Rect2(Point2(), Size2(s.x, s.y * get_as_ratio())); + draw_texture_rect_region(progress, region, source, tint_progress); } break; case FILL_BOTTOM_TO_TOP: { - Rect2 region = Rect2(Point2(0, s.y - s.y * get_as_ratio()), Size2(s.x, s.y * get_as_ratio())); - draw_texture_rect_region(progress, region, region, tint_progress); + Rect2 region = Rect2(progress_offset + Point2(0, s.y - s.y * get_as_ratio()), Size2(s.x, s.y * get_as_ratio())); + Rect2 source = Rect2(Point2(0, s.y - s.y * get_as_ratio()), Size2(s.x, s.y * get_as_ratio())); + draw_texture_rect_region(progress, region, source, tint_progress); } break; case FILL_CLOCKWISE: case FILL_COUNTER_CLOCKWISE: @@ -427,8 +443,9 @@ void TextureProgressBar::_notification(int p_what) { float val = get_as_ratio() * rad_max_degrees / 360; if (val == 1) { - Rect2 region = Rect2(Point2(), s); - draw_texture_rect(progress, region, false, tint_progress); + Rect2 region = Rect2(progress_offset, s); + Rect2 source = Rect2(Point2(), s); + draw_texture_rect_region(progress, region, source, tint_progress); } else if (val != 0) { Array pts; float direction = mode == FILL_COUNTER_CLOCKWISE ? -1 : 1; @@ -454,14 +471,14 @@ void TextureProgressBar::_notification(int p_what) { Vector<Point2> uvs; Vector<Point2> points; uvs.push_back(get_relative_center()); - points.push_back(Point2(s.x * get_relative_center().x, s.y * get_relative_center().y)); + points.push_back(progress_offset + Point2(s.x * get_relative_center().x, s.y * get_relative_center().y)); for (int i = 0; i < pts.size(); i++) { Point2 uv = unit_val_to_uv(pts[i]); if (uvs.find(uv) >= 0) { continue; } uvs.push_back(uv); - points.push_back(Point2(uv.x * s.x, uv.y * s.y)); + points.push_back(progress_offset + Point2(uv.x * s.x, uv.y * s.y)); } Vector<Color> colors; colors.push_back(tint_progress); @@ -484,17 +501,19 @@ void TextureProgressBar::_notification(int p_what) { } } break; case FILL_BILINEAR_LEFT_AND_RIGHT: { - Rect2 region = Rect2(Point2(s.x / 2 - s.x * get_as_ratio() / 2, 0), Size2(s.x * get_as_ratio(), s.y)); - draw_texture_rect_region(progress, region, region, tint_progress); + Rect2 region = Rect2(progress_offset + Point2(s.x / 2 - s.x * get_as_ratio() / 2, 0), Size2(s.x * get_as_ratio(), s.y)); + Rect2 source = Rect2(Point2(s.x / 2 - s.x * get_as_ratio() / 2, 0), Size2(s.x * get_as_ratio(), s.y)); + draw_texture_rect_region(progress, region, source, tint_progress); } break; case FILL_BILINEAR_TOP_AND_BOTTOM: { - Rect2 region = Rect2(Point2(0, s.y / 2 - s.y * get_as_ratio() / 2), Size2(s.x, s.y * get_as_ratio())); - draw_texture_rect_region(progress, region, region, tint_progress); + Rect2 region = Rect2(progress_offset + Point2(0, s.y / 2 - s.y * get_as_ratio() / 2), Size2(s.x, s.y * get_as_ratio())); + Rect2 source = Rect2(Point2(0, s.y / 2 - s.y * get_as_ratio() / 2), Size2(s.x, s.y * get_as_ratio())); + draw_texture_rect_region(progress, region, source, tint_progress); } break; case FILL_MODE_MAX: break; default: - draw_texture_rect_region(progress, Rect2(Point2(), Size2(s.x * get_as_ratio(), s.y)), Rect2(Point2(), Size2(s.x * get_as_ratio(), s.y)), tint_progress); + draw_texture_rect_region(progress, Rect2(progress_offset, Size2(s.x * get_as_ratio(), s.y)), Rect2(Point2(), Size2(s.x * get_as_ratio(), s.y)), tint_progress); } } if (over.is_valid()) { @@ -585,6 +604,9 @@ void TextureProgressBar::_bind_methods() { ClassDB::bind_method(D_METHOD("set_tint_over", "tint"), &TextureProgressBar::set_tint_over); ClassDB::bind_method(D_METHOD("get_tint_over"), &TextureProgressBar::get_tint_over); + ClassDB::bind_method(D_METHOD("set_texture_progress_offset", "offset"), &TextureProgressBar::set_progress_offset); + ClassDB::bind_method(D_METHOD("get_texture_progress_offset"), &TextureProgressBar::get_progress_offset); + ClassDB::bind_method(D_METHOD("set_radial_initial_angle", "mode"), &TextureProgressBar::set_radial_initial_angle); ClassDB::bind_method(D_METHOD("get_radial_initial_angle"), &TextureProgressBar::get_radial_initial_angle); @@ -604,6 +626,7 @@ void TextureProgressBar::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture_under", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_under_texture", "get_under_texture"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture_over", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_over_texture", "get_over_texture"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture_progress", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_progress_texture", "get_progress_texture"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "texture_progress_offset"), "set_texture_progress_offset", "get_texture_progress_offset"); ADD_PROPERTY(PropertyInfo(Variant::INT, "fill_mode", PROPERTY_HINT_ENUM, "Left to Right,Right to Left,Top to Bottom,Bottom to Top,Clockwise,Counter Clockwise,Bilinear (Left and Right),Bilinear (Top and Bottom),Clockwise and Counter Clockwise"), "set_fill_mode", "get_fill_mode"); ADD_GROUP("Tint", "tint_"); ADD_PROPERTY(PropertyInfo(Variant::COLOR, "tint_under"), "set_tint_under", "get_tint_under"); diff --git a/scene/gui/texture_progress_bar.h b/scene/gui/texture_progress_bar.h index d147c43a26..c508f41387 100644 --- a/scene/gui/texture_progress_bar.h +++ b/scene/gui/texture_progress_bar.h @@ -61,6 +61,9 @@ public: void set_fill_mode(int p_fill); int get_fill_mode(); + void set_progress_offset(Point2 p_offset); + Point2 get_progress_offset() const; + void set_radial_initial_angle(float p_angle); float get_radial_initial_angle(); @@ -100,6 +103,7 @@ public: private: FillMode mode = FILL_LEFT_TO_RIGHT; + Point2 progress_offset; float rad_init_angle = 0.0; float rad_max_degrees = 360.0; Point2 rad_center_off; diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp index d9892b53fc..cb990892ed 100644 --- a/scene/gui/tree.cpp +++ b/scene/gui/tree.cpp @@ -889,11 +889,22 @@ void TreeItem::set_custom_font(int p_column, const Ref<Font> &p_font) { ERR_FAIL_INDEX(p_column, cells.size()); cells.write[p_column].custom_font = p_font; } + Ref<Font> TreeItem::get_custom_font(int p_column) const { ERR_FAIL_INDEX_V(p_column, cells.size(), Ref<Font>()); return cells[p_column].custom_font; } +void TreeItem::set_custom_font_size(int p_column, int p_font_size) { + ERR_FAIL_INDEX(p_column, cells.size()); + cells.write[p_column].custom_font_size = p_font_size; +} + +int TreeItem::get_custom_font_size(int p_column) const { + ERR_FAIL_INDEX_V(p_column, cells.size(), -1); + return cells[p_column].custom_font_size; +} + void TreeItem::set_tooltip(int p_column, const String &p_tooltip) { ERR_FAIL_INDEX(p_column, cells.size()); cells.write[p_column].tooltip = p_tooltip; @@ -1132,6 +1143,9 @@ void TreeItem::_bind_methods() { ClassDB::bind_method(D_METHOD("set_custom_font", "column", "font"), &TreeItem::set_custom_font); ClassDB::bind_method(D_METHOD("get_custom_font", "column"), &TreeItem::get_custom_font); + ClassDB::bind_method(D_METHOD("set_custom_font_size", "column", "font_size"), &TreeItem::set_custom_font_size); + ClassDB::bind_method(D_METHOD("get_custom_font_size", "column"), &TreeItem::get_custom_font_size); + ClassDB::bind_method(D_METHOD("set_custom_bg_color", "column", "color", "just_outline"), &TreeItem::set_custom_bg_color, DEFVAL(false)); ClassDB::bind_method(D_METHOD("clear_custom_bg_color", "column"), &TreeItem::clear_custom_bg_color); ClassDB::bind_method(D_METHOD("get_custom_bg_color", "column"), &TreeItem::get_custom_bg_color); @@ -1507,7 +1521,14 @@ void Tree::update_item_cell(TreeItem *p_item, int p_col) { } else { font = cache.font; } - p_item->cells.write[p_col].text_buf->add_string(valtext, font, cache.font_size, p_item->cells[p_col].opentype_features, (p_item->cells[p_col].language != "") ? p_item->cells[p_col].language : TranslationServer::get_singleton()->get_tool_locale()); + + int font_size; + if (p_item->cells[p_col].custom_font_size > 0) { + font_size = p_item->cells[p_col].custom_font_size; + } else { + font_size = cache.font_size; + } + p_item->cells.write[p_col].text_buf->add_string(valtext, font, font_size, p_item->cells[p_col].opentype_features, (p_item->cells[p_col].language != "") ? p_item->cells[p_col].language : TranslationServer::get_singleton()->get_tool_locale()); TS->shaped_text_set_bidi_override(p_item->cells[p_col].text_buf->get_rid(), structured_text_parser(p_item->cells[p_col].st_parser, p_item->cells[p_col].st_args, valtext)); p_item->cells.write[p_col].dirty = false; } @@ -1696,24 +1717,30 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 } } - if (drop_mode_flags && drop_mode_over == p_item) { + if (drop_mode_flags && drop_mode_over) { Rect2 r = cell_rect; - bool has_parent = p_item->get_first_child() != nullptr; if (rtl) { r.position.x = get_size().width - r.position.x - r.size.x; } - - if (drop_mode_section == -1 || has_parent || drop_mode_section == 0) { - RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(r.position.x, r.position.y, r.size.x, 1), cache.drop_position_color); - } - - if (drop_mode_section == 0) { - RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(r.position.x, r.position.y, 1, r.size.y), cache.drop_position_color); - RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(r.position.x + r.size.x - 1, r.position.y, 1, r.size.y), cache.drop_position_color); - } - - if ((drop_mode_section == 1 && !has_parent) || drop_mode_section == 0) { - RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(r.position.x, r.position.y + r.size.y, r.size.x, 1), cache.drop_position_color); + if (drop_mode_over == p_item) { + if (drop_mode_section == 0 || drop_mode_section == -1) { + // Line above. + RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(r.position.x, r.position.y, r.size.x, 1), cache.drop_position_color); + } + if (drop_mode_section == 0) { + // Side lines. + RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(r.position.x, r.position.y, 1, r.size.y), cache.drop_position_color); + RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(r.position.x + r.size.x - 1, r.position.y, 1, r.size.y), cache.drop_position_color); + } + if (drop_mode_section == 0 || (drop_mode_section == 1 && (!p_item->get_first_child() || p_item->is_collapsed()))) { + // Line below. + RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(r.position.x, r.position.y + r.size.y, r.size.x, 1), cache.drop_position_color); + } + } else if (drop_mode_over == p_item->get_parent()) { + if (drop_mode_section == 1 && !p_item->get_prev() /* && !drop_mode_over->is_collapsed() */) { // The drop_mode_over shouldn't ever be collapsed in here, otherwise we would be drawing a child of a collapsed item. + // Line above. + RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(r.position.x, r.position.y, r.size.x, 1), cache.drop_position_color); + } } } @@ -2768,7 +2795,7 @@ void Tree::_go_down() { accept_event(); } -void Tree::_gui_input(Ref<InputEvent> p_event) { +void Tree::gui_input(const Ref<InputEvent> &p_event) { ERR_FAIL_COND(p_event.is_null()); Ref<InputEventKey> k = p_event; @@ -4650,8 +4677,6 @@ bool Tree::get_allow_reselect() const { } void Tree::_bind_methods() { - ClassDB::bind_method(D_METHOD("_gui_input"), &Tree::_gui_input); - ClassDB::bind_method(D_METHOD("clear"), &Tree::clear); ClassDB::bind_method(D_METHOD("create_item", "parent", "idx"), &Tree::_create_item, DEFVAL(Variant()), DEFVAL(-1)); @@ -4770,12 +4795,11 @@ Tree::Tree() { popup_menu = memnew(PopupMenu); popup_menu->hide(); - add_child(popup_menu); - // popup_menu->set_as_top_level(true); + add_child(popup_menu, false, INTERNAL_MODE_FRONT); popup_editor = memnew(Popup); popup_editor->set_wrap_controls(true); - add_child(popup_editor); + add_child(popup_editor, false, INTERNAL_MODE_FRONT); popup_editor_vb = memnew(VBoxContainer); popup_editor->add_child(popup_editor_vb); popup_editor_vb->add_theme_constant_override("separation", 0); @@ -4793,12 +4817,12 @@ Tree::Tree() { h_scroll = memnew(HScrollBar); v_scroll = memnew(VScrollBar); - add_child(h_scroll); - add_child(v_scroll); + add_child(h_scroll, false, INTERNAL_MODE_FRONT); + add_child(v_scroll, false, INTERNAL_MODE_FRONT); range_click_timer = memnew(Timer); range_click_timer->connect("timeout", callable_mp(this, &Tree::_range_click_timeout)); - add_child(range_click_timer); + add_child(range_click_timer, false, INTERNAL_MODE_FRONT); h_scroll->connect("value_changed", callable_mp(this, &Tree::_scroll_moved)); v_scroll->connect("value_changed", callable_mp(this, &Tree::_scroll_moved)); diff --git a/scene/gui/tree.h b/scene/gui/tree.h index c207737cc0..8b7ddc3faf 100644 --- a/scene/gui/tree.h +++ b/scene/gui/tree.h @@ -114,6 +114,7 @@ private: Vector<Button> buttons; Ref<Font> custom_font; + int custom_font_size = -1; Cell() { text_buf.instantiate(); @@ -299,6 +300,9 @@ public: void set_custom_font(int p_column, const Ref<Font> &p_font); Ref<Font> get_custom_font(int p_column) const; + void set_custom_font_size(int p_column, int p_font_size); + int get_custom_font_size(int p_column) const; + void set_custom_bg_color(int p_column, const Color &p_color, bool p_bg_outline = false); void clear_custom_bg_color(int p_column); Color get_custom_bg_color(int p_column) const; @@ -462,7 +466,6 @@ private: void popup_select(int p_option); - void _gui_input(Ref<InputEvent> p_event); void _notification(int p_what); void item_edited(int p_column, TreeItem *p_item, bool p_lmb = true); @@ -626,6 +629,8 @@ protected: } public: + virtual void gui_input(const Ref<InputEvent> &p_event) override; + virtual String get_tooltip(const Point2 &p_pos) const override; TreeItem *get_item_at_position(const Point2 &p_pos) const; diff --git a/scene/gui/video_player.cpp b/scene/gui/video_player.cpp index 229b5384ea..8734037a57 100644 --- a/scene/gui/video_player.cpp +++ b/scene/gui/video_player.cpp @@ -129,7 +129,7 @@ void VideoPlayer::_mix_audio() { void VideoPlayer::_notification(int p_notification) { switch (p_notification) { case NOTIFICATION_ENTER_TREE: { - AudioServer::get_singleton()->add_callback(_mix_audios, this); + AudioServer::get_singleton()->add_mix_callback(_mix_audios, this); if (stream.is_valid() && autoplay && !Engine::get_singleton()->is_editor_hint()) { play(); @@ -138,8 +138,7 @@ void VideoPlayer::_notification(int p_notification) { } break; case NOTIFICATION_EXIT_TREE: { - AudioServer::get_singleton()->remove_callback(_mix_audios, this); - + AudioServer::get_singleton()->remove_mix_callback(_mix_audios, this); } break; case NOTIFICATION_INTERNAL_PROCESS: { |