From f0eddb8e6f46b51435743d02bd64b4c805635c0e Mon Sep 17 00:00:00 2001 From: aaronp64 Date: Fri, 8 Aug 2025 15:23:53 -0400 Subject: [PATCH] Fix issues searching RichTextLabel when search result is in a table Fixes for cases where search results would be skipped or repeatedly found involving tables in RichTextLabel: - If previous result was found in last cell of table, earlier cells would be skipped, since the end of the table was reached. Updated to not skip earlier cells when searching in reverse. - When choosing next line to continue from after searching table, the inner line number within the table's cell was added, causing the search to jump forward if not on line 0 in the cell. This could cause lines to get skipped when searching forward, or searching the table again when searching in reverse. Updated to continue from the immediate next line before/after the table. - If a table cell has multiple lines, repeated searching would only include the line where the previous result was found, then jump to the next cell. Updated to search remaining lines in the same cell first. --- scene/gui/rich_text_label.cpp | 59 +++++++++++++++++++++++++---------- scene/gui/rich_text_label.h | 3 +- 2 files changed, 44 insertions(+), 18 deletions(-) diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp index cd44219fc4d..dadc3b5b4b9 100644 --- a/scene/gui/rich_text_label.cpp +++ b/scene/gui/rich_text_label.cpp @@ -6591,23 +6591,36 @@ bool RichTextLabel::_is_click_inside_selection() const { } } +bool RichTextLabel::_search_table_cell(ItemTable *p_table, List::Element *p_cell, const String &p_string, bool p_reverse_search, int p_from_line) { + ERR_FAIL_COND_V(p_cell->get()->type != ITEM_FRAME, false); // Children should all be frames. + ItemFrame *frame = static_cast(p_cell->get()); + if (p_from_line < 0) { + p_from_line = (int)frame->lines.size() - 1; + } + + if (p_reverse_search) { + for (int i = p_from_line; i >= 0; i--) { + if (_search_line(frame, i, p_string, -1, p_reverse_search)) { + return true; + } + } + } else { + for (int i = p_from_line; i < (int)frame->lines.size(); i++) { + if (_search_line(frame, i, p_string, 0, p_reverse_search)) { + return true; + } + } + } + + return false; +} + bool RichTextLabel::_search_table(ItemTable *p_table, List::Element *p_from, const String &p_string, bool p_reverse_search) { List::Element *E = p_from; while (E != nullptr) { - ERR_CONTINUE(E->get()->type != ITEM_FRAME); // Children should all be frames. - ItemFrame *frame = static_cast(E->get()); - if (p_reverse_search) { - for (int i = (int)frame->lines.size() - 1; i >= 0; i--) { - if (_search_line(frame, i, p_string, -1, p_reverse_search)) { - return true; - } - } - } else { - for (int i = 0; i < (int)frame->lines.size(); i++) { - if (_search_line(frame, i, p_string, 0, p_reverse_search)) { - return true; - } - } + int from_line = p_reverse_search ? -1 : 0; + if (_search_table_cell(p_table, E, p_string, p_reverse_search, from_line)) { + return true; } E = p_reverse_search ? E->prev() : E->next(); } @@ -6695,7 +6708,8 @@ bool RichTextLabel::search(const String &p_string, bool p_from_selection, bool p char_idx = p_search_previous ? -1 : 0; // Next, check to see if the current search result is in a table - if (selection.from_frame->parent != nullptr && selection.from_frame->parent->type == ITEM_TABLE) { + bool in_table = selection.from_frame->parent != nullptr && selection.from_frame->parent->type == ITEM_TABLE; + if (in_table) { // Find last search result in table ItemTable *parent_table = static_cast(selection.from_frame->parent); List::Element *parent_element = p_search_previous ? parent_table->subitems.back() : parent_table->subitems.front(); @@ -6705,9 +6719,17 @@ bool RichTextLabel::search(const String &p_string, bool p_from_selection, bool p ERR_FAIL_NULL_V(parent_element, false); } + // Search remainder of current cell + int from_line = p_search_previous ? selection.from_line - 1 : selection.from_line + 1; + if (from_line >= 0 && _search_table_cell(parent_table, parent_element, p_string, p_search_previous, from_line)) { + scroll_to_selection(); + queue_redraw(); + return true; + } + // Search remainder of table if (!(p_search_previous && parent_element == parent_table->subitems.front()) && - parent_element != parent_table->subitems.back()) { + !(!p_search_previous && parent_element == parent_table->subitems.back())) { parent_element = p_search_previous ? parent_element->prev() : parent_element->next(); // Don't want to search current item ERR_FAIL_NULL_V(parent_element, false); @@ -6720,7 +6742,10 @@ bool RichTextLabel::search(const String &p_string, bool p_from_selection, bool p } } - ending_line = selection.from_frame->line + selection.from_line; + ending_line = selection.from_frame->line; + if (!in_table) { + ending_line += selection.from_line; + } current_line = p_search_previous ? ending_line - 1 : ending_line + 1; } else if (p_search_previous) { current_line = ending_line; diff --git a/scene/gui/rich_text_label.h b/scene/gui/rich_text_label.h index 6fe9883bc5e..04879be5648 100644 --- a/scene/gui/rich_text_label.h +++ b/scene/gui/rich_text_label.h @@ -631,8 +631,9 @@ private: 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, bool p_meta = false); String _get_line_text(ItemFrame *p_frame, int p_line, Selection p_sel) const; - bool _search_line(ItemFrame *p_frame, int p_line, const String &p_string, int p_char_idx, bool p_reverse_search); + bool _search_table_cell(ItemTable *p_table, List::Element *p_cell, const String &p_string, bool p_reverse_search, int p_from_line); bool _search_table(ItemTable *p_table, List::Element *p_from, const String &p_string, bool p_reverse_search); + bool _search_line(ItemFrame *p_frame, int p_line, const String &p_string, int p_char_idx, bool p_reverse_search); float _shape_line(ItemFrame *p_frame, int p_line, const Ref &p_base_font, int p_base_font_size, int p_width, float p_h, int *r_char_offset); float _resize_line(ItemFrame *p_frame, int p_line, const Ref &p_base_font, int p_base_font_size, int p_width, float p_h);