ソースを参照

Merge pull request #35608 from golfinq/master

Rémi Verschelde 4 年 前
コミット
953de68cfc
3 ファイル変更177 行追加3 行削除
  1. 25 3
      doc/classes/RichTextLabel.xml
  2. 134 0
      scene/gui/rich_text_label.cpp
  3. 18 0
      scene/gui/rich_text_label.h

+ 25 - 3
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>

+ 134 - 0
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()) {

+ 18 - 0
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);