|
@@ -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;
|
|
|
|