From a70834e5fda89e4436c42c56c0a8eeb4758c172f Mon Sep 17 00:00:00 2001 From: ConteZero Date: Thu, 28 Oct 2021 09:07:18 +0200 Subject: [PATCH] Fix drag and drop on LineEdit --- doc/classes/Control.xml | 6 ++++ scene/gui/control.cpp | 2 ++ scene/gui/control.h | 2 ++ scene/gui/line_edit.cpp | 79 ++++++++++++++++++++++++++++++++++------- scene/gui/line_edit.h | 3 ++ scene/main/viewport.cpp | 16 +++++++-- 6 files changed, 94 insertions(+), 14 deletions(-) diff --git a/doc/classes/Control.xml b/doc/classes/Control.xml index 63e3eb7a5f..d24f50d4f9 100644 --- a/doc/classes/Control.xml +++ b/doc/classes/Control.xml @@ -1154,6 +1154,12 @@ Sent when control layout direction is changed. + + Sent when drop data operation is successful. + + + Sent when drop data operation fails. + Show the system's arrow mouse cursor when the user hovers the node. Use with [member mouse_default_cursor_shape]. diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp index 77a1efd021..a5e39aa1ca 100644 --- a/scene/gui/control.cpp +++ b/scene/gui/control.cpp @@ -3046,6 +3046,8 @@ void Control::_bind_methods() { BIND_CONSTANT(NOTIFICATION_SCROLL_BEGIN); BIND_CONSTANT(NOTIFICATION_SCROLL_END); BIND_CONSTANT(NOTIFICATION_LAYOUT_DIRECTION_CHANGED); + BIND_CONSTANT(NOTIFICATION_DROP_DATA_SUCCESS); + BIND_CONSTANT(NOTIFICATION_DROP_DATA_FAIL); BIND_ENUM_CONSTANT(CURSOR_ARROW); BIND_ENUM_CONSTANT(CURSOR_IBEAM); diff --git a/scene/gui/control.h b/scene/gui/control.h index 02ab336ef0..55b3682324 100644 --- a/scene/gui/control.h +++ b/scene/gui/control.h @@ -315,6 +315,8 @@ public: NOTIFICATION_SCROLL_BEGIN = 47, NOTIFICATION_SCROLL_END = 48, NOTIFICATION_LAYOUT_DIRECTION_CHANGED = 49, + NOTIFICATION_DROP_DATA_SUCCESS = 500, + NOTIFICATION_DROP_DATA_FAIL = 501, }; diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp index 8c33d306a1..fab564c605 100644 --- a/scene/gui/line_edit.cpp +++ b/scene/gui/line_edit.cpp @@ -268,7 +268,9 @@ void LineEdit::gui_input(const Ref &p_event) { return; } - shift_selection_check_pre(b->is_shift_pressed()); + if (b->is_shift_pressed()) { + shift_selection_check_pre(true); + } set_caret_at_pixel_pos(b->get_position().x); @@ -369,6 +371,11 @@ void LineEdit::gui_input(const Ref &p_event) { selection_fill_at_caret(); } } + + if (drag_action && can_drop_data(m->get_position(), get_viewport()->gui_get_drag_data())) { + drag_caret_force_displayed = true; + set_caret_at_pixel_pos(m->get_position().x); + } } Ref k = p_event; @@ -569,22 +576,44 @@ bool LineEdit::can_drop_data(const Point2 &p_point, const Variant &p_data) const return drop_override; } - return p_data.get_type() == Variant::STRING; + return is_editable() && p_data.get_type() == Variant::STRING; } void LineEdit::drop_data(const Point2 &p_point, const Variant &p_data) { Control::drop_data(p_point, p_data); - if (p_data.get_type() == Variant::STRING) { + if (p_data.get_type() == Variant::STRING && is_editable()) { set_caret_at_pixel_pos(p_point.x); - int selected = selection.end - selection.begin; + int caret_column_tmp = caret_column; + if (selection.drag_attempt) { + selection.drag_attempt = false; + if (caret_column < selection.begin || caret_column > selection.end) { + if (caret_column_tmp > selection.end) { + caret_column_tmp = caret_column_tmp - (selection.end - selection.begin); + } + selection_delete(); - text.erase(selection.begin, selected); - _shape(); - - insert_text_at_caret(p_data); - selection.begin = caret_column - selected; - selection.end = caret_column; + set_caret_column(caret_column_tmp); + insert_text_at_caret(p_data); + } + } else if (selection.enabled && caret_column >= selection.begin && caret_column <= selection.end) { + caret_column_tmp = selection.begin; + selection_delete(); + set_caret_column(caret_column_tmp); + insert_text_at_caret(p_data); + grab_focus(); + } else { + insert_text_at_caret(p_data); + grab_focus(); + } + select(caret_column_tmp, caret_column); + if (!text_changed_dirty) { + if (is_inside_tree()) { + MessageQueue::get_singleton()->push_call(this, "_text_changed"); + } + text_changed_dirty = true; + } + update(); } } @@ -802,7 +831,7 @@ void LineEdit::_notification(int p_what) { // Draw carets. ofs.x = x_ofs + scroll_offset; - if (draw_caret) { + if (draw_caret || drag_caret_force_displayed) { if (ime_text.length() == 0) { // Normal caret. CaretInfo caret = TS->shaped_text_get_carets(text_rid, caret_column); @@ -920,7 +949,7 @@ void LineEdit::_notification(int p_what) { DisplayServer::get_singleton()->virtual_keyboard_hide(); } - if (deselect_on_focus_loss_enabled) { + if (deselect_on_focus_loss_enabled && !selection.drag_attempt) { deselect(); } } break; @@ -934,6 +963,26 @@ void LineEdit::_notification(int p_what) { update(); } } break; + case Control::NOTIFICATION_DRAG_BEGIN: { + drag_action = true; + } break; + case Control::NOTIFICATION_DRAG_END: { + drag_action = false; + drag_caret_force_displayed = false; + } break; + case Control::NOTIFICATION_DROP_DATA_SUCCESS: { + if (selection.drag_attempt) { + selection.drag_attempt = false; + if (is_editable()) { + selection_delete(); + } else if (deselect_on_focus_loss_enabled) { + deselect(); + } + } + } break; + case Control::NOTIFICATION_DROP_DATA_FAIL: { + selection.drag_attempt = false; + } break; } } @@ -998,6 +1047,9 @@ void LineEdit::undo() { } else if (undo_stack_pos == undo_stack.front()) { return; } + + deselect(); + undo_stack_pos = undo_stack_pos->prev(); TextOperation op = undo_stack_pos->get(); text = op.text; @@ -1019,6 +1071,9 @@ void LineEdit::redo() { if (undo_stack_pos == undo_stack.back()) { return; } + + deselect(); + undo_stack_pos = undo_stack_pos->next(); TextOperation op = undo_stack_pos->get(); text = op.text; diff --git a/scene/gui/line_edit.h b/scene/gui/line_edit.h index 3364e02e01..247ca6a854 100644 --- a/scene/gui/line_edit.h +++ b/scene/gui/line_edit.h @@ -129,6 +129,9 @@ private: bool middle_mouse_paste_enabled = true; + bool drag_action = false; + bool drag_caret_force_displayed = false; + Ref right_icon; struct Selection { diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index 3280190250..a41434b781 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -1502,8 +1502,9 @@ void Viewport::_gui_input_event(Ref p_event) { if (gui.drag_data.get_type() != Variant::NIL && mb->get_button_index() == MOUSE_BUTTON_LEFT) { // Alternate drop use (when using force_drag(), as proposed by #5342). + bool drop_result = false; if (gui.mouse_focus) { - _gui_drop(gui.mouse_focus, pos, false); + drop_result = _gui_drop(gui.mouse_focus, pos, false); } gui.drag_data = Variant(); @@ -1514,6 +1515,11 @@ void Viewport::_gui_input_event(Ref p_event) { memdelete(drag_preview); gui.drag_preview_id = ObjectID(); } + if (drop_result) { + _propagate_viewport_notification(this, Control::NOTIFICATION_DROP_DATA_SUCCESS); + } else { + _propagate_viewport_notification(this, Control::NOTIFICATION_DROP_DATA_FAIL); + } _propagate_viewport_notification(this, NOTIFICATION_DRAG_END); // Change mouse accordingly. } @@ -1521,8 +1527,9 @@ void Viewport::_gui_input_event(Ref p_event) { _gui_cancel_tooltip(); } else { if (gui.drag_data.get_type() != Variant::NIL && mb->get_button_index() == MOUSE_BUTTON_LEFT) { + bool drop_result = false; if (gui.drag_mouse_over) { - _gui_drop(gui.drag_mouse_over, gui.drag_mouse_over_pos, false); + drop_result = _gui_drop(gui.drag_mouse_over, gui.drag_mouse_over_pos, false); } Control *drag_preview = _gui_get_drag_preview(); @@ -1534,6 +1541,11 @@ void Viewport::_gui_input_event(Ref p_event) { gui.drag_data = Variant(); gui.dragging = false; gui.drag_mouse_over = nullptr; + if (drop_result) { + _propagate_viewport_notification(this, Control::NOTIFICATION_DROP_DATA_SUCCESS); + } else { + _propagate_viewport_notification(this, Control::NOTIFICATION_DROP_DATA_FAIL); + } _propagate_viewport_notification(this, NOTIFICATION_DRAG_END); // Change mouse accordingly. }