diff --git a/doc/classes/Control.xml b/doc/classes/Control.xml
index 32a0a2ac1a6e..132470661ab5 100644
--- a/doc/classes/Control.xml
+++ b/doc/classes/Control.xml
@@ -500,6 +500,12 @@
See [method add_stylebox_override].
+
+
+
+ Returns [code]true[/code] if drag operation is successful.
+
+
diff --git a/doc/classes/TextEdit.xml b/doc/classes/TextEdit.xml
index da8eba148c0f..913ed94bbbb3 100644
--- a/doc/classes/TextEdit.xml
+++ b/doc/classes/TextEdit.xml
@@ -313,6 +313,13 @@
Returns if the given line is wrapped.
+
+
+
+
+ Returns whether the mouse is over selection. If [code]edges[/code] is [code]true[/code], the edges are considered part of the selection.
+
+
diff --git a/doc/classes/Viewport.xml b/doc/classes/Viewport.xml
index 69b03e51cbf3..b5a7158c4767 100644
--- a/doc/classes/Viewport.xml
+++ b/doc/classes/Viewport.xml
@@ -114,6 +114,12 @@
Returns [code]true[/code] if there are visible modals on-screen.
+
+
+
+ Returns [code]true[/code] if the drag operation is successful.
+
+
diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp
index 9acbdeeceeaf..fad4d8fd895f 100644
--- a/scene/gui/control.cpp
+++ b/scene/gui/control.cpp
@@ -757,6 +757,10 @@ void Control::set_drag_preview(Control *p_control) {
get_viewport()->_gui_set_drag_preview(this, p_control);
}
+bool Control::is_drag_successful() const {
+ return is_inside_tree() && get_viewport()->gui_is_drag_successful();
+}
+
bool Control::is_window_modal_on_top() const {
if (!is_inside_tree()) {
return false;
@@ -2852,6 +2856,7 @@ void Control::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_drag_forwarding", "target"), &Control::set_drag_forwarding);
ClassDB::bind_method(D_METHOD("set_drag_preview", "control"), &Control::set_drag_preview);
+ ClassDB::bind_method(D_METHOD("is_drag_successful"), &Control::is_drag_successful);
ClassDB::bind_method(D_METHOD("warp_mouse", "to_position"), &Control::warp_mouse);
diff --git a/scene/gui/control.h b/scene/gui/control.h
index 2657af02c7f6..dc5d2c83a2f0 100644
--- a/scene/gui/control.h
+++ b/scene/gui/control.h
@@ -310,6 +310,7 @@ class Control : public CanvasItem {
virtual void drop_data(const Point2 &p_point, const Variant &p_data);
void set_drag_preview(Control *p_control);
void force_drag(const Variant &p_data, Control *p_control);
+ bool is_drag_successful() const;
void set_custom_minimum_size(const Size2 &p_custom);
Size2 get_custom_minimum_size() const;
diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp
index 71dfda52c503..0e05c1120a73 100644
--- a/scene/gui/line_edit.cpp
+++ b/scene/gui/line_edit.cpp
@@ -31,11 +31,13 @@
#include "line_edit.h"
#include "core/message_queue.h"
+#include "core/os/input.h"
#include "core/os/keyboard.h"
#include "core/os/os.h"
#include "core/print_string.h"
#include "core/translation.h"
#include "label.h"
+#include "scene/main/viewport.h"
#ifdef TOOLS_ENABLED
#include "editor/editor_scale.h"
@@ -79,7 +81,9 @@ void LineEdit::_gui_input(Ref p_event) {
return;
}
- shift_selection_check_pre(b->get_shift());
+ if (b->get_shift()) {
+ shift_selection_check_pre(true);
+ }
set_cursor_at_pixel_pos(b->get_position().x);
@@ -124,7 +128,7 @@ void LineEdit::_gui_input(Ref p_event) {
deselect();
selection.cursor_start = cursor_pos;
selection.creating = true;
- } else if (selection.enabled) {
+ } else if (selection.enabled && !selection.doubleclick) {
selection.drag_attempt = true;
}
}
@@ -146,6 +150,9 @@ void LineEdit::_gui_input(Ref p_event) {
}
selection.creating = false;
selection.doubleclick = false;
+ if (!drag_action) {
+ selection.drag_attempt = false;
+ }
show_virtual_keyboard();
}
@@ -170,6 +177,11 @@ void LineEdit::_gui_input(Ref p_event) {
selection_fill_at_cursor();
}
}
+
+ if (drag_action && can_drop_data(m->get_position(), get_viewport()->gui_get_drag_data())) {
+ drag_caret_force_displayed = true;
+ set_cursor_at_pixel_pos(m->get_position().x);
+ }
}
Ref k = p_event;
@@ -641,28 +653,50 @@ 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_cursor_at_pixel_pos(p_point.x);
- int selected = selection.end - selection.begin;
+ int caret_column_tmp = cursor_pos;
+ bool is_inside_sel = selection.enabled && cursor_pos >= selection.begin && cursor_pos <= selection.end;
+ if (Input::get_singleton()->is_key_pressed(KEY_CONTROL)) {
+ is_inside_sel = selection.enabled && cursor_pos > selection.begin && cursor_pos < selection.end;
+ }
+ if (selection.drag_attempt) {
+ selection.drag_attempt = false;
+ if (!is_inside_sel) {
+ if (!Input::get_singleton()->is_key_pressed(KEY_CONTROL)) {
+ if (caret_column_tmp > selection.end) {
+ caret_column_tmp = caret_column_tmp - (selection.end - selection.begin);
+ }
+ selection_delete();
+ }
- Ref font = get_font("font");
- if (font != nullptr) {
- for (int i = selection.begin; i < selection.end; i++) {
- cached_width -= font->get_char_size(pass ? secret_character[0] : text[i]).width;
+ set_cursor_position(caret_column_tmp);
+ append_at_cursor(p_data);
}
+ } else if (selection.enabled && cursor_pos >= selection.begin && cursor_pos <= selection.end) {
+ caret_column_tmp = selection.begin;
+ selection_delete();
+ set_cursor_position(caret_column_tmp);
+ append_at_cursor(p_data);
+ grab_focus();
+ } else {
+ append_at_cursor(p_data);
+ grab_focus();
}
-
- text.erase(selection.begin, selected);
-
- append_at_cursor(p_data);
- selection.begin = cursor_pos - selected;
- selection.end = cursor_pos;
+ select(caret_column_tmp, cursor_pos);
+ if (!text_changed_dirty) {
+ if (is_inside_tree()) {
+ MessageQueue::get_singleton()->push_call(this, "_text_changed");
+ }
+ text_changed_dirty = true;
+ }
+ update();
}
}
@@ -910,7 +944,7 @@ void LineEdit::_notification(int p_what) {
}
}
- if ((char_ofs == cursor_pos || using_placeholder) && draw_caret) { // May be at the end, or placeholder.
+ if ((char_ofs == cursor_pos || using_placeholder || drag_caret_force_displayed) && draw_caret) { // May be at the end, or placeholder.
if (ime_text.length() == 0) {
int caret_x_ofs = x_ofs;
if (using_placeholder) {
@@ -977,6 +1011,25 @@ void LineEdit::_notification(int p_what) {
update();
}
} break;
+ case Control::NOTIFICATION_DRAG_BEGIN: {
+ drag_action = true;
+ } break;
+ case Control::NOTIFICATION_DRAG_END: {
+ if (is_drag_successful()) {
+ if (selection.drag_attempt) {
+ selection.drag_attempt = false;
+ if (is_editable() && !Input::get_singleton()->is_key_pressed(KEY_CONTROL)) {
+ selection_delete();
+ // } else if (deselect_on_focus_loss_enabled) {
+ // deselect();
+ }
+ }
+ } else {
+ selection.drag_attempt = false;
+ }
+ drag_action = false;
+ drag_caret_force_displayed = false;
+ } break;
}
}
@@ -1033,6 +1086,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;
@@ -1054,6 +1110,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 56d9628c9dfa..3c28aa1d3eb0 100644
--- a/scene/gui/line_edit.h
+++ b/scene/gui/line_edit.h
@@ -92,6 +92,9 @@ class LineEdit : public Control {
bool virtual_keyboard_enabled = true;
+ bool drag_action = false;
+ bool drag_caret_force_displayed = false;
+
Ref right_icon;
struct Selection {
diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp
index cecfdfd78ad8..2937bfcb563f 100644
--- a/scene/gui/rich_text_label.cpp
+++ b/scene/gui/rich_text_label.cpp
@@ -33,6 +33,7 @@
#include "core/math/math_defs.h"
#include "core/os/keyboard.h"
#include "core/os/os.h"
+#include "label.h"
#include "scene/scene_string_names.h"
#ifdef TOOLS_ENABLED
@@ -1047,6 +1048,9 @@ void RichTextLabel::_notification(int p_what) {
update();
}
}
+ case Control::NOTIFICATION_DRAG_END: {
+ selection.drag_attempt = false;
+ } break;
}
}
@@ -1129,6 +1133,9 @@ void RichTextLabel::_gui_input(Ref p_event) {
Item *item = nullptr;
bool outside;
+
+ selection.drag_attempt = false;
+
_find_click(main, b->get_position(), &item, &line, &outside);
if (item) {
@@ -1138,13 +1145,18 @@ void RichTextLabel::_gui_input(Ref p_event) {
// Erase previous selection.
if (selection.active) {
- selection.from = nullptr;
- selection.from_char = '\0';
- selection.to = nullptr;
- selection.to_char = '\0';
- selection.active = false;
-
- update();
+ if (_is_click_inside_selection()) {
+ selection.drag_attempt = true;
+ selection.click = nullptr;
+ } else {
+ selection.from = nullptr;
+ selection.from_char = '\0';
+ selection.to = nullptr;
+ selection.to_char = '\0';
+ selection.active = false;
+
+ update();
+ }
}
}
}
@@ -1154,6 +1166,8 @@ void RichTextLabel::_gui_input(Ref p_event) {
Item *item = nullptr;
bool outside;
+ selection.drag_attempt = false;
+
_find_click(main, b->get_position(), &item, &line, &outside);
while (item && item->type != ITEM_TEXT) {
@@ -1174,6 +1188,25 @@ void RichTextLabel::_gui_input(Ref p_event) {
}
}
} else if (!b->is_pressed()) {
+ if (selection.drag_attempt) {
+ selection.drag_attempt = false;
+ int line = 0;
+ Item *item = nullptr;
+ bool outside;
+ _find_click(main, b->get_position(), &item, &line, &outside);
+ selection.click = item;
+ selection.click_char = line;
+ if (_is_click_inside_selection()) {
+ selection.active = false;
+ selection.from = nullptr;
+ selection.from_char = '\0';
+ selection.to = nullptr;
+ selection.to_char = '\0';
+ selection.active = false;
+
+ update();
+ }
+ }
selection.click = nullptr;
if (!b->is_doubleclick() && !scroll_updated) {
@@ -2476,6 +2509,22 @@ void RichTextLabel::set_selection_enabled(bool p_enabled) {
}
}
+Variant RichTextLabel::get_drag_data(const Point2 &p_point) {
+ if (selection.drag_attempt && selection.enabled) {
+ String t = get_selected_text();
+ Label *l = memnew(Label);
+ l->set_text(t);
+ set_drag_preview(l);
+ return t;
+ }
+
+ return Variant();
+}
+
+bool RichTextLabel::_is_click_inside_selection() const {
+ return (selection.click->index >= selection.from->index && selection.click->index <= selection.to->index && (selection.click->index > selection.from->index || selection.click_char >= selection.from_char) && (selection.click->index < selection.to->index || selection.click_char <= selection.to_char));
+}
+
bool RichTextLabel::search(const String &p_string, bool p_from_selection, bool p_search_previous) {
ERR_FAIL_COND_V(!selection.enabled, false);
Item *it = main;
@@ -2985,6 +3034,7 @@ RichTextLabel::RichTextLabel() {
selection.click = nullptr;
selection.active = false;
selection.enabled = false;
+ selection.drag_attempt = false;
visible_characters = -1;
percent_visible = 1;
diff --git a/scene/gui/rich_text_label.h b/scene/gui/rich_text_label.h
index a5618e8ef271..af80efb93229 100644
--- a/scene/gui/rich_text_label.h
+++ b/scene/gui/rich_text_label.h
@@ -358,6 +358,7 @@ class RichTextLabel : public Control {
bool active; // anything selected? i.e. from, to, etc. valid?
bool enabled; // allow selections?
+ bool drag_attempt;
};
Selection selection;
@@ -365,6 +366,7 @@ class RichTextLabel : public Control {
int visible_characters;
float percent_visible;
+ bool _is_click_inside_selection() const;
int _process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int &y, int p_width, int p_line, ProcessMode p_mode, const Ref &p_base_font, const Color &p_base_color, const Color &p_font_color_shadow, bool p_shadow_as_outline, const Point2 &shadow_ofs, const Point2i &p_click_pos = Point2i(), Item **r_click_item = nullptr, int *r_click_char = nullptr, bool *r_outside = nullptr, int p_char_count = 0);
void _find_click(ItemFrame *p_frame, const Point2i &p_click, Item **r_click_item = nullptr, int *r_click_char = nullptr, bool *r_outside = nullptr);
@@ -465,6 +467,7 @@ class RichTextLabel : public Control {
VScrollBar *get_v_scroll() { return vscroll; }
virtual CursorShape get_cursor_shape(const Point2 &p_pos) const;
+ virtual Variant get_drag_data(const Point2 &p_point);
void set_selection_enabled(bool p_enabled);
bool is_selection_enabled() const;
diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp
index 86d73c61ad43..56e535780304 100644
--- a/scene/gui/text_edit.cpp
+++ b/scene/gui/text_edit.cpp
@@ -36,6 +36,7 @@
#include "core/os/os.h"
#include "core/project_settings.h"
#include "core/script_language.h"
+#include "label.h"
#include "scene/main/viewport.h"
#ifdef TOOLS_ENABLED
@@ -430,6 +431,7 @@ void TextEdit::_click_selection_held() {
}
void TextEdit::_update_selection_mode_pointer() {
+ selection.drag_attempt = false;
dragging_selection = true;
Point2 mp = get_local_mouse_position();
@@ -446,6 +448,7 @@ void TextEdit::_update_selection_mode_pointer() {
}
void TextEdit::_update_selection_mode_word() {
+ selection.drag_attempt = false;
dragging_selection = true;
Point2 mp = get_local_mouse_position();
@@ -503,6 +506,7 @@ void TextEdit::_update_selection_mode_word() {
}
void TextEdit::_update_selection_mode_line() {
+ selection.drag_attempt = false;
dragging_selection = true;
Point2 mp = get_local_mouse_position();
@@ -1502,7 +1506,7 @@ void TextEdit::_notification(int p_what) {
}
}
if (ime_text.length() == 0) {
- if (draw_caret) {
+ if (draw_caret || drag_caret_force_displayed) {
if (insert_mode) {
#ifdef TOOLS_ENABLED
int caret_h = (block_caret) ? 4 : 2 * EDSCALE;
@@ -1608,7 +1612,7 @@ void TextEdit::_notification(int p_what) {
}
}
if (ime_text.length() == 0) {
- if (draw_caret) {
+ if (draw_caret || drag_caret_force_displayed) {
if (insert_mode) {
int char_w = cache.font->get_char_size(' ').width;
#ifdef TOOLS_ENABLED
@@ -1891,6 +1895,37 @@ void TextEdit::_notification(int p_what) {
update();
}
} break;
+ case Control::NOTIFICATION_DRAG_BEGIN: {
+ selection.selecting_mode = Selection::MODE_NONE;
+ drag_action = true;
+ dragging_minimap = false;
+ dragging_selection = false;
+ can_drag_minimap = false;
+ click_select_held->stop();
+ } break;
+ case Control::NOTIFICATION_DRAG_END: {
+ if (is_drag_successful()) {
+ if (selection.drag_attempt) {
+ selection.drag_attempt = false;
+ if (!readonly && !Input::get_singleton()->is_key_pressed(KEY_CONTROL)) {
+ _remove_text(selection.from_line, selection.from_column, selection.to_line, selection.to_column);
+ cursor_set_line(selection.from_line, false);
+ cursor_set_column(selection.from_column);
+ selection.active = false;
+ selection.selecting_mode = Selection::MODE_NONE;
+ update();
+ }
+ }
+ } else {
+ selection.drag_attempt = false;
+ }
+ drag_action = false;
+ drag_caret_force_displayed = false;
+ dragging_minimap = false;
+ dragging_selection = false;
+ can_drag_minimap = false;
+ click_select_held->stop();
+ } break;
}
}
@@ -2484,6 +2519,7 @@ void TextEdit::_gui_input(const Ref &p_gui_input) {
cursor_set_line(row, false, false);
cursor_set_column(col);
+ selection.drag_attempt = false;
if (mb->get_shift() && (cursor.column != prev_col || cursor.line != prev_line)) {
if (!selection.active) {
@@ -2529,7 +2565,9 @@ void TextEdit::_gui_input(const Ref &p_gui_input) {
update();
}
-
+ } else if (is_mouse_over_selection()) {
+ selection.selecting_mode = Selection::MODE_NONE;
+ selection.drag_attempt = true;
} else {
selection.active = false;
selection.selecting_mode = Selection::MODE_POINTER;
@@ -2593,6 +2631,9 @@ void TextEdit::_gui_input(const Ref &p_gui_input) {
}
} else {
if (mb->get_button_index() == BUTTON_LEFT) {
+ if (selection.drag_attempt && selection.selecting_mode == Selection::MODE_NONE && is_mouse_over_selection()) {
+ selection.active = false;
+ }
if (mb->get_command() && highlighted_word != String()) {
int row, col;
_get_mouse_pos(Point2i(mb->get_position().x, mb->get_position().y), row, col);
@@ -2605,6 +2646,9 @@ void TextEdit::_gui_input(const Ref &p_gui_input) {
dragging_selection = false;
can_drag_minimap = false;
click_select_held->stop();
+ if (!drag_action) {
+ selection.drag_attempt = false;
+ }
}
// Notify to show soft keyboard.
@@ -2674,6 +2718,22 @@ void TextEdit::_gui_input(const Ref &p_gui_input) {
}
}
}
+
+ if (drag_action && can_drop_data(mm->get_position(), get_viewport()->gui_get_drag_data())) {
+ drag_caret_force_displayed = true;
+ Point2 mp = get_local_mouse_position();
+ int row, col;
+ _get_mouse_pos(Point2i(mp.x, mp.y), row, col);
+ cursor_set_line(row, true);
+ cursor_set_column(col);
+ if (row <= get_first_visible_line()) {
+ _scroll_lines_up();
+ } else if (row >= get_last_full_visible_line()) {
+ _scroll_lines_down();
+ }
+ dragging_selection = true;
+ update();
+ }
}
if (v_scroll->get_value() != prev_v_scroll || h_scroll->get_value() != prev_h_scroll) {
@@ -4963,6 +5023,104 @@ void TextEdit::insert_text_at_cursor(const String &p_text) {
update();
}
+Variant TextEdit::get_drag_data(const Point2 &p_point) {
+ if (selection.active && selection.drag_attempt) {
+ String t = get_selection_text();
+ Label *l = memnew(Label);
+ l->set_text(t);
+ set_drag_preview(l);
+ return t;
+ }
+
+ return Variant();
+}
+
+bool TextEdit::can_drop_data(const Point2 &p_point, const Variant &p_data) const {
+ bool drop_override = Control::can_drop_data(p_point, p_data); // In case user wants to drop custom data.
+ if (drop_override) {
+ return drop_override;
+ }
+
+ return !readonly && p_data.get_type() == Variant::STRING;
+}
+
+void TextEdit::drop_data(const Point2 &p_point, const Variant &p_data) {
+ Control::drop_data(p_point, p_data);
+
+ if (p_data.get_type() == Variant::STRING && !readonly) {
+ Point2 mp = get_local_mouse_position();
+ int caret_row_tmp, caret_column_tmp;
+ _get_mouse_pos(Point2i(mp.x, mp.y), caret_row_tmp, caret_column_tmp);
+ if (selection.drag_attempt) {
+ selection.drag_attempt = false;
+ if (!is_mouse_over_selection(!Input::get_singleton()->is_key_pressed(KEY_CONTROL))) {
+ begin_complex_operation();
+ if (!Input::get_singleton()->is_key_pressed(KEY_CONTROL)) {
+ if (caret_row_tmp > selection.to_line) {
+ caret_row_tmp = caret_row_tmp - (selection.to_line - selection.from_line);
+ } else if (caret_row_tmp == selection.to_line && caret_column_tmp >= selection.to_column) {
+ caret_column_tmp = caret_column_tmp - (selection.to_column - selection.from_column);
+ }
+
+ _remove_text(selection.from_line, selection.from_column, selection.to_line, selection.to_column);
+ cursor_set_line(selection.from_line, false);
+ cursor_set_column(selection.from_column);
+ selection.active = false;
+ selection.selecting_mode = Selection::MODE_NONE;
+ } else {
+ deselect();
+ }
+
+ cursor_set_line(caret_row_tmp, true, false);
+ cursor_set_column(caret_column_tmp);
+ insert_text_at_cursor(p_data);
+ end_complex_operation();
+ }
+ } else if (is_mouse_over_selection()) {
+ begin_complex_operation();
+ caret_row_tmp = selection.from_line;
+ caret_column_tmp = selection.from_column;
+
+ _remove_text(selection.from_line, selection.from_column, selection.to_line, selection.to_column);
+ cursor_set_line(selection.from_line, false);
+ cursor_set_column(selection.from_column);
+ selection.active = false;
+ selection.selecting_mode = Selection::MODE_NONE;
+
+ cursor_set_line(caret_row_tmp, true, false);
+ cursor_set_column(caret_column_tmp);
+ insert_text_at_cursor(p_data);
+ end_complex_operation();
+ grab_focus();
+ } else {
+ deselect();
+ cursor_set_line(caret_row_tmp, true, false);
+ cursor_set_column(caret_column_tmp);
+ insert_text_at_cursor(p_data);
+ grab_focus();
+ }
+
+ if (caret_row_tmp != cursor.line || caret_column_tmp != cursor.column) {
+ select(caret_row_tmp, caret_column_tmp, cursor.line, cursor.column);
+ }
+ }
+}
+
+bool TextEdit::is_mouse_over_selection(bool p_edges) const {
+ if (!selection.active) {
+ return false;
+ }
+ Point2 mp = get_local_mouse_position();
+ int row, col;
+ _get_mouse_pos(Point2i(mp.x, mp.y), row, col);
+ if (p_edges) {
+ if ((row == selection.from_line && col == selection.from_column) || (row == selection.to_line && col == selection.to_column)) {
+ return true;
+ }
+ }
+ return (row >= selection.from_line && row <= selection.to_line && (row > selection.from_line || col > selection.from_column) && (row < selection.to_line || col < selection.to_column));
+}
+
Control::CursorShape TextEdit::get_cursor_shape(const Point2 &p_pos) const {
if (highlighted_word != String()) {
return CURSOR_POINTING_HAND;
@@ -7274,6 +7432,7 @@ void TextEdit::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_selection_to_line"), &TextEdit::get_selection_to_line);
ClassDB::bind_method(D_METHOD("get_selection_to_column"), &TextEdit::get_selection_to_column);
ClassDB::bind_method(D_METHOD("get_selection_text"), &TextEdit::get_selection_text);
+ ClassDB::bind_method(D_METHOD("is_mouse_over_selection", "edges"), &TextEdit::is_mouse_over_selection);
ClassDB::bind_method(D_METHOD("get_word_under_cursor"), &TextEdit::get_word_under_cursor);
ClassDB::bind_method(D_METHOD("search", "key", "flags", "from_line", "from_column"), &TextEdit::_search_bind);
diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h
index cfbd67b7f12a..77744782efd9 100644
--- a/scene/gui/text_edit.h
+++ b/scene/gui/text_edit.h
@@ -192,6 +192,8 @@ class TextEdit : public Control {
int to_line, to_column;
bool shiftclick_left;
+ bool drag_attempt;
+
Selection() {
selecting_mode = MODE_NONE;
selecting_line = 0;
@@ -206,6 +208,7 @@ class TextEdit : public Control {
to_line = 0;
to_column = 0;
shiftclick_left = false;
+ drag_attempt = false;
}
} selection;
@@ -473,6 +476,9 @@ class TextEdit : public Control {
int get_char_pos_for(int p_px, String p_str) const;
int get_column_x_offset(int p_char, String p_str) const;
+ bool drag_action = false;
+ bool drag_caret_force_displayed = false;
+
void adjust_viewport_to_cursor();
void _scroll_moved(double);
void _update_scrollbars();
@@ -587,6 +593,9 @@ class TextEdit : public Control {
};
virtual CursorShape get_cursor_shape(const Point2 &p_pos = Point2i()) const;
+ virtual Variant get_drag_data(const Point2 &p_point);
+ virtual bool can_drop_data(const Point2 &p_point, const Variant &p_data) const;
+ virtual void drop_data(const Point2 &p_point, const Variant &p_data);
void _get_mouse_pos(const Point2i &p_mouse, int &r_row, int &r_col) const;
void _get_minimap_mouse_row(const Point2i &p_mouse, int &r_row) const;
@@ -723,6 +732,7 @@ class TextEdit : public Control {
int get_selection_to_line() const;
int get_selection_to_column() const;
String get_selection_text() const;
+ bool is_mouse_over_selection(bool p_edges = true) const;
String get_word_under_cursor() const;
String get_word_at_pos(const Vector2 &p_pos) const;
diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp
index b86d0441d812..27390f97437f 100644
--- a/scene/main/viewport.cpp
+++ b/scene/main/viewport.cpp
@@ -182,6 +182,7 @@ class TooltipLabel : public Label {
Viewport::GUI::GUI() {
dragging = false;
+ drag_successful = false;
mouse_focus = nullptr;
mouse_click_grabber = nullptr;
mouse_focus_mask = 0;
@@ -1968,8 +1969,9 @@ void Viewport::_gui_input_event(Ref p_event) {
if (gui.drag_data.get_type() != Variant::NIL && mb->get_button_index() == BUTTON_LEFT) {
//alternate drop use (when using force_drag(), as proposed by #5342
+ gui.drag_successful = false;
if (gui.mouse_focus) {
- _gui_drop(gui.mouse_focus, pos, false);
+ gui.drag_successful = _gui_drop(gui.mouse_focus, pos, false);
}
gui.drag_data = Variant();
@@ -1987,11 +1989,12 @@ void Viewport::_gui_input_event(Ref p_event) {
_gui_cancel_tooltip();
} else {
if (gui.drag_data.get_type() != Variant::NIL && mb->get_button_index() == BUTTON_LEFT) {
+ gui.drag_successful = false;
if (gui.mouse_over) {
Size2 pos = mpos;
pos = gui.focus_inv_xform.xform(pos);
- _gui_drop(gui.mouse_over, pos, false);
+ gui.drag_successful = _gui_drop(gui.mouse_over, pos, false);
}
Control *drag_preview = _gui_get_drag_preview();
@@ -3101,6 +3104,10 @@ bool Viewport::gui_is_dragging() const {
return gui.dragging;
}
+bool Viewport::gui_is_drag_successful() const {
+ return gui.drag_successful;
+}
+
void Viewport::set_input_as_handled() {
_drop_physics_mouseover();
if (handle_input_locally) {
@@ -3231,6 +3238,7 @@ void Viewport::_bind_methods() {
ClassDB::bind_method(D_METHOD("gui_has_modal_stack"), &Viewport::gui_has_modal_stack);
ClassDB::bind_method(D_METHOD("gui_get_drag_data"), &Viewport::gui_get_drag_data);
ClassDB::bind_method(D_METHOD("gui_is_dragging"), &Viewport::gui_is_dragging);
+ ClassDB::bind_method(D_METHOD("gui_is_drag_successful"), &Viewport::gui_is_drag_successful);
ClassDB::bind_method(D_METHOD("get_modal_stack_top"), &Viewport::get_modal_stack_top);
diff --git a/scene/main/viewport.h b/scene/main/viewport.h
index 77890f8147d8..80af5c79311d 100644
--- a/scene/main/viewport.h
+++ b/scene/main/viewport.h
@@ -321,6 +321,7 @@ class Viewport : public Node {
List roots;
int canvas_sort_index; //for sorting items with canvas as root
bool dragging;
+ bool drag_successful;
GUI();
} gui;
@@ -577,6 +578,7 @@ class Viewport : public Node {
bool is_handling_input_locally() const;
bool gui_is_dragging() const;
+ bool gui_is_drag_successful() const;
Viewport();
~Viewport();