Rich Text Label now allows for foreground colors and background colors

This commit is contained in:
golfinq 2020-01-26 17:11:09 -05:00 committed by golfinq
parent d88be9b70c
commit 0c1d10d1ca
3 changed files with 177 additions and 3 deletions

View File

@ -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_DROPCAP" value="22" enum="ItemType">
<constant name="ITEM_FGCOLOR" value="22" enum="ItemType">
</constant>
<constant name="ITEM_CUSTOMFX" value="23" enum="ItemType">
<constant name="ITEM_META" value="23" enum="ItemType">
</constant>
<constant name="ITEM_DROPCAP" value="24" enum="ItemType">
</constant>
<constant name="ITEM_CUSTOMFX" value="25" enum="ItemType">
</constant>
</constants>
<theme_items>

View File

@ -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()) {

View File

@ -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);