From fb7888990429e5ea73903b461ad9b7a9faeaa67c Mon Sep 17 00:00:00 2001 From: bruvzg <7645683+bruvzg@users.noreply.github.com> Date: Mon, 24 Apr 2023 14:45:45 +0300 Subject: [PATCH] [RichTextLabel] Add support for tab stops. --- doc/classes/RichTextLabel.xml | 1 + scene/gui/rich_text_label.cpp | 38 ++++++++++++++++++++++++++++++----- scene/gui/rich_text_label.h | 4 +++- 3 files changed, 37 insertions(+), 6 deletions(-) diff --git a/doc/classes/RichTextLabel.xml b/doc/classes/RichTextLabel.xml index c44f54749b6..4a243a70cea 100644 --- a/doc/classes/RichTextLabel.xml +++ b/doc/classes/RichTextLabel.xml @@ -410,6 +410,7 @@ + Adds a [code][p][/code] tag to the tag stack. diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp index 185db1b972c..e12180f2f9e 100644 --- a/scene/gui/rich_text_label.cpp +++ b/scene/gui/rich_text_label.cpp @@ -277,7 +277,10 @@ float RichTextLabel::_resize_line(ItemFrame *p_frame, int p_line, const Refset_width(p_width - l.offset.x); - if (tab_size > 0) { // Align inline tabs. + PackedFloat32Array tab_stops = _find_tab_stops(l.from); + if (!tab_stops.is_empty()) { + l.text_buf->tab_align(tab_stops); + } else if (tab_size > 0) { // Align inline tabs. Vector tabs; tabs.push_back(tab_size * p_base_font->get_char_size(' ', p_base_font_size).width); l.text_buf->tab_align(tabs); @@ -481,7 +484,10 @@ float RichTextLabel::_shape_line(ItemFrame *p_frame, int p_line, const Ref l.text_buf->set_alignment(_find_alignment(l.from)); l.text_buf->set_direction(_find_direction(l.from)); - if (tab_size > 0) { // Align inline tabs. + PackedFloat32Array tab_stops = _find_tab_stops(l.from); + if (!tab_stops.is_empty()) { + l.text_buf->tab_align(tab_stops); + } else if (tab_size > 0) { // Align inline tabs. Vector tabs; tabs.push_back(tab_size * p_base_font->get_char_size(' ', p_base_font_size).width); l.text_buf->tab_align(tabs); @@ -2468,6 +2474,21 @@ BitField RichTextLabel::_find_jst_flags(Item *p_i return default_jst_flags; } +PackedFloat32Array RichTextLabel::_find_tab_stops(Item *p_item) { + Item *item = p_item; + + while (item) { + if (item->type == ITEM_PARAGRAPH) { + ItemParagraph *p = static_cast(item); + return p->tab_stops; + } + + item = item->parent; + } + + return PackedFloat32Array(); +} + HorizontalAlignment RichTextLabel::_find_alignment(Item *p_item) { Item *item = p_item; @@ -3312,7 +3333,7 @@ void RichTextLabel::push_strikethrough() { _add_item(item, true); } -void RichTextLabel::push_paragraph(HorizontalAlignment p_alignment, Control::TextDirection p_direction, const String &p_language, TextServer::StructuredTextParser p_st_parser, BitField p_jst_flags) { +void RichTextLabel::push_paragraph(HorizontalAlignment p_alignment, Control::TextDirection p_direction, const String &p_language, TextServer::StructuredTextParser p_st_parser, BitField p_jst_flags, const PackedFloat32Array &p_tab_stops) { _stop_thread(); MutexLock data_lock(data_mutex); @@ -3324,6 +3345,7 @@ void RichTextLabel::push_paragraph(HorizontalAlignment p_alignment, Control::Tex item->language = p_language; item->st_parser = p_st_parser; item->jst_flags = p_jst_flags; + item->tab_stops = p_tab_stops; _add_item(item, true, true); } @@ -4094,6 +4116,7 @@ void RichTextLabel::append_text(const String &p_bbcode) { HorizontalAlignment alignment = HORIZONTAL_ALIGNMENT_LEFT; Control::TextDirection dir = Control::TEXT_DIRECTION_INHERITED; String lang; + PackedFloat32Array tab_stops; TextServer::StructuredTextParser st_parser_type = TextServer::STRUCTURED_TEXT_DEFAULT; BitField jst_flags = default_jst_flags; for (int i = 0; i < subtag.size(); i++) { @@ -4118,6 +4141,11 @@ void RichTextLabel::append_text(const String &p_bbcode) { jst_flags.set_flag(TextServer::JUSTIFICATION_DO_NOT_SKIP_SINGLE_LINE); } } + } else if (subtag_a[0] == "tab_stops") { + Vector splitters; + splitters.push_back(","); + splitters.push_back(";"); + tab_stops = subtag_a[1].split_floats_mk(splitters); } else if (subtag_a[0] == "align") { if (subtag_a[1] == "l" || subtag_a[1] == "left") { alignment = HORIZONTAL_ALIGNMENT_LEFT; @@ -4157,7 +4185,7 @@ void RichTextLabel::append_text(const String &p_bbcode) { } } } - push_paragraph(alignment, dir, lang, st_parser_type, jst_flags); + push_paragraph(alignment, dir, lang, st_parser_type, jst_flags, tab_stops); pos = brk_end + 1; tag_stack.push_front("p"); } else if (tag == "url") { @@ -5406,7 +5434,7 @@ void RichTextLabel::_bind_methods() { ClassDB::bind_method(D_METHOD("push_color", "color"), &RichTextLabel::push_color); ClassDB::bind_method(D_METHOD("push_outline_size", "outline_size"), &RichTextLabel::push_outline_size); ClassDB::bind_method(D_METHOD("push_outline_color", "color"), &RichTextLabel::push_outline_color); - ClassDB::bind_method(D_METHOD("push_paragraph", "alignment", "base_direction", "language", "st_parser", "justification_flags"), &RichTextLabel::push_paragraph, DEFVAL(TextServer::DIRECTION_AUTO), DEFVAL(""), DEFVAL(TextServer::STRUCTURED_TEXT_DEFAULT), DEFVAL(TextServer::JUSTIFICATION_WORD_BOUND | TextServer::JUSTIFICATION_KASHIDA | TextServer::JUSTIFICATION_SKIP_LAST_LINE | TextServer::JUSTIFICATION_DO_NOT_SKIP_SINGLE_LINE)); + ClassDB::bind_method(D_METHOD("push_paragraph", "alignment", "base_direction", "language", "st_parser", "justification_flags", "tab_stops"), &RichTextLabel::push_paragraph, DEFVAL(TextServer::DIRECTION_AUTO), DEFVAL(""), DEFVAL(TextServer::STRUCTURED_TEXT_DEFAULT), DEFVAL(TextServer::JUSTIFICATION_WORD_BOUND | TextServer::JUSTIFICATION_KASHIDA | TextServer::JUSTIFICATION_SKIP_LAST_LINE | TextServer::JUSTIFICATION_DO_NOT_SKIP_SINGLE_LINE), DEFVAL(PackedFloat32Array())); ClassDB::bind_method(D_METHOD("push_indent", "level"), &RichTextLabel::push_indent); ClassDB::bind_method(D_METHOD("push_list", "level", "type", "capitalize", "bullet"), &RichTextLabel::push_list, DEFVAL(String::utf8("•"))); ClassDB::bind_method(D_METHOD("push_meta", "data"), &RichTextLabel::push_meta); diff --git a/scene/gui/rich_text_label.h b/scene/gui/rich_text_label.h index 3e3413d47ab..f6cc9b2ac4b 100644 --- a/scene/gui/rich_text_label.h +++ b/scene/gui/rich_text_label.h @@ -241,6 +241,7 @@ private: Control::TextDirection direction = Control::TEXT_DIRECTION_AUTO; TextServer::StructuredTextParser st_parser = TextServer::STRUCTURED_TEXT_DEFAULT; BitField jst_flags = TextServer::JUSTIFICATION_WORD_BOUND | TextServer::JUSTIFICATION_KASHIDA | TextServer::JUSTIFICATION_SKIP_LAST_LINE | TextServer::JUSTIFICATION_DO_NOT_SKIP_SINGLE_LINE; + PackedFloat32Array tab_stops; ItemParagraph() { type = ITEM_PARAGRAPH; } }; @@ -493,6 +494,7 @@ private: ItemDropcap *_find_dc_item(Item *p_item); int _find_list(Item *p_item, Vector &r_index, Vector &r_list); int _find_margin(Item *p_item, const Ref &p_base_font, int p_base_font_size); + PackedFloat32Array _find_tab_stops(Item *p_item); HorizontalAlignment _find_alignment(Item *p_item); BitField _find_jst_flags(Item *p_item); TextServer::Direction _find_direction(Item *p_item); @@ -596,7 +598,7 @@ public: void push_outline_color(const Color &p_color); void push_underline(); void push_strikethrough(); - void push_paragraph(HorizontalAlignment p_alignment, Control::TextDirection p_direction = Control::TEXT_DIRECTION_INHERITED, const String &p_language = "", TextServer::StructuredTextParser p_st_parser = TextServer::STRUCTURED_TEXT_DEFAULT, BitField p_jst_flags = TextServer::JUSTIFICATION_WORD_BOUND | TextServer::JUSTIFICATION_KASHIDA | TextServer::JUSTIFICATION_SKIP_LAST_LINE | TextServer::JUSTIFICATION_DO_NOT_SKIP_SINGLE_LINE); + void push_paragraph(HorizontalAlignment p_alignment, Control::TextDirection p_direction = Control::TEXT_DIRECTION_INHERITED, const String &p_language = "", TextServer::StructuredTextParser p_st_parser = TextServer::STRUCTURED_TEXT_DEFAULT, BitField p_jst_flags = TextServer::JUSTIFICATION_WORD_BOUND | TextServer::JUSTIFICATION_KASHIDA | TextServer::JUSTIFICATION_SKIP_LAST_LINE | TextServer::JUSTIFICATION_DO_NOT_SKIP_SINGLE_LINE, const PackedFloat32Array &p_tab_stops = PackedFloat32Array()); void push_indent(int p_level); void push_list(int p_level, ListType p_list, bool p_capitalize, const String &p_bullet = String::utf8("•")); void push_meta(const Variant &p_meta);