From 406a22d0da3b32bec97ac42ea143842be5cdf640 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pa=CC=84vels=20Nadtoc=CC=8Cajevs?= <7645683+bruvzg@users.noreply.github.com> Date: Thu, 10 Jul 2025 09:56:23 +0300 Subject: [PATCH] [RTL] Add method to get visible content bounding box. --- doc/classes/RichTextLabel.xml | 37 +++++++++++++++++++++++++++++++++++ scene/gui/rich_text_label.cpp | 18 +++++++++++++++++ scene/gui/rich_text_label.h | 3 +++ 3 files changed, 58 insertions(+) diff --git a/doc/classes/RichTextLabel.xml b/doc/classes/RichTextLabel.xml index c79880a5ceb..44599142e80 100644 --- a/doc/classes/RichTextLabel.xml +++ b/doc/classes/RichTextLabel.xml @@ -104,6 +104,7 @@ Returns the height of the content. + [b]Note:[/b] This method always returns the full content size, and is not affected by [member visible_ratio] and [member visible_characters]. To get the visible content size, use [method get_visible_content_rect]. [b]Note:[/b] If [member threaded] is enabled, this method returns a value for the loaded part of the document. Use [method is_finished] or [signal finished] to determine whether document is fully loaded. @@ -111,6 +112,7 @@ Returns the width of the content. + [b]Note:[/b] This method always returns the full content size, and is not affected by [member visible_ratio] and [member visible_characters]. To get the visible content size, use [method get_visible_content_rect]. [b]Note:[/b] If [member threaded] is enabled, this method returns a value for the loaded part of the document. Use [method is_finished] or [signal finished] to determine whether document is fully loaded. @@ -257,10 +259,44 @@ [b]Warning:[/b] This is a required internal node, removing and freeing it may cause a crash. If you wish to hide it or any of its children, use their [member CanvasItem.visible] property. + + + + Returns the bounding rectangle of the visible content. + [b]Note:[/b] This method returns a correct value only after the label has been drawn. + [codeblocks] + [gdscript] + extends RichTextLabel + + @export var background_panel: Panel + + func _ready(): + await draw + background_panel.position = get_visible_content_rect().position + background_panel.size = get_visible_content_rect().size + [/gdscript] + [csharp] + public partial class TestLabel : RichTextLabel + { + [Export] + public Panel BackgroundPanel { get; set; } + + public override async void _Ready() + { + await ToSignal(this, Control.SignalName.Draw); + BackgroundGPanel.Position = GetVisibleContentRect().Position; + BackgroundPanel.Size = GetVisibleContentRect().Size; + } + } + [/csharp] + [/codeblocks] + + Returns the number of visible lines. + [b]Note:[/b] This method returns a correct value only after the label has been drawn. [b]Note:[/b] If [member threaded] is enabled, this method returns a value for the loaded part of the document. Use [method is_finished] or [signal finished] to determine whether document is fully loaded. @@ -268,6 +304,7 @@ Returns the number of visible paragraphs. A paragraph is considered visible if at least one of its lines is visible. + [b]Note:[/b] This method returns a correct value only after the label has been drawn. [b]Note:[/b] If [member threaded] is enabled, this method returns a value for the loaded part of the document. Use [method is_finished] or [signal finished] to determine whether document is fully loaded. diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp index 9e5d253bb99..9c9d194f86e 100644 --- a/scene/gui/rich_text_label.cpp +++ b/scene/gui/rich_text_label.cpp @@ -58,6 +58,14 @@ RichTextLabel::ItemCustomFX::~ItemCustomFX() { custom_effect.unref(); } +Rect2i _merge_or_copy_rect(const Rect2i &p_a, const Rect2i &p_b) { + if (!p_a.has_area()) { + return p_b; + } else { + return p_a.merge(p_b); + } +} + RichTextLabel::Item *RichTextLabel::_get_next_item(Item *p_item, bool p_free) const { if (!p_item) { return nullptr; @@ -986,8 +994,10 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o Size2 pad_size = rect.size.min(img->image->get_size()); Vector2 pad_off = (rect.size - pad_size) / 2; img->image->draw_rect(ci, Rect2(p_ofs + rect.position + off + pad_off, pad_size), false, img->color); + visible_rect = _merge_or_copy_rect(visible_rect, Rect2(p_ofs + rect.position + off + pad_off, pad_size)); } else { img->image->draw_rect(ci, Rect2(p_ofs + rect.position + off, rect.size), false, img->color); + visible_rect = _merge_or_copy_rect(visible_rect, Rect2(p_ofs + rect.position + off, rect.size)); } } break; case ITEM_TABLE: { @@ -1358,6 +1368,7 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o if (!skip) { if (txt_visible) { has_visible_chars = true; + visible_rect = _merge_or_copy_rect(visible_rect, Rect2i(fx_offset + char_off - Vector2i(0, l_ascent), Point2i(glyphs[i].advance, l_size.y))); if (step == DRAW_STEP_TEXT) { if (frid != RID()) { TS->font_draw_glyph(frid, ci, glyphs[i].font_size, fx_offset + char_off, gl, font_color); @@ -2501,6 +2512,7 @@ void RichTextLabel::_notification(int p_what) { visible_paragraph_count = 0; visible_line_count = 0; + visible_rect = Rect2i(); // New cache draw. Point2 ofs = text_rect.get_position() + Vector2(0, vbegin + main->lines[from_line].offset.y - vofs); @@ -7258,6 +7270,10 @@ int RichTextLabel::get_content_height() const { return total_height; } +Rect2i RichTextLabel::get_visible_content_rect() const { + return visible_rect; +} + int RichTextLabel::get_content_width() const { const_cast(this)->_validate_line_caches(); @@ -7480,6 +7496,8 @@ void RichTextLabel::_bind_methods() { ClassDB::bind_method(D_METHOD("get_line_height", "line"), &RichTextLabel::get_line_height); ClassDB::bind_method(D_METHOD("get_line_width", "line"), &RichTextLabel::get_line_width); + ClassDB::bind_method(D_METHOD("get_visible_content_rect"), &RichTextLabel::get_visible_content_rect); + ClassDB::bind_method(D_METHOD("get_line_offset", "line"), &RichTextLabel::get_line_offset); ClassDB::bind_method(D_METHOD("get_paragraph_offset", "paragraph"), &RichTextLabel::get_paragraph_offset); diff --git a/scene/gui/rich_text_label.h b/scene/gui/rich_text_label.h index e84d3d2c508..78bf6f0ba54 100644 --- a/scene/gui/rich_text_label.h +++ b/scene/gui/rich_text_label.h @@ -536,6 +536,7 @@ private: int current_char_ofs = 0; int visible_paragraph_count = 0; int visible_line_count = 0; + Rect2i visible_rect; int tab_size = 4; bool underline_meta = true; @@ -871,6 +872,8 @@ public: int get_line_height(int p_line) const; int get_line_width(int p_line) const; + Rect2i get_visible_content_rect() const; + void scroll_to_selection(); VScrollBar *get_v_scroll_bar() { return vscroll; }