Fix copying text across tables in RichTextLabel
Previously, using `\r` instead of `\n` for line breaks in tables (e.g., in class references) could cause issues when copying text across tables.
This commit is contained in:
parent
92a90a8e6f
commit
f9c31d3483
2 changed files with 45 additions and 22 deletions
|
|
@ -6915,38 +6915,41 @@ bool RichTextLabel::search(const String &p_string, bool p_from_selection, bool p
|
|||
}
|
||||
}
|
||||
|
||||
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) const {
|
||||
String txt;
|
||||
|
||||
ERR_FAIL_NULL_V(p_frame, txt);
|
||||
ERR_FAIL_COND_V(p_line < 0 || p_line >= (int)p_frame->lines.size(), txt);
|
||||
|
||||
int start = 0; // Unless the current line is the `from` line.
|
||||
if (!selection.from_line_found && p_frame == selection.from_frame) {
|
||||
if (p_line < selection.from_line) {
|
||||
return txt; // Skip the lines with smaller line numbers in the same `from` frame.
|
||||
}
|
||||
selection.from_line_found = true;
|
||||
start = selection.from_char;
|
||||
}
|
||||
const bool from_this = selection.from_line_found; // Used to detect cases starting from a sub-frame.
|
||||
|
||||
Line &l = p_frame->lines[p_line];
|
||||
|
||||
Item *it_to = (p_line + 1 < (int)p_frame->lines.size()) ? p_frame->lines[p_line + 1].from : nullptr;
|
||||
int end_idx = 0;
|
||||
if (it_to != nullptr) {
|
||||
end_idx = it_to->index;
|
||||
} else {
|
||||
for (Item *it = l.from; it; it = _get_next_item(it)) {
|
||||
end_idx = it->index + 1;
|
||||
}
|
||||
}
|
||||
for (Item *it = l.from; it && it != it_to; it = _get_next_item(it)) {
|
||||
for (Item *it = l.from; !selection.to_line_found && it && it != it_to; it = _get_next_item(it)) {
|
||||
if (it->type == ITEM_TABLE) {
|
||||
ItemTable *table = static_cast<ItemTable *>(it);
|
||||
for (Item *E : table->subitems) {
|
||||
ERR_CONTINUE(E->type != ITEM_FRAME); // Children should all be frames.
|
||||
ItemFrame *frame = static_cast<ItemFrame *>(E);
|
||||
for (int i = 0; i < (int)frame->lines.size(); i++) {
|
||||
txt += _get_line_text(frame, i, p_selection);
|
||||
for (int i = 0; !selection.to_line_found && i < (int)frame->lines.size(); i++) {
|
||||
txt += _get_line_text(frame, i);
|
||||
}
|
||||
if (selection.to_line_found) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((p_selection.to_item != nullptr) && (p_selection.to_item->index < l.from->index)) {
|
||||
continue;
|
||||
}
|
||||
if ((p_selection.from_item != nullptr) && (p_selection.from_item->index >= end_idx)) {
|
||||
if (!selection.from_line_found) {
|
||||
continue;
|
||||
}
|
||||
if (it->type == ITEM_DROPCAP) {
|
||||
|
|
@ -6961,12 +6964,26 @@ String RichTextLabel::_get_line_text(ItemFrame *p_frame, int p_line, Selection p
|
|||
txt += " ";
|
||||
}
|
||||
}
|
||||
if ((l.from != nullptr) && (p_frame == p_selection.to_frame) && (p_selection.to_item != nullptr) && (p_selection.to_item->index >= l.from->index) && (p_selection.to_item->index < end_idx)) {
|
||||
txt = txt.substr(0, p_selection.to_char);
|
||||
|
||||
if (!selection.from_line_found) {
|
||||
return txt; // Empty.
|
||||
}
|
||||
if ((l.from != nullptr) && (p_frame == p_selection.from_frame) && (p_selection.from_item != nullptr) && (p_selection.from_item->index >= l.from->index) && (p_selection.from_item->index < end_idx)) {
|
||||
txt = txt.substr(p_selection.from_char);
|
||||
|
||||
int chars = -1; // Unless the current line is the `to` line.
|
||||
if (p_frame == selection.to_frame && p_line == selection.to_line) {
|
||||
selection.to_line_found = true;
|
||||
|
||||
if (from_this ^ selection.from_line_found) {
|
||||
// For cases text from child frame to parent frame is considered to be on the same line,
|
||||
// even if the line numbers are different. `start` has been reset to 0.
|
||||
chars = selection.to_char - selection.from_char;
|
||||
} else {
|
||||
chars = selection.to_char - start;
|
||||
}
|
||||
}
|
||||
|
||||
txt = txt.substr(start, chars);
|
||||
|
||||
return txt;
|
||||
}
|
||||
|
||||
|
|
@ -7005,8 +7022,12 @@ String RichTextLabel::get_selected_text() const {
|
|||
|
||||
String txt;
|
||||
int to_line = main->first_invalid_line.load();
|
||||
for (int i = 0; i < to_line; i++) {
|
||||
txt += _get_line_text(main, i, selection);
|
||||
|
||||
selection.from_line_found = false;
|
||||
selection.to_line_found = false;
|
||||
|
||||
for (int i = 0; !selection.to_line_found && i < to_line; i++) {
|
||||
txt += _get_line_text(main, i);
|
||||
}
|
||||
|
||||
if (selection_modifier.is_valid()) {
|
||||
|
|
|
|||
|
|
@ -625,11 +625,13 @@ private:
|
|||
int from_line = 0;
|
||||
Item *from_item = nullptr;
|
||||
int from_char = 0;
|
||||
mutable bool from_line_found = false;
|
||||
|
||||
ItemFrame *to_frame = nullptr;
|
||||
int to_line = 0;
|
||||
Item *to_item = nullptr;
|
||||
int to_char = 0;
|
||||
mutable bool to_line_found = false;
|
||||
|
||||
bool double_click = false; // Selecting whole words?
|
||||
bool active = false; // anything selected? i.e. from, to, etc. valid?
|
||||
|
|
@ -663,7 +665,7 @@ private:
|
|||
bool _is_click_inside_selection() const;
|
||||
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;
|
||||
String _get_line_text(ItemFrame *p_frame, int p_line) const;
|
||||
bool _search_table_cell(ItemTable *p_table, List<Item *>::Element *p_cell, const String &p_string, bool p_reverse_search, int p_from_line);
|
||||
bool _search_table(ItemTable *p_table, List<Item *>::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);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue