diff options
-rw-r--r-- | doc/classes/RichTextLabel.xml | 28 | ||||
-rw-r--r-- | scene/gui/rich_text_label.cpp | 134 | ||||
-rw-r--r-- | scene/gui/rich_text_label.h | 18 |
3 files changed, 177 insertions, 3 deletions
diff --git a/doc/classes/RichTextLabel.xml b/doc/classes/RichTextLabel.xml index 623ee7520d..38884a027f 100644 --- a/doc/classes/RichTextLabel.xml +++ b/doc/classes/RichTextLabel.xml @@ -170,6 +170,15 @@ Terminates the current tag. Use after [code]push_*[/code] methods to close BBCodes manually. Does not need to follow [code]add_*[/code] methods. </description> </method> + <method name="push_bgcolor"> + <return type="void"> + </return> + <argument index="0" name="bgcolor" type="Color"> + </argument> + <description> + Adds a [code][bgcolor][/code] tag to the tag stack. + </description> + </method> <method name="push_bold"> <return type="void"> </return> @@ -221,6 +230,15 @@ Adds a [code][dropcap][/code] tag to the tag stack. Drop cap (dropped capital) is a decorative element at the beginning of a paragraph that is larger than the rest of the text. </description> </method> + <method name="push_fgcolor"> + <return type="void"> + </return> + <argument index="0" name="fgcolor" type="Color"> + </argument> + <description> + Adds a [code][fgcolor][/code] tag to the tag stack. + </description> + </method> <method name="push_font"> <return type="void"> </return> @@ -592,11 +610,15 @@ </constant> <constant name="ITEM_RAINBOW" value="20" enum="ItemType"> </constant> - <constant name="ITEM_META" value="21" enum="ItemType"> + <constant name="ITEM_BGCOLOR" value="21" enum="ItemType"> + </constant> + <constant name="ITEM_FGCOLOR" value="22" enum="ItemType"> + </constant> + <constant name="ITEM_META" value="23" enum="ItemType"> </constant> - <constant name="ITEM_DROPCAP" value="22" enum="ItemType"> + <constant name="ITEM_DROPCAP" value="24" enum="ItemType"> </constant> - <constant name="ITEM_CUSTOMFX" value="23" enum="ItemType"> + <constant name="ITEM_CUSTOMFX" value="25" enum="ItemType"> </constant> </constants> <theme_items> diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp index 987d05bf71..7db6665e82 100644 --- a/scene/gui/rich_text_label.cpp +++ b/scene/gui/rich_text_label.cpp @@ -934,6 +934,11 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o } } + Vector2 fbg_line_off = off + p_ofs; + // Draw background color box + Vector2i chr_range = TS->shaped_text_get_range(rid); + _draw_fbg_boxes(ci, rid, fbg_line_off, it_from, it_to, chr_range.x, chr_range.y, 0); + // Draw main text. Color selection_fg = get_theme_color("font_selected_color"); Color selection_bg = get_theme_color("selection_color"); @@ -1079,6 +1084,9 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o off.x += glyphs[i].advance; } } + // Draw foreground color box + _draw_fbg_boxes(ci, rid, fbg_line_off, it_from, it_to, chr_range.x, chr_range.y, 1); + off.y += TS->shaped_text_get_descent(rid) + l.text_buf->get_spacing_bottom(); } @@ -2036,6 +2044,36 @@ bool RichTextLabel::_find_meta(Item *p_item, Variant *r_meta, ItemMeta **r_item) return false; } +Color RichTextLabel::_find_bgcolor(Item *p_item) { + Item *item = p_item; + + while (item) { + if (item->type == ITEM_BGCOLOR) { + ItemBGColor *color = static_cast<ItemBGColor *>(item); + return color->color; + } + + item = item->parent; + } + + return Color(0, 0, 0, 0); +} + +Color RichTextLabel::_find_fgcolor(Item *p_item) { + Item *item = p_item; + + while (item) { + if (item->type == ITEM_FGCOLOR) { + ItemFGColor *color = static_cast<ItemFGColor *>(item); + return color->color; + } + + item = item->parent; + } + + return Color(0, 0, 0, 0); +} + bool RichTextLabel::_find_layout_subitem(Item *from, Item *to) { if (from && from != to) { if (from->type != ITEM_FONT && from->type != ITEM_COLOR && from->type != ITEM_UNDERLINE && from->type != ITEM_STRIKETHROUGH) { @@ -2546,6 +2584,22 @@ void RichTextLabel::push_rainbow(float p_saturation, float p_value, float p_freq _add_item(item, true); } +void RichTextLabel::push_bgcolor(const Color &p_color) { + ERR_FAIL_COND(current->type == ITEM_TABLE); + ItemBGColor *item = memnew(ItemBGColor); + + item->color = p_color; + _add_item(item, true); +} + +void RichTextLabel::push_fgcolor(const Color &p_color) { + ERR_FAIL_COND(current->type == ITEM_TABLE); + ItemFGColor *item = memnew(ItemFGColor); + + item->color = p_color; + _add_item(item, true); +} + void RichTextLabel::push_customfx(Ref<RichTextEffect> p_custom_effect, Dictionary p_environment) { ItemCustomFX *item = memnew(ItemCustomFX); item->custom_effect = p_custom_effect; @@ -3352,6 +3406,23 @@ Error RichTextLabel::append_bbcode(const String &p_bbcode) { pos = brk_end + 1; tag_stack.push_front("rainbow"); set_process_internal(true); + + } else if (tag.begins_with("bgcolor=")) { + String color_str = tag.substr(8, tag.length()); + Color color = Color::from_string(color_str, base_color); + + push_bgcolor(color); + pos = brk_end + 1; + tag_stack.push_front("bgcolor"); + + } else if (tag.begins_with("fgcolor=")) { + String color_str = tag.substr(8, tag.length()); + Color color = Color::from_string(color_str, base_color); + + push_fgcolor(color); + pos = brk_end + 1; + tag_stack.push_front("fgcolor"); + } else { Vector<String> &expr = split_tag_block; if (expr.size() < 1) { @@ -3918,6 +3989,8 @@ void RichTextLabel::_bind_methods() { ClassDB::bind_method(D_METHOD("set_cell_size_override", "min_size", "max_size"), &RichTextLabel::set_cell_size_override); ClassDB::bind_method(D_METHOD("set_cell_padding", "padding"), &RichTextLabel::set_cell_padding); ClassDB::bind_method(D_METHOD("push_cell"), &RichTextLabel::push_cell); + ClassDB::bind_method(D_METHOD("push_fgcolor", "fgcolor"), &RichTextLabel::push_fgcolor); + ClassDB::bind_method(D_METHOD("push_bgcolor", "bgcolor"), &RichTextLabel::push_bgcolor); ClassDB::bind_method(D_METHOD("pop"), &RichTextLabel::pop); ClassDB::bind_method(D_METHOD("clear"), &RichTextLabel::clear); @@ -4056,6 +4129,8 @@ void RichTextLabel::_bind_methods() { BIND_ENUM_CONSTANT(ITEM_WAVE); BIND_ENUM_CONSTANT(ITEM_TORNADO); BIND_ENUM_CONSTANT(ITEM_RAINBOW); + BIND_ENUM_CONSTANT(ITEM_BGCOLOR); + BIND_ENUM_CONSTANT(ITEM_FGCOLOR); BIND_ENUM_CONSTANT(ITEM_META); BIND_ENUM_CONSTANT(ITEM_DROPCAP); BIND_ENUM_CONSTANT(ITEM_CUSTOMFX); @@ -4108,6 +4183,65 @@ Size2 RichTextLabel::get_minimum_size() const { return size; } +void RichTextLabel::_draw_fbg_boxes(RID p_ci, RID p_rid, Vector2 line_off, Item *it_from, Item *it_to, int start, int end, int fbg_flag) { + Vector2i fbg_index = Vector2i(end, start); + Color last_color = Color(0, 0, 0, 0); + bool draw_box = false; + // Draw a box based on color tags associated with glyphs + for (int i = start; i < end; i++) { + Item *it = _get_item_at_pos(it_from, it_to, i); + Color color = Color(0, 0, 0, 0); + + if (fbg_flag == 0) { + color = _find_bgcolor(it); + } else { + color = _find_fgcolor(it); + } + + bool change_to_color = ((color.a > 0) && ((last_color.a - 0.0) < 0.01)); + bool change_from_color = (((color.a - 0.0) < 0.01) && (last_color.a > 0.0)); + bool change_color = (((color.a > 0) == (last_color.a > 0)) && (color != last_color)); + + if (change_to_color) { + fbg_index.x = MIN(i, fbg_index.x); + fbg_index.y = MAX(i, fbg_index.y); + } + + if (change_from_color || change_color) { + fbg_index.x = MIN(i, fbg_index.x); + fbg_index.y = MAX(i, fbg_index.y); + draw_box = true; + } + + if (draw_box) { + Vector<Vector2> sel = TS->shaped_text_get_selection(p_rid, fbg_index.x, fbg_index.y); + for (int j = 0; j < sel.size(); j++) { + Vector2 rect_off = line_off + Vector2(sel[j].x, -TS->shaped_text_get_ascent(p_rid)); + Vector2 rect_size = Vector2(sel[j].y - sel[j].x, TS->shaped_text_get_size(p_rid).y); + RenderingServer::get_singleton()->canvas_item_add_rect(p_ci, Rect2(rect_off, rect_size), last_color); + } + fbg_index = Vector2i(end, start); + draw_box = false; + } + + if (change_color) { + fbg_index.x = MIN(i, fbg_index.x); + fbg_index.y = MAX(i, fbg_index.y); + } + + last_color = color; + } + + if (last_color.a > 0) { + Vector<Vector2> sel = TS->shaped_text_get_selection(p_rid, fbg_index.x, end); + for (int i = 0; i < sel.size(); i++) { + Vector2 rect_off = line_off + Vector2(sel[i].x, -TS->shaped_text_get_ascent(p_rid)); + Vector2 rect_size = Vector2(sel[i].y - sel[i].x, TS->shaped_text_get_size(p_rid).y); + RenderingServer::get_singleton()->canvas_item_add_rect(p_ci, Rect2(rect_off, rect_size), last_color); + } + } +} + Ref<RichTextEffect> RichTextLabel::_get_custom_effect_by_code(String p_bbcode_identifier) { for (int i = 0; i < custom_effects.size(); i++) { if (!custom_effects[i].is_valid()) { diff --git a/scene/gui/rich_text_label.h b/scene/gui/rich_text_label.h index 9cf94b0cd7..9bcb9e93c9 100644 --- a/scene/gui/rich_text_label.h +++ b/scene/gui/rich_text_label.h @@ -75,6 +75,8 @@ public: ITEM_WAVE, ITEM_TORNADO, ITEM_RAINBOW, + ITEM_BGCOLOR, + ITEM_FGCOLOR, ITEM_META, ITEM_DROPCAP, ITEM_CUSTOMFX @@ -307,6 +309,16 @@ private: ItemRainbow() { type = ITEM_RAINBOW; } }; + struct ItemBGColor : public Item { + Color color; + ItemBGColor() { type = ITEM_BGCOLOR; } + }; + + struct ItemFGColor : public Item { + Color color; + ItemFGColor() { type = ITEM_FGCOLOR; } + }; + struct ItemCustomFX : public ItemFX { Ref<CharFXTransform> char_fx_transform; Ref<RichTextEffect> custom_effect; @@ -422,6 +434,8 @@ private: bool _find_underline(Item *p_item); bool _find_strikethrough(Item *p_item); bool _find_meta(Item *p_item, Variant *r_meta, ItemMeta **r_item = nullptr); + Color _find_bgcolor(Item *p_item); + Color _find_fgcolor(Item *p_item); bool _find_layout_subitem(Item *from, Item *to); void _fetch_item_fx_stack(Item *p_item, Vector<ItemFX *> &r_stack); @@ -437,6 +451,8 @@ private: Ref<RichTextEffect> _get_custom_effect_by_code(String p_bbcode_identifier); virtual Dictionary parse_expressions_for_values(Vector<String> p_expressions); + void _draw_fbg_boxes(RID p_ci, RID p_rid, Vector2 line_off, Item *it_from, Item *it_to, int start, int end, int fbg_flag); + bool use_bbcode = false; String bbcode; @@ -474,6 +490,8 @@ public: void push_wave(float p_frequency, float p_amplitude); void push_tornado(float p_frequency, float p_radius); void push_rainbow(float p_saturation, float p_value, float p_frequency); + void push_bgcolor(const Color &p_color); + void push_fgcolor(const Color &p_color); void push_customfx(Ref<RichTextEffect> p_custom_effect, Dictionary p_environment); void set_table_column_expand(int p_column, bool p_expand, int p_ratio = 1); void set_cell_row_background_color(const Color &p_odd_row_bg, const Color &p_even_row_bg); |