Browse Source

Merge pull request #62774 from Rindbee/make-the-meta-click-area-fit

Make the meta click area fit to its visible area
Rémi Verschelde 3 years ago
parent
commit
c17af2c5a3
2 changed files with 53 additions and 13 deletions
  1. 52 13
      scene/gui/rich_text_label.cpp
  2. 1 0
      scene/gui/rich_text_label.h

+ 52 - 13
scene/gui/rich_text_label.cpp

@@ -149,7 +149,12 @@ RichTextLabel::Item *RichTextLabel::_get_item_at_pos(RichTextLabel::Item *p_item
 					return it;
 				}
 			} break;
-			case ITEM_NEWLINE:
+			case ITEM_NEWLINE: {
+				offset += 1;
+				if (offset == p_position) {
+					return it;
+				}
+			} break;
 			case ITEM_IMAGE:
 			case ITEM_TABLE: {
 				offset += 1;
@@ -1344,6 +1349,8 @@ void RichTextLabel::_find_click(ItemFrame *p_frame, const Point2i &p_click, Item
 float RichTextLabel::_find_click_in_line(ItemFrame *p_frame, int p_line, const Vector2 &p_ofs, int p_width, const Point2i &p_click, ItemFrame **r_click_frame, int *r_click_line, Item **r_click_item, int *r_click_char, bool p_table) {
 	Vector2 off;
 
+	bool line_clicked = false;
+	float text_rect_begin = 0.0;
 	int char_pos = -1;
 	Line &l = p_frame->lines[p_line];
 	MutexLock lock(l.text_buf->get_mutex());
@@ -1469,7 +1476,11 @@ float RichTextLabel::_find_click_in_line(ItemFrame *p_frame, int p_line, const V
 		}
 
 		if (p_click.y >= rect.position.y && p_click.y <= rect.position.y + rect.size.y) {
-			char_pos = TS->shaped_text_hit_test_position(rid, p_click.x - rect.position.x);
+			if ((!rtl && p_click.x >= rect.position.x) || (rtl && p_click.x <= rect.position.x + rect.size.x)) {
+				char_pos = TS->shaped_text_hit_test_position(rid, p_click.x - rect.position.x);
+			}
+			line_clicked = true;
+			text_rect_begin = rtl ? rect.position.x + rect.size.x : rect.position.x;
 		}
 
 		// If table hit was detected, and line hit is in the table bounds use table hit.
@@ -1496,23 +1507,38 @@ float RichTextLabel::_find_click_in_line(ItemFrame *p_frame, int p_line, const V
 	}
 
 	// Text line hit.
-	if (char_pos >= 0) {
+	if (line_clicked) {
 		// Find item.
 		if (r_click_item != nullptr) {
 			Item *it = p_frame->lines[p_line].from;
 			Item *it_to = (p_line + 1 < (int)p_frame->lines.size()) ? p_frame->lines[p_line + 1].from : nullptr;
-			if (char_pos == p_frame->lines[p_line].char_count) {
-				// Selection after the end of line, select last item.
-				if (it_to != nullptr) {
-					*r_click_item = _get_prev_item(it_to);
-				} else {
-					for (Item *i = it; i; i = _get_next_item(i)) {
-						*r_click_item = i;
+			if (char_pos >= 0) {
+				*r_click_item = _get_item_at_pos(it, it_to, char_pos);
+			} else {
+				int stop = text_rect_begin;
+				*r_click_item = _find_indentable(it);
+				while (*r_click_item) {
+					Ref<Font> font = _find_font(*r_click_item);
+					if (!font.is_valid()) {
+						font = get_theme_font(SNAME("normal_font"));
+					}
+					int font_size = _find_font_size(*r_click_item);
+					if (font_size == -1) {
+						font_size = get_theme_font_size(SNAME("normal_font_size"));
+					}
+					if (rtl) {
+						stop += tab_size * font->get_char_size(' ', font_size).width;
+						if (stop > p_click.x) {
+							break;
+						}
+					} else {
+						stop -= tab_size * font->get_char_size(' ', font_size).width;
+						if (stop < p_click.x) {
+							break;
+						}
 					}
+					*r_click_item = _find_indentable((*r_click_item)->parent);
 				}
-			} else {
-				// Selection in the line.
-				*r_click_item = _get_item_at_pos(it, it_to, char_pos);
 			}
 		}
 
@@ -2069,6 +2095,19 @@ void RichTextLabel::_find_frame(Item *p_item, ItemFrame **r_frame, int *r_line)
 	}
 }
 
+RichTextLabel::Item *RichTextLabel::_find_indentable(Item *p_item) {
+	Item *indentable = p_item;
+
+	while (indentable) {
+		if (indentable->type == ITEM_INDENT || indentable->type == ITEM_LIST) {
+			return indentable;
+		}
+		indentable = indentable->parent;
+	}
+
+	return indentable;
+}
+
 Ref<Font> RichTextLabel::_find_font(Item *p_item) {
 	Item *fontitem = p_item;
 

+ 1 - 0
scene/gui/rich_text_label.h

@@ -459,6 +459,7 @@ private:
 	String _roman(int p_num, bool p_capitalize) const;
 	String _letters(int p_num, bool p_capitalize) const;
 
+	Item *_find_indentable(Item *p_item);
 	Item *_get_item_at_pos(Item *p_item_from, Item *p_item_to, int p_position);
 	void _find_frame(Item *p_item, ItemFrame **r_frame, int *r_line);
 	int _find_font_size(Item *p_item);