mirror of
https://github.com/Relintai/pandemonium_engine.git
synced 2024-12-23 20:36:53 +01:00
Ported: Add drag and drop to TextEdit, LineEdit, RichTextLabel - ConteZero
4167e98088
This commit is contained in:
parent
c8adff0f99
commit
a43091d427
@ -432,6 +432,12 @@
|
||||
<description>
|
||||
</description>
|
||||
</method>
|
||||
<method name="is_drag_successful" qualifiers="const">
|
||||
<return type="bool" />
|
||||
<description>
|
||||
Returns [code]true[/code] if drag operation is successful.
|
||||
</description>
|
||||
</method>
|
||||
<method name="minimum_size_changed">
|
||||
<return type="void" />
|
||||
<description>
|
||||
|
@ -325,6 +325,13 @@
|
||||
Returns if the given line is wrapped.
|
||||
</description>
|
||||
</method>
|
||||
<method name="is_mouse_over_selection" qualifiers="const">
|
||||
<return type="bool" />
|
||||
<argument index="0" name="edges" type="bool" />
|
||||
<description>
|
||||
Returns whether the mouse is over selection. If [code]edges[/code] is [code]true[/code], the edges are considered part of the selection.
|
||||
</description>
|
||||
</method>
|
||||
<method name="is_selection_active" qualifiers="const">
|
||||
<return type="bool" />
|
||||
<description>
|
||||
|
@ -114,6 +114,12 @@
|
||||
Returns [code]true[/code] if there are visible modals on-screen.
|
||||
</description>
|
||||
</method>
|
||||
<method name="gui_is_drag_successful" qualifiers="const">
|
||||
<return type="bool" />
|
||||
<description>
|
||||
Returns [code]true[/code] if the drag operation is successful.
|
||||
</description>
|
||||
</method>
|
||||
<method name="gui_is_dragging" qualifiers="const">
|
||||
<return type="bool" />
|
||||
<description>
|
||||
|
@ -772,6 +772,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;
|
||||
@ -2759,6 +2763,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);
|
||||
|
||||
|
@ -318,6 +318,7 @@ public:
|
||||
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;
|
||||
|
@ -31,6 +31,7 @@
|
||||
#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"
|
||||
@ -39,6 +40,7 @@
|
||||
#include "scene/gui/popup_menu.h"
|
||||
#include "scene/gui/shortcut.h"
|
||||
#include "scene/main/timer.h"
|
||||
#include "scene/main/viewport.h"
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
#include "editor/editor_scale.h"
|
||||
@ -83,7 +85,9 @@ void LineEdit::_gui_input(Ref<InputEvent> 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);
|
||||
|
||||
@ -128,7 +132,7 @@ void LineEdit::_gui_input(Ref<InputEvent> 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;
|
||||
}
|
||||
}
|
||||
@ -151,6 +155,10 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) {
|
||||
selection.creating = false;
|
||||
selection.doubleclick = false;
|
||||
|
||||
if (!drag_action) {
|
||||
selection.drag_attempt = false;
|
||||
}
|
||||
|
||||
show_virtual_keyboard();
|
||||
}
|
||||
|
||||
@ -174,6 +182,11 @@ void LineEdit::_gui_input(Ref<InputEvent> 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<InputEventKey> k = p_event;
|
||||
@ -647,28 +660,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;
|
||||
|
||||
Ref<Font> 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;
|
||||
}
|
||||
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();
|
||||
}
|
||||
|
||||
text.erase(selection.begin, selected);
|
||||
|
||||
append_at_cursor(p_data);
|
||||
selection.begin = cursor_pos - selected;
|
||||
selection.end = cursor_pos;
|
||||
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();
|
||||
}
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
@ -924,7 +959,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) {
|
||||
@ -996,6 +1031,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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1052,6 +1106,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;
|
||||
@ -1070,9 +1127,13 @@ void LineEdit::redo() {
|
||||
if (undo_stack_pos == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
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;
|
||||
@ -1988,6 +2049,10 @@ LineEdit::LineEdit() {
|
||||
selecting_enabled = true;
|
||||
deselect_on_focus_loss_enabled = true;
|
||||
popup_show = false;
|
||||
virtual_keyboard_enabled = true;
|
||||
|
||||
drag_action = false;
|
||||
drag_caret_force_displayed = false;
|
||||
|
||||
undo_stack_pos = nullptr;
|
||||
_create_undo_state();
|
||||
|
@ -92,7 +92,10 @@ private:
|
||||
|
||||
bool shortcut_keys_enabled;
|
||||
|
||||
bool virtual_keyboard_enabled = true;
|
||||
bool virtual_keyboard_enabled;
|
||||
|
||||
bool drag_action;
|
||||
bool drag_caret_force_displayed;
|
||||
|
||||
Ref<Texture> right_icon;
|
||||
|
||||
|
@ -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/gui/scroll_bar.h"
|
||||
#include "scene/scene_string_names.h"
|
||||
|
||||
@ -1071,6 +1072,9 @@ void RichTextLabel::_notification(int p_what) {
|
||||
update();
|
||||
}
|
||||
} break;
|
||||
case Control::NOTIFICATION_DRAG_END: {
|
||||
selection.drag_attempt = false;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1153,6 +1157,9 @@ void RichTextLabel::_gui_input(Ref<InputEvent> p_event) {
|
||||
Item *item = nullptr;
|
||||
|
||||
bool outside;
|
||||
|
||||
selection.drag_attempt = false;
|
||||
|
||||
_find_click(main, b->get_position(), &item, &line, &outside);
|
||||
|
||||
if (item) {
|
||||
@ -1162,13 +1169,18 @@ void RichTextLabel::_gui_input(Ref<InputEvent> 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;
|
||||
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();
|
||||
update();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1178,6 +1190,8 @@ void RichTextLabel::_gui_input(Ref<InputEvent> 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) {
|
||||
@ -1198,6 +1212,26 @@ void RichTextLabel::_gui_input(Ref<InputEvent> 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) {
|
||||
@ -2515,6 +2549,22 @@ void RichTextLabel::set_deselect_on_focus_loss_enabled(const 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;
|
||||
@ -3033,6 +3083,7 @@ RichTextLabel::RichTextLabel() {
|
||||
selection.click = nullptr;
|
||||
selection.active = false;
|
||||
selection.enabled = false;
|
||||
selection.drag_attempt = false;
|
||||
deselect_on_focus_loss_enabled = true;
|
||||
|
||||
visible_characters = -1;
|
||||
|
@ -360,6 +360,7 @@ private:
|
||||
|
||||
bool active; // anything selected? i.e. from, to, etc. valid?
|
||||
bool enabled; // allow selections?
|
||||
bool drag_attempt;
|
||||
};
|
||||
|
||||
Selection selection;
|
||||
@ -368,6 +369,7 @@ private:
|
||||
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<Font> &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);
|
||||
|
||||
@ -468,6 +470,7 @@ public:
|
||||
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;
|
||||
|
@ -36,6 +36,7 @@
|
||||
#include "core/os/os.h"
|
||||
#include "core/project_settings.h"
|
||||
#include "core/script_language.h"
|
||||
#include "label.h"
|
||||
#include "scene/gui/popup_menu.h"
|
||||
#include "scene/gui/scroll_bar.h"
|
||||
#include "scene/gui/shortcut.h"
|
||||
@ -436,6 +437,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();
|
||||
|
||||
@ -452,6 +454,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();
|
||||
|
||||
@ -509,6 +512,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();
|
||||
|
||||
@ -1508,7 +1512,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;
|
||||
@ -1614,7 +1618,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
|
||||
@ -1905,6 +1909,37 @@ void TextEdit::_notification(int p_what) {
|
||||
deselect();
|
||||
}
|
||||
} 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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2498,6 +2533,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &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) {
|
||||
@ -2544,6 +2580,9 @@ void TextEdit::_gui_input(const Ref<InputEvent> &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;
|
||||
@ -2607,6 +2646,10 @@ void TextEdit::_gui_input(const Ref<InputEvent> &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);
|
||||
@ -2619,6 +2662,10 @@ void TextEdit::_gui_input(const Ref<InputEvent> &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.
|
||||
@ -2634,6 +2681,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
|
||||
} else {
|
||||
_scroll_down(delta);
|
||||
}
|
||||
|
||||
h_scroll->set_value(h_scroll->get_value() + pan_gesture->get_delta().x * 100);
|
||||
if (v_scroll->get_value() != prev_v_scroll || h_scroll->get_value() != prev_h_scroll) {
|
||||
accept_event(); // Accept event if scroll changed.
|
||||
@ -2688,6 +2736,22 @@ void TextEdit::_gui_input(const Ref<InputEvent> &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) {
|
||||
@ -4981,6 +5045,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;
|
||||
@ -7305,6 +7467,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);
|
||||
|
||||
@ -7459,6 +7622,9 @@ TextEdit::TextEdit() {
|
||||
cache.info_gutter_width = 0;
|
||||
set_default_cursor_shape(CURSOR_IBEAM);
|
||||
|
||||
drag_action = false;
|
||||
drag_caret_force_displayed = false;
|
||||
|
||||
indent_size = 4;
|
||||
text.set_indent_size(indent_size);
|
||||
text.clear();
|
||||
|
@ -192,6 +192,8 @@ private:
|
||||
int to_line, to_column;
|
||||
|
||||
bool shiftclick_left;
|
||||
bool drag_attempt;
|
||||
|
||||
Selection() {
|
||||
selecting_mode = MODE_NONE;
|
||||
selecting_line = 0;
|
||||
@ -206,6 +208,7 @@ private:
|
||||
to_line = 0;
|
||||
to_column = 0;
|
||||
shiftclick_left = false;
|
||||
drag_attempt = false;
|
||||
}
|
||||
} selection;
|
||||
|
||||
@ -475,6 +478,9 @@ private:
|
||||
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;
|
||||
bool drag_caret_force_displayed;
|
||||
|
||||
void adjust_viewport_to_cursor();
|
||||
void _scroll_moved(double);
|
||||
void _update_scrollbars();
|
||||
@ -589,6 +595,9 @@ public:
|
||||
};
|
||||
|
||||
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;
|
||||
@ -725,6 +734,7 @@ public:
|
||||
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;
|
||||
|
@ -186,6 +186,7 @@ public:
|
||||
|
||||
Viewport::GUI::GUI() {
|
||||
dragging = false;
|
||||
drag_successful = false;
|
||||
mouse_focus = nullptr;
|
||||
mouse_click_grabber = nullptr;
|
||||
mouse_focus_mask = 0;
|
||||
@ -1975,8 +1976,10 @@ void Viewport::_gui_input_event(Ref<InputEvent> 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();
|
||||
@ -1994,11 +1997,12 @@ void Viewport::_gui_input_event(Ref<InputEvent> 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();
|
||||
@ -3135,6 +3139,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) {
|
||||
@ -3265,6 +3273,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);
|
||||
|
||||
|
@ -322,6 +322,7 @@ private:
|
||||
List<Control *> roots;
|
||||
int canvas_sort_index; //for sorting items with canvas as root
|
||||
bool dragging;
|
||||
bool drag_successful;
|
||||
|
||||
GUI();
|
||||
} gui;
|
||||
@ -579,6 +580,7 @@ public:
|
||||
bool is_handling_input_locally() const;
|
||||
|
||||
bool gui_is_dragging() const;
|
||||
bool gui_is_drag_successful() const;
|
||||
|
||||
Viewport();
|
||||
~Viewport();
|
||||
|
Loading…
Reference in New Issue
Block a user