Add drag to RichTextLabel

This commit is contained in:
ConteZero 2021-11-21 19:26:15 +01:00
parent 0e26152392
commit cb222f6c9d
2 changed files with 65 additions and 10 deletions

View File

@ -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"
#include "servers/display_server.h"
@ -1501,6 +1502,9 @@ void RichTextLabel::_notification(int p_what) {
update();
}
} break;
case NOTIFICATION_DRAG_END: {
selection.drag_attempt = false;
} break;
}
}
@ -1554,6 +1558,8 @@ void RichTextLabel::gui_input(const Ref<InputEvent> &p_event) {
int c_index = 0;
bool outside;
selection.drag_attempt = false;
_find_click(main, b->get_position(), &c_frame, &c_line, &c_item, &c_index, &outside);
if (c_item != nullptr) {
if (selection.enabled) {
@ -1564,6 +1570,10 @@ void RichTextLabel::gui_input(const Ref<InputEvent> &p_event) {
// Erase previous selection.
if (selection.active) {
if (_is_click_inside_selection()) {
selection.drag_attempt = true;
selection.click_item = nullptr;
} else {
selection.from_frame = nullptr;
selection.from_line = 0;
selection.from_item = nullptr;
@ -1578,6 +1588,7 @@ void RichTextLabel::gui_input(const Ref<InputEvent> &p_event) {
}
}
}
}
} else if (b->is_pressed() && b->is_double_click() && selection.enabled) {
//double_click: select word
@ -1587,6 +1598,8 @@ void RichTextLabel::gui_input(const Ref<InputEvent> &p_event) {
int c_index = 0;
bool outside;
selection.drag_attempt = false;
_find_click(main, b->get_position(), &c_frame, &c_line, &c_item, &c_index, &outside);
if (c_frame) {
@ -1618,6 +1631,22 @@ void RichTextLabel::gui_input(const Ref<InputEvent> &p_event) {
DisplayServer::get_singleton()->clipboard_set_primary(get_selected_text());
}
selection.click_item = nullptr;
if (selection.drag_attempt) {
selection.drag_attempt = false;
if (_is_click_inside_selection()) {
selection.from_frame = nullptr;
selection.from_line = 0;
selection.from_item = nullptr;
selection.from_char = 0;
selection.to_frame = nullptr;
selection.to_line = 0;
selection.to_item = nullptr;
selection.to_char = 0;
selection.active = false;
update();
}
}
if (!b->is_double_click() && !scroll_updated) {
Item *c_item = nullptr;
@ -3626,6 +3655,29 @@ 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 {
if (selection.active && selection.enabled && selection.click_frame && selection.from_frame && selection.to_frame) {
const Line &l_click = selection.click_frame->lines[selection.click_line];
const Line &l_from = selection.from_frame->lines[selection.from_line];
const Line &l_to = selection.to_frame->lines[selection.to_line];
return (l_click.char_offset + selection.click_char >= l_from.char_offset + selection.from_char) && (l_click.char_offset + selection.click_char <= l_to.char_offset + selection.to_char);
} else {
return false;
}
}
bool RichTextLabel::_search_table(ItemTable *p_table, List<Item *>::Element *p_from, const String &p_string, bool p_reverse_search) {
List<Item *>::Element *E = p_from;
while (E != nullptr) {

View File

@ -396,6 +396,7 @@ private:
bool active = false; // anything selected? i.e. from, to, etc. valid?
bool enabled = false; // allow selections?
bool drag_attempt = false;
};
Selection selection;
@ -404,6 +405,7 @@ private:
int visible_characters = -1;
float percent_visible = 1.0;
bool _is_click_inside_selection() const;
void _find_click(ItemFrame *p_frame, const Point2i &p_click, ItemFrame **r_click_frame = nullptr, int *r_click_line = nullptr, Item **r_click_item = nullptr, int *r_click_char = nullptr, bool *r_outside = nullptr);
String _get_line_text(ItemFrame *p_frame, int p_line, Selection p_sel) const;
@ -545,6 +547,7 @@ public:
VScrollBar *get_v_scroll() { return vscroll; }
virtual CursorShape get_cursor_shape(const Point2 &p_pos) const override;
virtual Variant get_drag_data(const Point2 &p_point) override;
void set_selection_enabled(bool p_enabled);
bool is_selection_enabled() const;