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; }