|
@@ -3452,7 +3452,30 @@ void RichTextLabel::set_selection_enabled(bool p_enabled) {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-bool RichTextLabel::_search_line(ItemFrame *p_frame, int p_line, const String &p_string, Item *p_from, Item *p_to) {
|
|
|
|
|
|
+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) {
|
|
|
|
+ ERR_CONTINUE(E->get()->type != ITEM_FRAME); // Children should all be frames.
|
|
|
|
+ ItemFrame *frame = static_cast<ItemFrame *>(E->get());
|
|
|
|
+ if (p_reverse_search) {
|
|
|
|
+ for (int i = 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 < frame->lines.size(); i++) {
|
|
|
|
+ if (_search_line(frame, i, p_string, 0, p_reverse_search)) {
|
|
|
|
+ return true;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ E = p_reverse_search ? E->prev() : E->next();
|
|
|
|
+ }
|
|
|
|
+ return false;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+bool RichTextLabel::_search_line(ItemFrame *p_frame, int p_line, const String &p_string, int p_char_idx, bool p_reverse_search) {
|
|
ERR_FAIL_COND_V(p_frame == nullptr, false);
|
|
ERR_FAIL_COND_V(p_frame == nullptr, false);
|
|
ERR_FAIL_COND_V(p_line < 0 || p_line >= p_frame->lines.size(), false);
|
|
ERR_FAIL_COND_V(p_line < 0 || p_line >= p_frame->lines.size(), false);
|
|
|
|
|
|
@@ -3474,24 +3497,23 @@ bool RichTextLabel::_search_line(ItemFrame *p_frame, int p_line, const String &p
|
|
} break;
|
|
} break;
|
|
case ITEM_TABLE: {
|
|
case ITEM_TABLE: {
|
|
ItemTable *table = static_cast<ItemTable *>(it);
|
|
ItemTable *table = static_cast<ItemTable *>(it);
|
|
- int idx = 0;
|
|
|
|
- for (List<Item *>::Element *E = table->subitems.front(); E; E = E->next()) {
|
|
|
|
- ERR_CONTINUE(E->get()->type != ITEM_FRAME); // Children should all be frames.
|
|
|
|
- ItemFrame *frame = static_cast<ItemFrame *>(E->get());
|
|
|
|
-
|
|
|
|
- for (int i = 0; i < frame->lines.size(); i++) {
|
|
|
|
- if (_search_line(frame, i, p_string, p_from, p_to)) {
|
|
|
|
- return true;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- idx++;
|
|
|
|
|
|
+ List<Item *>::Element *E = p_reverse_search ? table->subitems.back() : table->subitems.front();
|
|
|
|
+ if (_search_table(table, E, p_string, p_reverse_search)) {
|
|
|
|
+ return true;
|
|
}
|
|
}
|
|
} break;
|
|
} break;
|
|
default:
|
|
default:
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
- int sp = text.findn(p_string, 0);
|
|
|
|
|
|
+
|
|
|
|
+ int sp = -1;
|
|
|
|
+ if (p_reverse_search) {
|
|
|
|
+ sp = text.rfindn(p_string, p_char_idx);
|
|
|
|
+ } else {
|
|
|
|
+ sp = text.findn(p_string, p_char_idx);
|
|
|
|
+ }
|
|
|
|
+
|
|
if (sp != -1) {
|
|
if (sp != -1) {
|
|
selection.from_frame = p_frame;
|
|
selection.from_frame = p_frame;
|
|
selection.from_line = p_line;
|
|
selection.from_line = p_line;
|
|
@@ -3499,8 +3521,8 @@ bool RichTextLabel::_search_line(ItemFrame *p_frame, int p_line, const String &p
|
|
selection.from_char = sp;
|
|
selection.from_char = sp;
|
|
selection.to_frame = p_frame;
|
|
selection.to_frame = p_frame;
|
|
selection.to_line = p_line;
|
|
selection.to_line = p_line;
|
|
- selection.to_item = _get_item_at_pos(l.from, it_to, sp + p_string.length() - 1);
|
|
|
|
- selection.to_char = sp + p_string.length() - 1;
|
|
|
|
|
|
+ selection.to_item = _get_item_at_pos(l.from, it_to, sp + p_string.length());
|
|
|
|
+ selection.to_char = sp + p_string.length();
|
|
selection.active = true;
|
|
selection.active = true;
|
|
return true;
|
|
return true;
|
|
}
|
|
}
|
|
@@ -3511,23 +3533,81 @@ bool RichTextLabel::_search_line(ItemFrame *p_frame, int p_line, const String &p
|
|
bool RichTextLabel::search(const String &p_string, bool p_from_selection, bool p_search_previous) {
|
|
bool RichTextLabel::search(const String &p_string, bool p_from_selection, bool p_search_previous) {
|
|
ERR_FAIL_COND_V(!selection.enabled, false);
|
|
ERR_FAIL_COND_V(!selection.enabled, false);
|
|
|
|
|
|
|
|
+ if (p_string.size() == 0) {
|
|
|
|
+ selection.active = false;
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ int char_idx = p_search_previous ? -1 : 0;
|
|
|
|
+ int current_line = 0;
|
|
|
|
+ int ending_line = main->lines.size() - 1;
|
|
if (p_from_selection && selection.active) {
|
|
if (p_from_selection && selection.active) {
|
|
- for (int i = 0; i < main->lines.size(); i++) {
|
|
|
|
- if (_search_line(main, i, p_string, selection.from_item, selection.to_item)) {
|
|
|
|
- update();
|
|
|
|
- return true;
|
|
|
|
- }
|
|
|
|
|
|
+ // First check to see if other results exist in current line
|
|
|
|
+ char_idx = p_search_previous ? selection.from_char - 1 : selection.to_char;
|
|
|
|
+ if (!(p_search_previous && char_idx < 0) &&
|
|
|
|
+ _search_line(selection.from_frame, selection.from_line, p_string, char_idx, p_search_previous)) {
|
|
|
|
+ scroll_to_line(selection.from_frame->line + selection.from_line);
|
|
|
|
+ update();
|
|
|
|
+ return true;
|
|
}
|
|
}
|
|
- } else {
|
|
|
|
- for (int i = 0; i < main->lines.size(); i++) {
|
|
|
|
- if (_search_line(main, i, p_string, nullptr, nullptr)) {
|
|
|
|
- update();
|
|
|
|
- return true;
|
|
|
|
|
|
+ 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) {
|
|
|
|
+ // Find last search result in table
|
|
|
|
+ ItemTable *parent_table = static_cast<ItemTable *>(selection.from_frame->parent);
|
|
|
|
+ List<Item *>::Element *parent_element = p_search_previous ? parent_table->subitems.back() : parent_table->subitems.front();
|
|
|
|
+
|
|
|
|
+ while (parent_element->get() != selection.from_frame) {
|
|
|
|
+ parent_element = p_search_previous ? parent_element->prev() : parent_element->next();
|
|
|
|
+ ERR_FAIL_COND_V(parent_element == nullptr, false);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // Search remainder of table
|
|
|
|
+ if (!(p_search_previous && parent_element == parent_table->subitems.front()) &&
|
|
|
|
+ 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_COND_V(parent_element == nullptr, false);
|
|
|
|
+
|
|
|
|
+ // Search for next element
|
|
|
|
+ if (_search_table(parent_table, parent_element, p_string, p_search_previous)) {
|
|
|
|
+ scroll_to_line(selection.from_frame->line + selection.from_line);
|
|
|
|
+ update();
|
|
|
|
+ return true;
|
|
|
|
+ }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ ending_line = selection.from_frame->line + selection.from_line;
|
|
|
|
+ current_line = p_search_previous ? ending_line - 1 : ending_line + 1;
|
|
|
|
+ } else if (p_search_previous) {
|
|
|
|
+ current_line = ending_line;
|
|
|
|
+ ending_line = 0;
|
|
}
|
|
}
|
|
|
|
|
|
- return false;
|
|
|
|
|
|
+ // Search remainder of the file
|
|
|
|
+ while (current_line != ending_line) {
|
|
|
|
+ // Wrap around
|
|
|
|
+ if (current_line < 0) {
|
|
|
|
+ current_line = main->lines.size() - 1;
|
|
|
|
+ } else if (current_line >= main->lines.size()) {
|
|
|
|
+ current_line = 0;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (_search_line(main, current_line, p_string, char_idx, p_search_previous)) {
|
|
|
|
+ scroll_to_line(current_line);
|
|
|
|
+ update();
|
|
|
|
+ return true;
|
|
|
|
+ }
|
|
|
|
+ p_search_previous ? current_line-- : current_line++;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (p_from_selection && selection.active) {
|
|
|
|
+ // Check contents of selection
|
|
|
|
+ return _search_line(main, current_line, p_string, char_idx, p_search_previous);
|
|
|
|
+ } else {
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
String RichTextLabel::_get_line_text(ItemFrame *p_frame, int p_line, Selection p_selection) const {
|
|
String RichTextLabel::_get_line_text(ItemFrame *p_frame, int p_line, Selection p_selection) const {
|