Merge pull request #45128 from bruvzg/rtl_wrapped_lines

RichTextLabel: Add count and scroll functions for wrapped lines and paragraphs.
This commit is contained in:
Rémi Verschelde 2021-01-18 11:37:21 +01:00 committed by GitHub
commit 16fa4201f1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 89 additions and 12 deletions

View file

@ -70,7 +70,14 @@
<return type="int">
</return>
<description>
Returns the total number of newlines in the tag stack's text tags. Considers wrapped text as one line.
Returns the total number of lines in the text. Wrapped text is counted as multiple lines.
</description>
</method>
<method name="get_paragraph_count" qualifiers="const">
<return type="int">
</return>
<description>
Returns the total number of paragraphs (newlines or [code]p[/code] tags in the tag stack's text tags). Considers wrapped text as one paragraph.
</description>
</method>
<method name="get_total_character_count" qualifiers="const">
@ -94,6 +101,13 @@
Returns the number of visible lines.
</description>
</method>
<method name="get_visible_paragraph_count" qualifiers="const">
<return type="int">
</return>
<description>
Returns the number of visible paragraphs. A paragraph is considered visible if at least one of its lines is visible.
</description>
</method>
<method name="install_effect">
<return type="void">
</return>
@ -342,6 +356,15 @@
Scrolls the window's top line to match [code]line[/code].
</description>
</method>
<method name="scroll_to_paragraph">
<return type="void">
</return>
<argument index="0" name="paragraph" type="int">
</argument>
<description>
Scrolls the window's top line to match first line of the [code]paragraph[/code].
</description>
</method>
<method name="set_cell_border_color">
<return type="void">
</return>

View file

@ -618,11 +618,11 @@ void RichTextLabel::_shape_line(ItemFrame *p_frame, int p_line, const Ref<Font>
}
}
void RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_ofs, int p_width, const Color &p_base_color, int p_outline_size, const Color &p_outline_color, const Color &p_font_color_shadow, bool p_shadow_as_outline, const Point2 &p_shadow_ofs) {
int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_ofs, int p_width, const Color &p_base_color, int p_outline_size, const Color &p_outline_color, const Color &p_font_color_shadow, bool p_shadow_as_outline, const Point2 &p_shadow_ofs) {
Vector2 off;
ERR_FAIL_COND(p_frame == nullptr);
ERR_FAIL_COND(p_line < 0 || p_line >= p_frame->lines.size());
ERR_FAIL_COND_V(p_frame == nullptr, 0);
ERR_FAIL_COND_V(p_line < 0 || p_line >= p_frame->lines.size(), 0);
Line &l = p_frame->lines.write[p_line];
@ -631,7 +631,7 @@ void RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_
Variant meta;
if (it_from == nullptr) {
return;
return 0;
}
RID ci = get_canvas_item();
@ -699,14 +699,24 @@ void RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_
}
l.text_buf->draw_dropcap(ci, p_ofs + ((rtl) ? Vector2() : Vector2(l.offset.x, 0)), l.dc_color);
int line_count = 0;
Size2 ctrl_size = get_size();
// Draw text.
for (int line = 0; line < l.text_buf->get_line_count(); line++) {
RID rid = l.text_buf->get_line_rid(line);
if (p_ofs.y + off.y >= ctrl_size.height) {
break;
}
if (p_ofs.y + off.y + TS->shaped_text_get_size(rid).y <= 0) {
off.y += TS->shaped_text_get_size(rid).y;
continue;
}
float width = l.text_buf->get_width();
float length = TS->shaped_text_get_width(rid);
// Draw line.
line_count++;
if (rtl) {
off.x = p_width - l.offset.x - width;
@ -1068,6 +1078,8 @@ void RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_
}
off.y += TS->shaped_text_get_descent(rid);
}
return line_count;
}
void RichTextLabel::_find_click(ItemFrame *p_frame, const Point2i &p_click, ItemFrame **r_click_frame, int *r_click_line, Item **r_click_item, int *r_click_char, bool *r_outside) {
@ -1392,13 +1404,14 @@ void RichTextLabel::_notification(int p_what) {
bool use_outline = get_theme_constant("shadow_as_outline");
Point2 shadow_ofs(get_theme_constant("shadow_offset_x"), get_theme_constant("shadow_offset_y"));
visible_paragraph_count = 0;
visible_line_count = 0;
// New cache draw.
Point2 ofs = text_rect.get_position() + Vector2(0, main->lines[from_line].offset.y - vofs);
while (ofs.y < size.height && from_line < main->lines.size()) {
visible_line_count++;
_draw_line(main, from_line, ofs, text_rect.size.x, base_color, outline_size, outline_color, font_color_shadow, use_outline, shadow_ofs);
visible_paragraph_count++;
visible_line_count += _draw_line(main, from_line, ofs, text_rect.size.x, base_color, outline_size, outline_color, font_color_shadow, use_outline, shadow_ofs);
ofs.y += main->lines[from_line].text_buf->get_size().y;
from_line++;
}
@ -3367,14 +3380,46 @@ Error RichTextLabel::append_bbcode(const String &p_bbcode) {
return OK;
}
void RichTextLabel::scroll_to_line(int p_line) {
ERR_FAIL_INDEX(p_line, main->lines.size());
void RichTextLabel::scroll_to_paragraph(int p_paragraph) {
ERR_FAIL_INDEX(p_paragraph, main->lines.size());
_validate_line_caches(main);
vscroll->set_value(main->lines[p_line].offset.y);
vscroll->set_value(main->lines[p_paragraph].offset.y);
}
int RichTextLabel::get_paragraph_count() const {
return current_frame->lines.size();
}
int RichTextLabel::get_visible_paragraph_count() const {
if (!is_visible()) {
return 0;
}
return visible_paragraph_count;
}
void RichTextLabel::scroll_to_line(int p_line) {
_validate_line_caches(main);
int line_count = 0;
for (int i = 0; i < main->lines.size(); i++) {
if ((line_count <= p_line) && (line_count + main->lines[i].text_buf->get_line_count() >= p_line)) {
float line_offset = 0.f;
for (int j = 0; j < p_line - line_count; j++) {
line_offset += main->lines[i].text_buf->get_line_size(j).y;
}
vscroll->set_value(main->lines[i].offset.y + line_offset);
return;
}
line_count += main->lines[i].text_buf->get_line_count();
}
}
int RichTextLabel::get_line_count() const {
return current_frame->lines.size();
int line_count = 0;
for (int i = 0; i < main->lines.size(); i++) {
line_count += main->lines[i].text_buf->get_line_count();
}
return line_count;
}
int RichTextLabel::get_visible_line_count() const {
@ -3783,6 +3828,7 @@ void RichTextLabel::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_v_scroll"), &RichTextLabel::get_v_scroll);
ClassDB::bind_method(D_METHOD("scroll_to_line", "line"), &RichTextLabel::scroll_to_line);
ClassDB::bind_method(D_METHOD("scroll_to_paragraph", "paragraph"), &RichTextLabel::scroll_to_paragraph);
ClassDB::bind_method(D_METHOD("set_tab_size", "spaces"), &RichTextLabel::set_tab_size);
ClassDB::bind_method(D_METHOD("get_tab_size"), &RichTextLabel::get_tab_size);
@ -3813,6 +3859,9 @@ void RichTextLabel::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_line_count"), &RichTextLabel::get_line_count);
ClassDB::bind_method(D_METHOD("get_visible_line_count"), &RichTextLabel::get_visible_line_count);
ClassDB::bind_method(D_METHOD("get_paragraph_count"), &RichTextLabel::get_paragraph_count);
ClassDB::bind_method(D_METHOD("get_visible_paragraph_count"), &RichTextLabel::get_visible_paragraph_count);
ClassDB::bind_method(D_METHOD("get_content_height"), &RichTextLabel::get_content_height);
ClassDB::bind_method(D_METHOD("parse_expressions_for_values", "expressions"), &RichTextLabel::parse_expressions_for_values);

View file

@ -337,6 +337,7 @@ private:
bool updating_scroll;
int current_idx = 1;
int current_char_ofs = 0;
int visible_paragraph_count;
int visible_line_count;
int tab_size;
@ -393,7 +394,7 @@ private:
void _shape_line(ItemFrame *p_frame, int p_line, const Ref<Font> &p_base_font, int p_base_font_size, int p_width, int *r_char_offset);
void _resize_line(ItemFrame *p_frame, int p_line, const Ref<Font> &p_base_font, int p_base_font_size, int p_width);
void _draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_ofs, int p_width, const Color &p_base_color, int p_outline_size, const Color &p_outline_color, const Color &p_font_color_shadow, bool p_shadow_as_outline, const Point2 &shadow_ofs);
int _draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_ofs, int p_width, const Color &p_base_color, int p_outline_size, const Color &p_outline_color, const Color &p_font_color_shadow, bool p_shadow_as_outline, const Point2 &shadow_ofs);
float _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 = nullptr, int *r_click_line = nullptr, Item **r_click_item = nullptr, int *r_click_char = nullptr);
String _roman(int p_num, bool p_capitalize) const;
@ -507,6 +508,10 @@ public:
bool search(const String &p_string, bool p_from_selection = false, bool p_search_previous = false);
void scroll_to_paragraph(int p_paragraph);
int get_paragraph_count() const;
int get_visible_paragraph_count() const;
void scroll_to_line(int p_line);
int get_line_count() const;
int get_visible_line_count() const;