diff options
-rw-r--r-- | doc/classes/LineEdit.xml | 7 | ||||
-rw-r--r-- | doc/classes/TextEdit.xml | 7 | ||||
-rw-r--r-- | editor/editor_resource_picker.cpp | 15 | ||||
-rw-r--r-- | editor/editor_resource_picker.h | 4 | ||||
-rw-r--r-- | editor/editor_spin_slider.cpp | 79 | ||||
-rw-r--r-- | editor/editor_spin_slider.h | 9 | ||||
-rw-r--r-- | editor/plugins/canvas_item_editor_plugin.cpp | 2 | ||||
-rw-r--r-- | editor/plugins/node_3d_editor_plugin.cpp | 2 | ||||
-rw-r--r-- | editor/scene_tree_editor.cpp | 31 | ||||
-rw-r--r-- | editor/scene_tree_editor.h | 3 | ||||
-rw-r--r-- | scene/gui/color_picker.cpp | 2 | ||||
-rw-r--r-- | scene/gui/line_edit.cpp | 69 | ||||
-rw-r--r-- | scene/gui/line_edit.h | 3 | ||||
-rw-r--r-- | scene/gui/spin_box.cpp | 2 | ||||
-rw-r--r-- | scene/gui/text_edit.cpp | 110 | ||||
-rw-r--r-- | scene/gui/text_edit.h | 9 |
16 files changed, 221 insertions, 133 deletions
diff --git a/doc/classes/LineEdit.xml b/doc/classes/LineEdit.xml index 773f7b1a02..af6fc738c7 100644 --- a/doc/classes/LineEdit.xml +++ b/doc/classes/LineEdit.xml @@ -102,6 +102,13 @@ Inserts [code]text[/code] at the caret. If the resulting value is longer than [member max_length], nothing happens. </description> </method> + <method name="is_menu_visible" qualifiers="const"> + <return type="bool"> + </return> + <description> + Returns whether the menu is visible. Use this instead of [code]get_menu().visible[/code] to improve performance (so the creation of the menu is avoided). + </description> + </method> <method name="menu_option"> <return type="void"> </return> diff --git a/doc/classes/TextEdit.xml b/doc/classes/TextEdit.xml index 5de6c059c3..6bc3cff199 100644 --- a/doc/classes/TextEdit.xml +++ b/doc/classes/TextEdit.xml @@ -382,6 +382,13 @@ <description> </description> </method> + <method name="is_menu_visible" qualifiers="const"> + <return type="bool"> + </return> + <description> + Returns whether the menu is visible. Use this instead of [code]get_menu().visible[/code] to improve performance (so the creation of the menu is avoided). + </description> + </method> <method name="is_selection_active" qualifiers="const"> <return type="bool"> </return> diff --git a/editor/editor_resource_picker.cpp b/editor/editor_resource_picker.cpp index 4d9865622c..495db29789 100644 --- a/editor/editor_resource_picker.cpp +++ b/editor/editor_resource_picker.cpp @@ -141,6 +141,7 @@ void EditorResourcePicker::_update_menu() { } void EditorResourcePicker::_update_menu_items() { + _ensure_resource_menu(); edit_menu->clear(); // Add options for creating specific subtypes of the base resource type. @@ -360,6 +361,7 @@ void EditorResourcePicker::_edit_menu_cbk(int p_which) { } void EditorResourcePicker::set_create_options(Object *p_menu_node) { + _ensure_resource_menu(); // If a subclass implements this method, use it to replace all create items. if (get_script_instance() && get_script_instance()->has_method("_set_create_options")) { get_script_instance()->call("_set_create_options", p_menu_node); @@ -783,6 +785,15 @@ bool EditorResourcePicker::is_editable() const { return editable; } +void EditorResourcePicker::_ensure_resource_menu() { + if (edit_menu) { + return; + } + edit_menu = memnew(PopupMenu); + add_child(edit_menu); + edit_menu->connect("id_pressed", callable_mp(this, &EditorResourcePicker::_edit_menu_cbk)); + edit_menu->connect("popup_hide", callable_mp((BaseButton *)edit_button, &BaseButton::set_pressed), varray(false)); +} EditorResourcePicker::EditorResourcePicker() { assign_button = memnew(Button); assign_button->set_flat(true); @@ -808,10 +819,6 @@ EditorResourcePicker::EditorResourcePicker() { edit_button->connect("pressed", callable_mp(this, &EditorResourcePicker::_update_menu)); add_child(edit_button); edit_button->connect("gui_input", callable_mp(this, &EditorResourcePicker::_button_input)); - edit_menu = memnew(PopupMenu); - add_child(edit_menu); - edit_menu->connect("id_pressed", callable_mp(this, &EditorResourcePicker::_edit_menu_cbk)); - edit_menu->connect("popup_hide", callable_mp((BaseButton *)edit_button, &BaseButton::set_pressed), varray(false)); } void EditorScriptPicker::set_create_options(Object *p_menu_node) { diff --git a/editor/editor_resource_picker.h b/editor/editor_resource_picker.h index 9a4b945bc7..82a4817dfc 100644 --- a/editor/editor_resource_picker.h +++ b/editor/editor_resource_picker.h @@ -67,7 +67,7 @@ class EditorResourcePicker : public HBoxContainer { CONVERT_BASE_ID = 1000, }; - PopupMenu *edit_menu; + PopupMenu *edit_menu = nullptr; void _update_resource(); void _update_resource_preview(const String &p_path, const Ref<Texture2D> &p_preview, const Ref<Texture2D> &p_small_preview, ObjectID p_obj); @@ -90,6 +90,8 @@ class EditorResourcePicker : public HBoxContainer { bool can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const; void drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from); + void _ensure_resource_menu(); + protected: static void _bind_methods(); void _notification(int p_what); diff --git a/editor/editor_spin_slider.cpp b/editor/editor_spin_slider.cpp index aa4a394d30..247eaab9f8 100644 --- a/editor/editor_spin_slider.cpp +++ b/editor/editor_spin_slider.cpp @@ -185,6 +185,27 @@ void EditorSpinSlider::_grabber_gui_input(const Ref<InputEvent> &p_event) { } } +void EditorSpinSlider::_update_value_input_stylebox() { + if (!value_input) { + return; + } + // Add a left margin to the stylebox to make the number align with the Label + // when it's edited. The LineEdit "focus" stylebox uses the "normal" stylebox's + // default margins. + Ref<StyleBoxFlat> stylebox = + EditorNode::get_singleton()->get_theme_base()->get_theme_stylebox("normal", "LineEdit")->duplicate(); + // EditorSpinSliders with a label have more space on the left, so add an + // higher margin to match the location where the text begins. + // The margin values below were determined by empirical testing. + if (is_layout_rtl()) { + stylebox->set_default_margin(SIDE_LEFT, 0); + stylebox->set_default_margin(SIDE_RIGHT, (get_label() != String() ? 23 : 16) * EDSCALE); + } else { + stylebox->set_default_margin(SIDE_LEFT, (get_label() != String() ? 23 : 16) * EDSCALE); + stylebox->set_default_margin(SIDE_RIGHT, 0); + } + value_input->add_theme_style_override("normal", stylebox); +} void EditorSpinSlider::_notification(int p_what) { if (p_what == NOTIFICATION_WM_WINDOW_FOCUS_OUT || p_what == NOTIFICATION_WM_WINDOW_FOCUS_IN || @@ -197,23 +218,8 @@ void EditorSpinSlider::_notification(int p_what) { } } - if (p_what == NOTIFICATION_READY) { - // Add a left margin to the stylebox to make the number align with the Label - // when it's edited. The LineEdit "focus" stylebox uses the "normal" stylebox's - // default margins. - Ref<StyleBoxFlat> stylebox = - EditorNode::get_singleton()->get_theme_base()->get_theme_stylebox("normal", "LineEdit")->duplicate(); - // EditorSpinSliders with a label have more space on the left, so add an - // higher margin to match the location where the text begins. - // The margin values below were determined by empirical testing. - if (is_layout_rtl()) { - stylebox->set_default_margin(SIDE_LEFT, 0); - stylebox->set_default_margin(SIDE_RIGHT, (get_label() != String() ? 23 : 16) * EDSCALE); - } else { - stylebox->set_default_margin(SIDE_LEFT, (get_label() != String() ? 23 : 16) * EDSCALE); - stylebox->set_default_margin(SIDE_RIGHT, 0); - } - value_input->add_theme_style_override("normal", stylebox); + if (p_what == NOTIFICATION_READY || p_what == NOTIFICATION_THEME_CHANGED) { + _update_value_input_stylebox(); } if (p_what == NOTIFICATION_DRAW) { @@ -332,7 +338,7 @@ void EditorSpinSlider::_notification(int p_what) { grabbing_spinner_mouse_pos = get_global_position() + grabber_rect.position + grabber_rect.size * 0.5; - bool display_grabber = (mouse_over_spin || mouse_over_grabber) && !grabbing_spinner && !value_input_popup->is_visible(); + bool display_grabber = (mouse_over_spin || mouse_over_grabber) && !grabbing_spinner && !(value_input_popup && value_input_popup->is_visible()); if (grabber->is_visible() != display_grabber) { if (display_grabber) { grabber->show(); @@ -445,7 +451,9 @@ void EditorSpinSlider::_evaluate_input_text() { //text_submitted signal void EditorSpinSlider::_value_input_submitted(const String &p_text) { value_input_just_closed = true; - value_input_popup->hide(); + if (value_input_popup) { + value_input_popup->hide(); + } } //modal_closed signal @@ -457,7 +465,7 @@ void EditorSpinSlider::_value_input_closed() { //focus_exited signal void EditorSpinSlider::_value_focus_exited() { // discontinue because the focus_exit was caused by right-click context menu - if (value_input->get_menu()->is_visible()) { + if (value_input->is_menu_visible()) { return; } @@ -468,7 +476,9 @@ void EditorSpinSlider::_value_focus_exited() { // -> modal_close was not called // -> need to close/hide manually if (!value_input_just_closed) { //value_input_just_closed should do the same - value_input_popup->hide(); + if (value_input_popup) { + value_input_popup->hide(); + } //tab was pressed } else { //enter, click, esc @@ -509,6 +519,7 @@ void EditorSpinSlider::set_custom_label_color(bool p_use_custom_label_color, Col } void EditorSpinSlider::_focus_entered() { + _ensure_input_popup(); Rect2 gr = get_screen_rect(); value_input->set_text(get_text_value()); value_input_popup->set_position(gr.position); @@ -541,6 +552,23 @@ void EditorSpinSlider::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flat"), "set_flat", "is_flat"); } +void EditorSpinSlider::_ensure_input_popup() { + if (value_input_popup) { + return; + } + value_input_popup = memnew(Popup); + add_child(value_input_popup); + value_input = memnew(LineEdit); + value_input_popup->add_child(value_input); + value_input_popup->set_wrap_controls(true); + value_input->set_anchors_and_offsets_preset(PRESET_WIDE); + value_input_popup->connect("popup_hide", callable_mp(this, &EditorSpinSlider::_value_input_closed)); + value_input->connect("text_submitted", callable_mp(this, &EditorSpinSlider::_value_input_submitted)); + value_input->connect("focus_exited", callable_mp(this, &EditorSpinSlider::_value_focus_exited)); + if (is_inside_tree()) { + _update_value_input_stylebox(); + } +} EditorSpinSlider::EditorSpinSlider() { flat = false; grabbing_spinner_attempt = false; @@ -563,15 +591,6 @@ EditorSpinSlider::EditorSpinSlider() { mousewheel_over_grabber = false; grabbing_grabber = false; grabber_range = 1; - value_input_popup = memnew(Popup); - add_child(value_input_popup); - value_input = memnew(LineEdit); - value_input_popup->add_child(value_input); - value_input_popup->set_wrap_controls(true); - value_input->set_anchors_and_offsets_preset(PRESET_WIDE); - value_input_popup->connect("popup_hide", callable_mp(this, &EditorSpinSlider::_value_input_closed)); - value_input->connect("text_submitted", callable_mp(this, &EditorSpinSlider::_value_input_submitted)); - value_input->connect("focus_exited", callable_mp(this, &EditorSpinSlider::_value_focus_exited)); value_input_just_closed = false; hide_slider = false; read_only = false; diff --git a/editor/editor_spin_slider.h b/editor/editor_spin_slider.h index c30ff30390..af1f385fad 100644 --- a/editor/editor_spin_slider.h +++ b/editor/editor_spin_slider.h @@ -63,9 +63,9 @@ class EditorSpinSlider : public Range { Vector2 grabbing_spinner_mouse_pos; double pre_grab_value; - Popup *value_input_popup; - LineEdit *value_input; - bool value_input_just_closed; + Popup *value_input_popup = nullptr; + LineEdit *value_input = nullptr; + bool value_input_just_closed = false; void _grabber_gui_input(const Ref<InputEvent> &p_event); void _value_input_closed(); @@ -79,6 +79,9 @@ class EditorSpinSlider : public Range { void _evaluate_input_text(); + void _update_value_input_stylebox(); + void _ensure_input_popup(); + protected: void _notification(int p_what); void _gui_input(const Ref<InputEvent> &p_event); diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp index 240e28a3c5..4af499f10c 100644 --- a/editor/plugins/canvas_item_editor_plugin.cpp +++ b/editor/plugins/canvas_item_editor_plugin.cpp @@ -2324,7 +2324,7 @@ bool CanvasItemEditor::_gui_input_select(const Ref<InputEvent> &p_event) { } if (m.is_valid()) { Point2 click = transform.affine_inverse().xform(m->get_position()); - bool movement_threshold_passed = drag_start_origin.distance_to(click) > 10 * EDSCALE; + bool movement_threshold_passed = drag_start_origin.distance_to(click) > (8 * MAX(1, EDSCALE)) / zoom; if (m.is_valid() && movement_threshold_passed) { List<CanvasItem *> selection2 = _get_edited_canvas_items(); diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp index 52f1178d06..d5302df5e9 100644 --- a/editor/plugins/node_3d_editor_plugin.cpp +++ b/editor/plugins/node_3d_editor_plugin.cpp @@ -1467,7 +1467,7 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) { } else if (nav_scheme == NAVIGATION_MODO && m->is_alt_pressed()) { nav_mode = NAVIGATION_ORBIT; } else { - bool movement_threshold_passed = _edit.original_mouse_pos.distance_to(_edit.mouse_pos) > 10 * EDSCALE; + const bool movement_threshold_passed = _edit.original_mouse_pos.distance_to(_edit.mouse_pos) > 8 * EDSCALE; if (clicked.is_valid() && movement_threshold_passed) { if (!clicked_includes_current) { _select_clicked(clicked_wants_append, true); diff --git a/editor/scene_tree_editor.cpp b/editor/scene_tree_editor.cpp index 5958a09169..ad9ad3757c 100644 --- a/editor/scene_tree_editor.cpp +++ b/editor/scene_tree_editor.cpp @@ -521,7 +521,7 @@ void SceneTreeEditor::_node_removed(Node *p_node) { if (p_node == selected) { selected = nullptr; - emit_signal("node_selected"); + _emit_node_selected(); } } @@ -615,24 +615,6 @@ void SceneTreeEditor::_tree_changed() { pending_test_update = true; } -void SceneTreeEditor::_selected_changed() { - TreeItem *s = tree->get_selected(); - ERR_FAIL_COND(!s); - NodePath np = s->get_metadata(0); - - Node *n = get_node(np); - - if (n == selected) { - return; - } - - selected = get_node(np); - - blocked++; - emit_signal("node_selected"); - blocked--; -} - void SceneTreeEditor::_deselect_items() { // Clear currently selected items in scene tree dock. if (editor_selection) { @@ -641,6 +623,12 @@ void SceneTreeEditor::_deselect_items() { } } +void SceneTreeEditor::_emit_node_selected() { + blocked++; + emit_signal("node_selected"); + blocked--; +} + void SceneTreeEditor::_cell_multi_selected(Object *p_object, int p_cell, bool p_selected) { TreeItem *item = Object::cast_to<TreeItem>(p_object); ERR_FAIL_COND(!item); @@ -667,7 +655,7 @@ void SceneTreeEditor::_cell_multi_selected(Object *p_object, int p_cell, bool p_ // Selection changed to be single node, so emit "selected" (for single node) rather than "changed" (for multiple nodes) if (editor_selection->get_selected_nodes().size() == 1) { selected = editor_selection->get_selected_node_list()[0]; - emit_signal("node_selected"); + _emit_node_selected(); } else { emit_signal("node_changed"); } @@ -759,7 +747,7 @@ void SceneTreeEditor::set_selected(Node *p_node, bool p_emit_selected) { } if (p_emit_selected) { - emit_signal("node_selected"); + _emit_node_selected(); } } @@ -1200,7 +1188,6 @@ SceneTreeEditor::SceneTreeEditor(bool p_label, bool p_can_rename, bool p_can_ope tree->connect("empty_tree_rmb_selected", callable_mp(this, &SceneTreeEditor::_rmb_select)); } - tree->connect("cell_selected", callable_mp(this, &SceneTreeEditor::_selected_changed)); tree->connect("item_edited", callable_mp(this, &SceneTreeEditor::_renamed), varray(), CONNECT_DEFERRED); tree->connect("multi_selected", callable_mp(this, &SceneTreeEditor::_cell_multi_selected)); tree->connect("button_pressed", callable_mp(this, &SceneTreeEditor::_cell_button_pressed)); diff --git a/editor/scene_tree_editor.h b/editor/scene_tree_editor.h index acd49e8d92..e833bf93e0 100644 --- a/editor/scene_tree_editor.h +++ b/editor/scene_tree_editor.h @@ -81,7 +81,6 @@ class SceneTreeEditor : public Control { TreeItem *_find(TreeItem *p_node, const NodePath &p_path); void _notification(int p_what); - void _selected_changed(); void _deselect_items(); void _rename_node(ObjectID p_node, const String &p_name); @@ -133,6 +132,8 @@ class SceneTreeEditor : public Control { Vector<StringName> valid_types; + void _emit_node_selected(); + public: void set_filter(const String &p_filter); String get_filter() const; diff --git a/scene/gui/color_picker.cpp b/scene/gui/color_picker.cpp index 659d14ae70..842cef3b83 100644 --- a/scene/gui/color_picker.cpp +++ b/scene/gui/color_picker.cpp @@ -1048,7 +1048,7 @@ void ColorPicker::_focus_exit() { } void ColorPicker::_html_focus_exit() { - if (c_text->get_menu()->is_visible()) { + if (c_text->is_menu_visible()) { return; } _html_submitted(c_text->get_text()); diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp index f2d0d9bb22..c862624f98 100644 --- a/scene/gui/line_edit.cpp +++ b/scene/gui/line_edit.cpp @@ -227,6 +227,7 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) { return; } if (b->is_pressed() && b->get_button_index() == MOUSE_BUTTON_RIGHT && context_menu_enabled) { + _ensure_menu(); menu->set_position(get_screen_transform().xform(get_local_mouse_position())); menu->set_size(Vector2(1, 1)); _generate_context_menu(); @@ -348,6 +349,7 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) { if (context_menu_enabled) { if (k->is_action("ui_menu", true)) { + _ensure_menu(); Point2 pos = Point2(get_caret_pixel_pos().x, (get_size().y + get_theme_font("font")->get_height(get_theme_font_size("font_size"))) / 2); menu->set_position(get_global_transform().xform(pos)); menu->set_size(Vector2(1, 1)); @@ -612,7 +614,7 @@ void LineEdit::_notification(int p_what) { update(); } break; case NOTIFICATION_DRAW: { - if ((!has_focus() && !menu->has_focus() && !caret_force_displayed) || !window_has_focus) { + if ((!has_focus() && !(menu && menu->has_focus()) && !caret_force_displayed) || !window_has_focus) { draw_caret = false; } @@ -1252,10 +1254,12 @@ void LineEdit::set_text_direction(Control::TextDirection p_text_direction) { } _shape(); - menu_dir->set_item_checked(menu_dir->get_item_index(MENU_DIR_INHERITED), text_direction == TEXT_DIRECTION_INHERITED); - menu_dir->set_item_checked(menu_dir->get_item_index(MENU_DIR_AUTO), text_direction == TEXT_DIRECTION_AUTO); - menu_dir->set_item_checked(menu_dir->get_item_index(MENU_DIR_LTR), text_direction == TEXT_DIRECTION_LTR); - menu_dir->set_item_checked(menu_dir->get_item_index(MENU_DIR_RTL), text_direction == TEXT_DIRECTION_RTL); + if (menu_dir) { + menu_dir->set_item_checked(menu_dir->get_item_index(MENU_DIR_INHERITED), text_direction == TEXT_DIRECTION_INHERITED); + menu_dir->set_item_checked(menu_dir->get_item_index(MENU_DIR_AUTO), text_direction == TEXT_DIRECTION_AUTO); + menu_dir->set_item_checked(menu_dir->get_item_index(MENU_DIR_LTR), text_direction == TEXT_DIRECTION_LTR); + menu_dir->set_item_checked(menu_dir->get_item_index(MENU_DIR_RTL), text_direction == TEXT_DIRECTION_RTL); + } update(); } } @@ -1302,7 +1306,9 @@ String LineEdit::get_language() const { void LineEdit::set_draw_control_chars(bool p_draw_control_chars) { if (draw_control_chars != p_draw_control_chars) { draw_control_chars = p_draw_control_chars; - menu->set_item_checked(menu->get_item_index(MENU_DISPLAY_UCC), draw_control_chars); + if (menu && menu->get_item_index(MENU_DISPLAY_UCC) >= 0) { + menu->set_item_checked(menu->get_item_index(MENU_DISPLAY_UCC), draw_control_chars); + } _shape(); update(); } @@ -1810,7 +1816,12 @@ bool LineEdit::is_context_menu_enabled() { return context_menu_enabled; } +bool LineEdit::is_menu_visible() const { + return menu && menu->is_visible(); +} + PopupMenu *LineEdit::get_menu() const { + const_cast<LineEdit *>(this)->_ensure_menu(); return menu; } @@ -2009,6 +2020,7 @@ int LineEdit::_get_menu_action_accelerator(const String &p_action) { void LineEdit::_generate_context_menu() { // Reorganize context menu. + _ensure_menu(); menu->clear(); if (editable) { menu->add_item(RTR("Cut"), MENU_CUT, is_shortcut_keys_enabled() ? _get_menu_action_accelerator("ui_cut") : 0); @@ -2148,6 +2160,7 @@ void LineEdit::_bind_methods() { ClassDB::bind_method(D_METHOD("get_secret_character"), &LineEdit::get_secret_character); ClassDB::bind_method(D_METHOD("menu_option", "option"), &LineEdit::menu_option); ClassDB::bind_method(D_METHOD("get_menu"), &LineEdit::get_menu); + ClassDB::bind_method(D_METHOD("is_menu_visible"), &LineEdit::is_menu_visible); ClassDB::bind_method(D_METHOD("set_context_menu_enabled", "enable"), &LineEdit::set_context_menu_enabled); ClassDB::bind_method(D_METHOD("is_context_menu_enabled"), &LineEdit::is_context_menu_enabled); ClassDB::bind_method(D_METHOD("set_virtual_keyboard_enabled", "enable"), &LineEdit::set_virtual_keyboard_enabled); @@ -2230,23 +2243,14 @@ void LineEdit::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "caret_mid_grapheme"), "set_caret_mid_grapheme_enabled", "is_caret_mid_grapheme_enabled"); } -LineEdit::LineEdit() { - text_rid = TS->create_shaped_text(); - _create_undo_state(); - - deselect(); - set_focus_mode(FOCUS_ALL); - set_default_cursor_shape(CURSOR_IBEAM); - set_mouse_filter(MOUSE_FILTER_STOP); - - caret_blink_timer = memnew(Timer); - add_child(caret_blink_timer); - 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); +void LineEdit::_ensure_menu() { + if (menu) { + return; + } menu = memnew(PopupMenu); add_child(menu); + menu->connect("id_pressed", callable_mp(this, &LineEdit::menu_option)); menu_dir = memnew(PopupMenu); menu_dir->set_name("DirMenu"); @@ -2279,10 +2283,31 @@ LineEdit::LineEdit() { menu_ctl->add_item(RTR("Soft hyphen (SHY)"), MENU_INSERT_SHY); menu->add_child(menu_ctl); - set_editable(true); // Initialise to opposite first, so we get past the early-out in set_editable. - menu->connect("id_pressed", callable_mp(this, &LineEdit::menu_option)); menu_dir->connect("id_pressed", callable_mp(this, &LineEdit::menu_option)); menu_ctl->connect("id_pressed", callable_mp(this, &LineEdit::menu_option)); + + menu_dir->set_item_checked(menu_dir->get_item_index(MENU_DIR_INHERITED), text_direction == TEXT_DIRECTION_INHERITED); + menu_dir->set_item_checked(menu_dir->get_item_index(MENU_DIR_AUTO), text_direction == TEXT_DIRECTION_AUTO); + menu_dir->set_item_checked(menu_dir->get_item_index(MENU_DIR_LTR), text_direction == TEXT_DIRECTION_LTR); + menu_dir->set_item_checked(menu_dir->get_item_index(MENU_DIR_RTL), text_direction == TEXT_DIRECTION_RTL); +} + +LineEdit::LineEdit() { + text_rid = TS->create_shaped_text(); + _create_undo_state(); + + deselect(); + set_focus_mode(FOCUS_ALL); + set_default_cursor_shape(CURSOR_IBEAM); + set_mouse_filter(MOUSE_FILTER_STOP); + + caret_blink_timer = memnew(Timer); + add_child(caret_blink_timer); + 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); + + set_editable(true); // Initialise to opposite first, so we get past the early-out in set_editable. } LineEdit::~LineEdit() { diff --git a/scene/gui/line_edit.h b/scene/gui/line_edit.h index 12fec2f98b..16f3356637 100644 --- a/scene/gui/line_edit.h +++ b/scene/gui/line_edit.h @@ -198,6 +198,8 @@ private: void _backspace(bool p_word = false, bool p_all_to_left = false); void _delete(bool p_word = false, bool p_all_to_right = false); + void _ensure_menu(); + protected: void _notification(int p_what); static void _bind_methods(); @@ -222,6 +224,7 @@ public: void set_context_menu_enabled(bool p_enable); bool is_context_menu_enabled(); PopupMenu *get_menu() const; + bool is_menu_visible() const; void select(int p_from = 0, int p_to = -1); void select_all(); diff --git a/scene/gui/spin_box.cpp b/scene/gui/spin_box.cpp index 941dd30057..5c7b375608 100644 --- a/scene/gui/spin_box.cpp +++ b/scene/gui/spin_box.cpp @@ -170,7 +170,7 @@ void SpinBox::_gui_input(const Ref<InputEvent> &p_event) { void SpinBox::_line_edit_focus_exit() { // discontinue because the focus_exit was caused by right-click context menu - if (line_edit->get_menu()->is_visible()) { + if (line_edit->is_menu_visible()) { return; } diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index 6f96b530a6..9450b39aed 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -599,7 +599,7 @@ void TextEdit::_notification(int p_what) { Size2 size = get_size(); bool rtl = is_layout_rtl(); - if ((!has_focus() && !menu->has_focus()) || !window_has_focus) { + if ((!has_focus() && !(menu && menu->has_focus())) || !window_has_focus) { draw_caret = false; } @@ -2470,6 +2470,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { } } + _ensure_menu(); menu->set_position(get_screen_transform().xform(mpos)); menu->set_size(Vector2(1, 1)); _generate_context_menu(); @@ -2709,6 +2710,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { // MISC. if (k->is_action("ui_menu", true)) { if (context_menu_enabled) { + _ensure_menu(); menu->set_position(get_screen_transform().xform(_get_cursor_pixel_pos())); menu->set_size(Vector2(1, 1)); _generate_context_menu(); @@ -3214,6 +3216,7 @@ int TextEdit::_get_menu_action_accelerator(const String &p_action) { void TextEdit::_generate_context_menu() { // Reorganize context menu. + _ensure_menu(); menu->clear(); if (!readonly) { menu->add_item(RTR("Cut"), MENU_CUT, is_shortcut_keys_enabled() ? _get_menu_action_accelerator("ui_cut") : 0); @@ -3858,10 +3861,12 @@ void TextEdit::set_text_direction(Control::TextDirection p_text_direction) { text.set_direction_and_language(dir, (language != "") ? language : TranslationServer::get_singleton()->get_tool_locale()); text.invalidate_all(); - menu_dir->set_item_checked(menu_dir->get_item_index(MENU_DIR_INHERITED), text_direction == TEXT_DIRECTION_INHERITED); - menu_dir->set_item_checked(menu_dir->get_item_index(MENU_DIR_AUTO), text_direction == TEXT_DIRECTION_AUTO); - menu_dir->set_item_checked(menu_dir->get_item_index(MENU_DIR_LTR), text_direction == TEXT_DIRECTION_LTR); - menu_dir->set_item_checked(menu_dir->get_item_index(MENU_DIR_RTL), text_direction == TEXT_DIRECTION_RTL); + if (menu_dir) { + menu_dir->set_item_checked(menu_dir->get_item_index(MENU_DIR_INHERITED), text_direction == TEXT_DIRECTION_INHERITED); + menu_dir->set_item_checked(menu_dir->get_item_index(MENU_DIR_AUTO), text_direction == TEXT_DIRECTION_AUTO); + menu_dir->set_item_checked(menu_dir->get_item_index(MENU_DIR_LTR), text_direction == TEXT_DIRECTION_LTR); + menu_dir->set_item_checked(menu_dir->get_item_index(MENU_DIR_RTL), text_direction == TEXT_DIRECTION_RTL); + } update(); } } @@ -3917,7 +3922,9 @@ String TextEdit::get_language() const { void TextEdit::set_draw_control_chars(bool p_draw_control_chars) { if (draw_control_chars != p_draw_control_chars) { draw_control_chars = p_draw_control_chars; - menu->set_item_checked(menu->get_item_index(MENU_DISPLAY_UCC), draw_control_chars); + if (menu && menu->get_item_index(MENU_DISPLAY_UCC) >= 0) { + menu->set_item_checked(menu->get_item_index(MENU_DISPLAY_UCC), draw_control_chars); + } text.set_draw_control_chars(draw_control_chars); text.invalidate_all(); update(); @@ -5594,7 +5601,12 @@ bool TextEdit::is_virtual_keyboard_enabled() const { return virtual_keyboard_enabled; } +bool TextEdit::is_menu_visible() const { + return menu && menu->is_visible(); +} + PopupMenu *TextEdit::get_menu() const { + const_cast<TextEdit *>(this)->_ensure_menu(); return menu; } @@ -5833,6 +5845,7 @@ void TextEdit::_bind_methods() { ClassDB::bind_method(D_METHOD("menu_option", "option"), &TextEdit::menu_option); ClassDB::bind_method(D_METHOD("get_menu"), &TextEdit::get_menu); + ClassDB::bind_method(D_METHOD("is_menu_visible"), &TextEdit::is_menu_visible); ClassDB::bind_method(D_METHOD("draw_minimap", "draw"), &TextEdit::set_draw_minimap); ClassDB::bind_method(D_METHOD("is_drawing_minimap"), &TextEdit::is_drawing_minimap); @@ -5921,6 +5934,54 @@ void TextEdit::_bind_methods() { ProjectSettings::get_singleton()->set_custom_property_info("gui/common/text_edit_undo_stack_max_size", PropertyInfo(Variant::INT, "gui/common/text_edit_undo_stack_max_size", PROPERTY_HINT_RANGE, "0,10000,1,or_greater")); // No negative numbers. } +void TextEdit::_ensure_menu() { + if (menu) { + return; + } + + menu = memnew(PopupMenu); + add_child(menu); + + menu_dir = memnew(PopupMenu); + menu_dir->set_name("DirMenu"); + menu_dir->add_radio_check_item(RTR("Same as layout direction"), MENU_DIR_INHERITED); + 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_ctl = memnew(PopupMenu); + menu_ctl->set_name("CTLMenu"); + menu_ctl->add_item(RTR("Left-to-right mark (LRM)"), MENU_INSERT_LRM); + menu_ctl->add_item(RTR("Right-to-left mark (RLM)"), MENU_INSERT_RLM); + menu_ctl->add_item(RTR("Start of left-to-right embedding (LRE)"), MENU_INSERT_LRE); + menu_ctl->add_item(RTR("Start of right-to-left embedding (RLE)"), MENU_INSERT_RLE); + menu_ctl->add_item(RTR("Start of left-to-right override (LRO)"), MENU_INSERT_LRO); + menu_ctl->add_item(RTR("Start of right-to-left override (RLO)"), MENU_INSERT_RLO); + menu_ctl->add_item(RTR("Pop direction formatting (PDF)"), MENU_INSERT_PDF); + menu_ctl->add_separator(); + menu_ctl->add_item(RTR("Arabic letter mark (ALM)"), MENU_INSERT_ALM); + menu_ctl->add_item(RTR("Left-to-right isolate (LRI)"), MENU_INSERT_LRI); + menu_ctl->add_item(RTR("Right-to-left isolate (RLI)"), MENU_INSERT_RLI); + menu_ctl->add_item(RTR("First strong isolate (FSI)"), MENU_INSERT_FSI); + menu_ctl->add_item(RTR("Pop direction isolate (PDI)"), MENU_INSERT_PDI); + menu_ctl->add_separator(); + menu_ctl->add_item(RTR("Zero width joiner (ZWJ)"), MENU_INSERT_ZWJ); + 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->connect("id_pressed", callable_mp(this, &TextEdit::menu_option)); + menu_dir->connect("id_pressed", callable_mp(this, &TextEdit::menu_option)); + menu_ctl->connect("id_pressed", callable_mp(this, &TextEdit::menu_option)); + + menu_dir->set_item_checked(menu_dir->get_item_index(MENU_DIR_INHERITED), text_direction == TEXT_DIRECTION_INHERITED); + menu_dir->set_item_checked(menu_dir->get_item_index(MENU_DIR_AUTO), text_direction == TEXT_DIRECTION_AUTO); + menu_dir->set_item_checked(menu_dir->get_item_index(MENU_DIR_LTR), text_direction == TEXT_DIRECTION_LTR); + menu_dir->set_item_checked(menu_dir->get_item_index(MENU_DIR_RTL), text_direction == TEXT_DIRECTION_RTL); +} + TextEdit::TextEdit() { clear(); set_focus_mode(FOCUS_ALL); @@ -5960,44 +6021,7 @@ TextEdit::TextEdit() { undo_stack_max_size = GLOBAL_GET("gui/common/text_edit_undo_stack_max_size"); - menu = memnew(PopupMenu); - add_child(menu); - - menu_dir = memnew(PopupMenu); - menu_dir->set_name("DirMenu"); - menu_dir->add_radio_check_item(RTR("Same as layout direction"), MENU_DIR_INHERITED); - 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_dir->set_item_checked(menu_dir->get_item_index(MENU_DIR_INHERITED), true); - menu->add_child(menu_dir); - - menu_ctl = memnew(PopupMenu); - menu_ctl->set_name("CTLMenu"); - menu_ctl->add_item(RTR("Left-to-right mark (LRM)"), MENU_INSERT_LRM); - menu_ctl->add_item(RTR("Right-to-left mark (RLM)"), MENU_INSERT_RLM); - menu_ctl->add_item(RTR("Start of left-to-right embedding (LRE)"), MENU_INSERT_LRE); - menu_ctl->add_item(RTR("Start of right-to-left embedding (RLE)"), MENU_INSERT_RLE); - menu_ctl->add_item(RTR("Start of left-to-right override (LRO)"), MENU_INSERT_LRO); - menu_ctl->add_item(RTR("Start of right-to-left override (RLO)"), MENU_INSERT_RLO); - menu_ctl->add_item(RTR("Pop direction formatting (PDF)"), MENU_INSERT_PDF); - menu_ctl->add_separator(); - menu_ctl->add_item(RTR("Arabic letter mark (ALM)"), MENU_INSERT_ALM); - menu_ctl->add_item(RTR("Left-to-right isolate (LRI)"), MENU_INSERT_LRI); - menu_ctl->add_item(RTR("Right-to-left isolate (RLI)"), MENU_INSERT_RLI); - menu_ctl->add_item(RTR("First strong isolate (FSI)"), MENU_INSERT_FSI); - menu_ctl->add_item(RTR("Pop direction isolate (PDI)"), MENU_INSERT_PDI); - menu_ctl->add_separator(); - menu_ctl->add_item(RTR("Zero width joiner (ZWJ)"), MENU_INSERT_ZWJ); - 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); - set_readonly(false); - menu->connect("id_pressed", callable_mp(this, &TextEdit::menu_option)); - menu_dir->connect("id_pressed", callable_mp(this, &TextEdit::menu_option)); - menu_ctl->connect("id_pressed", callable_mp(this, &TextEdit::menu_option)); } TextEdit::~TextEdit() { diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h index dcd5c6d0f8..7863499878 100644 --- a/scene/gui/text_edit.h +++ b/scene/gui/text_edit.h @@ -410,9 +410,11 @@ private: Dictionary _search_bind(const String &p_key, uint32_t p_search_flags, int p_from_line, int p_from_column) const; - PopupMenu *menu; - PopupMenu *menu_dir; - PopupMenu *menu_ctl; + PopupMenu *menu = nullptr; + PopupMenu *menu_dir = nullptr; + PopupMenu *menu_ctl = nullptr; + + void _ensure_menu(); void _clear(); @@ -781,6 +783,7 @@ public: void set_virtual_keyboard_enabled(bool p_enable); bool is_virtual_keyboard_enabled() const; + bool is_menu_visible() const; PopupMenu *get_menu() const; String get_text_for_lookup_completion(); |