Sfoglia il codice sorgente

Merge pull request #55207 from ConteZero/rich_text_label_drag

Rémi Verschelde 3 anni fa
parent
commit
9abf5f01fd
2 ha cambiato i file con 66 aggiunte e 11 eliminazioni
  1. 63 11
      scene/gui/rich_text_label.cpp
  2. 3 0
      scene/gui/rich_text_label.h

+ 63 - 11
scene/gui/rich_text_label.cpp

@@ -33,6 +33,7 @@
 #include "core/math/math_defs.h"
 #include "core/math/math_defs.h"
 #include "core/os/keyboard.h"
 #include "core/os/keyboard.h"
 #include "core/os/os.h"
 #include "core/os/os.h"
+#include "label.h"
 #include "scene/scene_string_names.h"
 #include "scene/scene_string_names.h"
 #include "servers/display_server.h"
 #include "servers/display_server.h"
 
 
@@ -1590,6 +1591,9 @@ void RichTextLabel::_notification(int p_what) {
 				update();
 				update();
 			}
 			}
 		} break;
 		} break;
+		case NOTIFICATION_DRAG_END: {
+			selection.drag_attempt = false;
+		} break;
 	}
 	}
 }
 }
 
 
@@ -1650,6 +1654,8 @@ void RichTextLabel::gui_input(const Ref<InputEvent> &p_event) {
 				int c_index = 0;
 				int c_index = 0;
 				bool outside;
 				bool outside;
 
 
+				selection.drag_attempt = false;
+
 				_find_click(main, b->get_position(), &c_frame, &c_line, &c_item, &c_index, &outside);
 				_find_click(main, b->get_position(), &c_frame, &c_line, &c_item, &c_index, &outside);
 				if (c_item != nullptr) {
 				if (c_item != nullptr) {
 					if (selection.enabled) {
 					if (selection.enabled) {
@@ -1660,17 +1666,22 @@ void RichTextLabel::gui_input(const Ref<InputEvent> &p_event) {
 
 
 						// Erase previous selection.
 						// Erase previous selection.
 						if (selection.active) {
 						if (selection.active) {
-							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 (_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;
+								selection.from_char = 0;
+								selection.to_frame = nullptr;
+								selection.to_line = 0;
+								selection.to_item = nullptr;
+								selection.to_char = 0;
+								selection.active = false;
+
+								update();
+							}
 						}
 						}
 					}
 					}
 				}
 				}
@@ -1683,6 +1694,8 @@ void RichTextLabel::gui_input(const Ref<InputEvent> &p_event) {
 				int c_index = 0;
 				int c_index = 0;
 				bool outside;
 				bool outside;
 
 
+				selection.drag_attempt = false;
+
 				_find_click(main, b->get_position(), &c_frame, &c_line, &c_item, &c_index, &outside);
 				_find_click(main, b->get_position(), &c_frame, &c_line, &c_item, &c_index, &outside);
 
 
 				if (c_frame) {
 				if (c_frame) {
@@ -1714,6 +1727,22 @@ void RichTextLabel::gui_input(const Ref<InputEvent> &p_event) {
 					DisplayServer::get_singleton()->clipboard_set_primary(get_selected_text());
 					DisplayServer::get_singleton()->clipboard_set_primary(get_selected_text());
 				}
 				}
 				selection.click_item = nullptr;
 				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) {
 				if (!b->is_double_click() && !scroll_updated) {
 					Item *c_item = nullptr;
 					Item *c_item = nullptr;
@@ -3734,6 +3763,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) {
 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;
 	List<Item *>::Element *E = p_from;
 	while (E != nullptr) {
 	while (E != nullptr) {

+ 3 - 0
scene/gui/rich_text_label.h

@@ -407,6 +407,7 @@ private:
 
 
 		bool active = false; // anything selected? i.e. from, to, etc. valid?
 		bool active = false; // anything selected? i.e. from, to, etc. valid?
 		bool enabled = false; // allow selections?
 		bool enabled = false; // allow selections?
+		bool drag_attempt = false;
 	};
 	};
 
 
 	Selection selection;
 	Selection selection;
@@ -416,6 +417,7 @@ private:
 	float percent_visible = 1.0;
 	float percent_visible = 1.0;
 	VisibleCharactersBehavior visible_chars_behavior = VC_CHARS_BEFORE_SHAPING;
 	VisibleCharactersBehavior visible_chars_behavior = VC_CHARS_BEFORE_SHAPING;
 
 
+	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);
 	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;
 	String _get_line_text(ItemFrame *p_frame, int p_line, Selection p_sel) const;
@@ -559,6 +561,7 @@ public:
 	VScrollBar *get_v_scroll_bar() { return vscroll; }
 	VScrollBar *get_v_scroll_bar() { return vscroll; }
 
 
 	virtual CursorShape get_cursor_shape(const Point2 &p_pos) const override;
 	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);
 	void set_selection_enabled(bool p_enabled);
 	bool is_selection_enabled() const;
 	bool is_selection_enabled() const;