RichTextLabel: adds separate get_total_x_count, get_visible_x_count and scroll_to_x functions for wrapped lines and paragraphs (newlines).

This commit is contained in:
bruvzg 2021-01-12 14:03:10 +02:00
parent 380bb2d533
commit e4651a44ab
No known key found for this signature in database
GPG Key ID: 009E1BFE42239B95
3 changed files with 89 additions and 12 deletions

View File

@ -70,7 +70,14 @@
<return type="int"> <return type="int">
</return> </return>
<description> <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> </description>
</method> </method>
<method name="get_total_character_count" qualifiers="const"> <method name="get_total_character_count" qualifiers="const">
@ -94,6 +101,13 @@
Returns the number of visible lines. Returns the number of visible lines.
</description> </description>
</method> </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"> <method name="install_effect">
<return type="void"> <return type="void">
</return> </return>
@ -342,6 +356,15 @@
Scrolls the window's top line to match [code]line[/code]. Scrolls the window's top line to match [code]line[/code].
</description> </description>
</method> </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"> <method name="set_cell_border_color">
<return type="void"> <return type="void">
</return> </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; Vector2 off;
ERR_FAIL_COND(p_frame == nullptr); ERR_FAIL_COND_V(p_frame == nullptr, 0);
ERR_FAIL_COND(p_line < 0 || p_line >= p_frame->lines.size()); ERR_FAIL_COND_V(p_line < 0 || p_line >= p_frame->lines.size(), 0);
Line &l = p_frame->lines.write[p_line]; 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; Variant meta;
if (it_from == nullptr) { if (it_from == nullptr) {
return; return 0;
} }
RID ci = get_canvas_item(); 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); 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. // Draw text.
for (int line = 0; line < l.text_buf->get_line_count(); line++) { for (int line = 0; line < l.text_buf->get_line_count(); line++) {
RID rid = l.text_buf->get_line_rid(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 width = l.text_buf->get_width();
float length = TS->shaped_text_get_width(rid); float length = TS->shaped_text_get_width(rid);
// Draw line. // Draw line.
line_count++;
if (rtl) { if (rtl) {
off.x = p_width - l.offset.x - width; 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); 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) { 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"); bool use_outline = get_theme_constant("shadow_as_outline");
Point2 shadow_ofs(get_theme_constant("shadow_offset_x"), get_theme_constant("shadow_offset_y")); Point2 shadow_ofs(get_theme_constant("shadow_offset_x"), get_theme_constant("shadow_offset_y"));
visible_paragraph_count = 0;
visible_line_count = 0; visible_line_count = 0;
// New cache draw. // New cache draw.
Point2 ofs = text_rect.get_position() + Vector2(0, main->lines[from_line].offset.y - vofs); 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()) { while (ofs.y < size.height && from_line < main->lines.size()) {
visible_line_count++; visible_paragraph_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_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; ofs.y += main->lines[from_line].text_buf->get_size().y;
from_line++; from_line++;
} }
@ -3367,14 +3380,46 @@ Error RichTextLabel::append_bbcode(const String &p_bbcode) {
return OK; return OK;
} }
void RichTextLabel::scroll_to_line(int p_line) { void RichTextLabel::scroll_to_paragraph(int p_paragraph) {
ERR_FAIL_INDEX(p_line, main->lines.size()); ERR_FAIL_INDEX(p_paragraph, main->lines.size());
_validate_line_caches(main); _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 { 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 { 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("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_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("set_tab_size", "spaces"), &RichTextLabel::set_tab_size);
ClassDB::bind_method(D_METHOD("get_tab_size"), &RichTextLabel::get_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_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_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("get_content_height"), &RichTextLabel::get_content_height);
ClassDB::bind_method(D_METHOD("parse_expressions_for_values", "expressions"), &RichTextLabel::parse_expressions_for_values); 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; bool updating_scroll;
int current_idx = 1; int current_idx = 1;
int current_char_ofs = 0; int current_char_ofs = 0;
int visible_paragraph_count;
int visible_line_count; int visible_line_count;
int tab_size; 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 _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 _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); 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; 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); 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); void scroll_to_line(int p_line);
int get_line_count() const; int get_line_count() const;
int get_visible_line_count() const; int get_visible_line_count() const;