summaryrefslogtreecommitdiff
path: root/scene/gui/rich_text_label.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'scene/gui/rich_text_label.cpp')
-rw-r--r--scene/gui/rich_text_label.cpp184
1 files changed, 136 insertions, 48 deletions
diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp
index c763ae6bd6..987d05bf71 100644
--- a/scene/gui/rich_text_label.cpp
+++ b/scene/gui/rich_text_label.cpp
@@ -1432,10 +1432,11 @@ void RichTextLabel::_notification(int p_what) {
}
} break;
case NOTIFICATION_INTERNAL_PROCESS: {
- float dt = get_process_delta_time();
-
- _update_fx(main, dt);
- update();
+ if (is_visible_in_tree()) {
+ float dt = get_process_delta_time();
+ _update_fx(main, dt);
+ update();
+ }
}
}
}
@@ -1482,7 +1483,7 @@ void RichTextLabel::_gui_input(Ref<InputEvent> p_event) {
}
if (b->get_button_index() == MOUSE_BUTTON_LEFT) {
- if (b->is_pressed() && !b->is_doubleclick()) {
+ if (b->is_pressed() && !b->is_double_click()) {
scroll_updated = false;
ItemFrame *c_frame = nullptr;
int c_line = 0;
@@ -1514,8 +1515,8 @@ void RichTextLabel::_gui_input(Ref<InputEvent> p_event) {
}
}
}
- } else if (b->is_pressed() && b->is_doubleclick() && selection.enabled) {
- //doubleclick: select word
+ } else if (b->is_pressed() && b->is_double_click() && selection.enabled) {
+ //double_click: select word
ItemFrame *c_frame = nullptr;
int c_line = 0;
@@ -1549,7 +1550,7 @@ void RichTextLabel::_gui_input(Ref<InputEvent> p_event) {
} else if (!b->is_pressed()) {
selection.click_item = nullptr;
- if (!b->is_doubleclick() && !scroll_updated) {
+ if (!b->is_double_click() && !scroll_updated) {
Item *c_item = nullptr;
bool outside = true;
@@ -2231,18 +2232,22 @@ void RichTextLabel::_remove_item(Item *p_item, const int p_line, const int p_sub
int size = p_item->subitems.size();
if (size == 0) {
p_item->parent->subitems.erase(p_item);
+ // If a newline was erased, all lines AFTER the newline need to be decremented.
if (p_item->type == ITEM_NEWLINE) {
current_frame->lines.remove(p_line);
- for (int i = p_subitem_line; i < current->subitems.size(); i++) {
- if (current->subitems[i]->line > 0) {
+ for (int i = 0; i < current->subitems.size(); i++) {
+ if (current->subitems[i]->line > p_subitem_line) {
current->subitems[i]->line--;
}
}
}
} else {
+ // First, remove all child items for the provided item.
for (int i = 0; i < size; i++) {
_remove_item(p_item->subitems.front()->get(), p_line, p_subitem_line);
}
+ // Then remove the provided item itself.
+ p_item->parent->subitems.erase(p_item);
}
}
@@ -2302,21 +2307,23 @@ bool RichTextLabel::remove_line(const int p_line) {
return false;
}
- int i = 0;
- while (i < current->subitems.size() && current->subitems[i]->line < p_line) {
- i++;
+ // Remove all subitems with the same line as that provided.
+ Vector<int> subitem_indices_to_remove;
+ for (int i = 0; i < current->subitems.size(); i++) {
+ if (current->subitems[i]->line == p_line) {
+ subitem_indices_to_remove.push_back(i);
+ }
}
- bool was_newline = false;
- while (i < current->subitems.size()) {
- was_newline = current->subitems[i]->type == ITEM_NEWLINE;
- _remove_item(current->subitems[i], current->subitems[i]->line, p_line);
- if (was_newline) {
- break;
- }
+ bool had_newline = false;
+ // Reverse for loop to remove items from the end first.
+ for (int i = subitem_indices_to_remove.size() - 1; i >= 0; i--) {
+ int subitem_idx = subitem_indices_to_remove[i];
+ had_newline = had_newline || current->subitems[subitem_idx]->type == ITEM_NEWLINE;
+ _remove_item(current->subitems[subitem_idx], current->subitems[subitem_idx]->line, p_line);
}
- if (!was_newline) {
+ if (!had_newline) {
current_frame->lines.remove(p_line);
if (current_frame->lines.size() == 0) {
current_frame->lines.resize(1);
@@ -2328,6 +2335,7 @@ bool RichTextLabel::remove_line(const int p_line) {
}
main->first_invalid_line = 0; // p_line ???
+ update();
return true;
}
@@ -3444,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_line < 0 || p_line >= p_frame->lines.size(), false);
@@ -3466,24 +3497,23 @@ bool RichTextLabel::_search_line(ItemFrame *p_frame, int p_line, const String &p
} break;
case ITEM_TABLE: {
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;
default:
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) {
selection.from_frame = p_frame;
selection.from_line = p_line;
@@ -3491,8 +3521,8 @@ bool RichTextLabel::_search_line(ItemFrame *p_frame, int p_line, const String &p
selection.from_char = sp;
selection.to_frame = p_frame;
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;
return true;
}
@@ -3503,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) {
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) {
- 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 {
@@ -3926,7 +4014,7 @@ void RichTextLabel::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "custom_effects", PROPERTY_HINT_ARRAY_TYPE, "RichTextEffect", (PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE)), "set_effects", "get_effects");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "text_direction", PROPERTY_HINT_ENUM, "Auto,LTR,RTL,Inherited"), "set_text_direction", "get_text_direction");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "text_direction", PROPERTY_HINT_ENUM, "Auto,Left-to-Right,Right-to-Left,Inherited"), "set_text_direction", "get_text_direction");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "language"), "set_language", "get_language");
ADD_GROUP("Structured Text", "structured_text_");