فهرست منبع

Merge pull request #39113 from nekomatata/bbcode-image-color

Add color option for img bbcode tag in RichTextLabel to tint images
Rémi Verschelde 5 سال پیش
والد
کامیت
901832e21c
3فایلهای تغییر یافته به همراه159 افزوده شده و 149 حذف شده
  1. 3 1
      doc/classes/RichTextLabel.xml
  2. 152 147
      scene/gui/rich_text_label.cpp
  3. 4 1
      scene/gui/rich_text_label.h

+ 3 - 1
doc/classes/RichTextLabel.xml

@@ -20,8 +20,10 @@
 			</argument>
 			<argument index="2" name="height" type="int" default="0">
 			</argument>
+			<argument index="3" name="color" type="Color" default="Color( 1, 1, 1, 1 )">
+			</argument>
 			<description>
-				Adds an image's opening and closing tags to the tag stack, optionally providing a [code]width[/code] and [code]height[/code] to resize the image.
+				Adds an image's opening and closing tags to the tag stack, optionally providing a [code]width[/code] and [code]height[/code] to resize the image and a [code]color[/code] to tint the image.
 				If [code]width[/code] or [code]height[/code] is set to 0, the image size will be adjusted in order to keep the original aspect ratio.
 			</description>
 		</method>

+ 152 - 147
scene/gui/rich_text_label.cpp

@@ -646,7 +646,7 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int &
 				}
 
 				if (p_mode == PROCESS_DRAW && visible) {
-					img->image->draw_rect(ci, Rect2(p_ofs + Point2(align_ofs + wofs, y + lh - font->get_descent() - img->size.height), img->size));
+					img->image->draw_rect(ci, Rect2(p_ofs + Point2(align_ofs + wofs, y + lh - font->get_descent() - img->size.height), img->size), false, img->color);
 				}
 				p_char_count++;
 
@@ -1443,6 +1443,46 @@ void RichTextLabel::_fetch_item_fx_stack(Item *p_item, Vector<ItemFX *> &r_stack
 	}
 }
 
+Color RichTextLabel::_get_color_from_string(const String &p_color_str, const Color &p_default_color) {
+	if (p_color_str.begins_with("#")) {
+		return Color::html(p_color_str);
+	} else if (p_color_str == "aqua") {
+		return Color(0, 1, 1);
+	} else if (p_color_str == "black") {
+		return Color(0, 0, 0);
+	} else if (p_color_str == "blue") {
+		return Color(0, 0, 1);
+	} else if (p_color_str == "fuchsia") {
+		return Color(1, 0, 1);
+	} else if (p_color_str == "gray" || p_color_str == "grey") {
+		return Color(0.5, 0.5, 0.5);
+	} else if (p_color_str == "green") {
+		return Color(0, 0.5, 0);
+	} else if (p_color_str == "lime") {
+		return Color(0, 1, 0);
+	} else if (p_color_str == "maroon") {
+		return Color(0.5, 0, 0);
+	} else if (p_color_str == "navy") {
+		return Color(0, 0, 0.5);
+	} else if (p_color_str == "olive") {
+		return Color(0.5, 0.5, 0);
+	} else if (p_color_str == "purple") {
+		return Color(0.5, 0, 0.5);
+	} else if (p_color_str == "red") {
+		return Color(1, 0, 0);
+	} else if (p_color_str == "silver") {
+		return Color(0.75, 0.75, 0.75);
+	} else if (p_color_str == "teal") {
+		return Color(0, 0.5, 0.5);
+	} else if (p_color_str == "white") {
+		return Color(1, 1, 1);
+	} else if (p_color_str == "yellow") {
+		return Color(1, 1, 0);
+	} else {
+		return p_default_color;
+	}
+}
+
 bool RichTextLabel::_find_meta(Item *p_item, Variant *r_meta, ItemMeta **r_item) {
 	Item *item = p_item;
 
@@ -1636,7 +1676,7 @@ void RichTextLabel::_remove_item(Item *p_item, const int p_line, const int p_sub
 	}
 }
 
-void RichTextLabel::add_image(const Ref<Texture2D> &p_image, const int p_width, const int p_height) {
+void RichTextLabel::add_image(const Ref<Texture2D> &p_image, const int p_width, const int p_height, const Color &p_color) {
 	if (current->type == ITEM_TABLE) {
 		return;
 	}
@@ -1645,6 +1685,7 @@ void RichTextLabel::add_image(const Ref<Texture2D> &p_image, const int p_width,
 	ItemImage *item = memnew(ItemImage);
 
 	item->image = p_image;
+	item->color = p_color;
 
 	if (p_width > 0) {
 		// custom width
@@ -2034,7 +2075,32 @@ Error RichTextLabel::append_bbcode(const String &p_bbcode) {
 
 		String tag = p_bbcode.substr(brk_pos + 1, brk_end - brk_pos - 1);
 		Vector<String> split_tag_block = tag.split(" ", false);
-		String bbcode = !split_tag_block.empty() ? split_tag_block[0] : "";
+
+		// Find optional parameters.
+		String bbcode_name;
+		typedef Map<String, String> OptionMap;
+		OptionMap bbcode_options;
+		if (!split_tag_block.empty()) {
+			bbcode_name = split_tag_block[0];
+			for (int i = 1; i < split_tag_block.size(); i++) {
+				const String &expr = split_tag_block[i];
+				int value_pos = expr.find("=");
+				if (value_pos > -1) {
+					bbcode_options[expr.substr(0, value_pos)] = expr.substr(value_pos + 1);
+				}
+			}
+		} else {
+			bbcode_name = tag;
+		}
+
+		// Find main parameter.
+		String bbcode_value;
+		int main_value_pos = bbcode_name.find("=");
+		if (main_value_pos > -1) {
+			bbcode_value = bbcode_name.substr(main_value_pos + 1);
+			bbcode_name = bbcode_name.substr(0, main_value_pos);
+		}
+
 		if (tag.begins_with("/") && tag_stack.size()) {
 			bool tag_ok = tag_stack.size() && tag_stack.front()->get() == tag.substr(1, tag.length());
 
@@ -2160,7 +2226,7 @@ Error RichTextLabel::append_bbcode(const String &p_bbcode) {
 			push_meta(url);
 			pos = brk_end + 1;
 			tag_stack.push_front("url");
-		} else if (tag == "img") {
+		} else if (bbcode_name == "img") {
 			int end = p_bbcode.find("[", brk_end);
 			if (end == -1) {
 				end = p_bbcode.length();
@@ -2170,80 +2236,42 @@ Error RichTextLabel::append_bbcode(const String &p_bbcode) {
 
 			Ref<Texture2D> texture = ResourceLoader::load(image, "Texture2D");
 			if (texture.is_valid()) {
-				add_image(texture);
-			}
-
-			pos = end;
-			tag_stack.push_front(tag);
-		} else if (tag.begins_with("img=")) {
-			int width = 0;
-			int height = 0;
-
-			String params = tag.substr(4, tag.length());
-			int sep = params.find("x");
-			if (sep == -1) {
-				width = params.to_int();
-			} else {
-				width = params.substr(0, sep).to_int();
-				height = params.substr(sep + 1, params.length()).to_int();
-			}
+				Color color = Color(1.0, 1.0, 1.0);
+				OptionMap::Element *color_option = bbcode_options.find("color");
+				if (color_option) {
+					color = _get_color_from_string(color_option->value(), color);
+				}
 
-			int end = p_bbcode.find("[", brk_end);
-			if (end == -1) {
-				end = p_bbcode.length();
-			}
+				int width = 0;
+				int height = 0;
+				if (!bbcode_value.empty()) {
+					int sep = bbcode_value.find("x");
+					if (sep == -1) {
+						width = bbcode_value.to_int();
+					} else {
+						width = bbcode_value.substr(0, sep).to_int();
+						height = bbcode_value.substr(sep + 1).to_int();
+					}
+				} else {
+					OptionMap::Element *width_option = bbcode_options.find("width");
+					if (width_option) {
+						width = width_option->value().to_int();
+					}
 
-			String image = p_bbcode.substr(brk_end + 1, end - brk_end - 1);
+					OptionMap::Element *height_option = bbcode_options.find("height");
+					if (height_option) {
+						height = height_option->value().to_int();
+					}
+				}
 
-			Ref<Texture2D> texture = ResourceLoader::load(image, "Texture");
-			if (texture.is_valid()) {
-				add_image(texture, width, height);
+				add_image(texture, width, height, color);
 			}
 
 			pos = end;
-			tag_stack.push_front("img");
+			tag_stack.push_front(bbcode_name);
 		} else if (tag.begins_with("color=")) {
-			String col = tag.substr(6, tag.length());
-			Color color;
-
-			if (col.begins_with("#")) {
-				color = Color::html(col);
-			} else if (col == "aqua") {
-				color = Color(0, 1, 1);
-			} else if (col == "black") {
-				color = Color(0, 0, 0);
-			} else if (col == "blue") {
-				color = Color(0, 0, 1);
-			} else if (col == "fuchsia") {
-				color = Color(1, 0, 1);
-			} else if (col == "gray" || col == "grey") {
-				color = Color(0.5, 0.5, 0.5);
-			} else if (col == "green") {
-				color = Color(0, 0.5, 0);
-			} else if (col == "lime") {
-				color = Color(0, 1, 0);
-			} else if (col == "maroon") {
-				color = Color(0.5, 0, 0);
-			} else if (col == "navy") {
-				color = Color(0, 0, 0.5);
-			} else if (col == "olive") {
-				color = Color(0.5, 0.5, 0);
-			} else if (col == "purple") {
-				color = Color(0.5, 0, 0.5);
-			} else if (col == "red") {
-				color = Color(1, 0, 0);
-			} else if (col == "silver") {
-				color = Color(0.75, 0.75, 0.75);
-			} else if (col == "teal") {
-				color = Color(0, 0.5, 0.5);
-			} else if (col == "white") {
-				color = Color(1, 1, 1);
-			} else if (col == "yellow") {
-				color = Color(1, 1, 0);
-			} else {
-				color = base_color;
-			}
-
+			String color_str = tag.substr(6, tag.length());
+			Color color = _get_color_from_string(color_str, base_color);
 			push_color(color);
 			pos = brk_end + 1;
 			tag_stack.push_front("color");
@@ -2261,113 +2289,90 @@ Error RichTextLabel::append_bbcode(const String &p_bbcode) {
 			pos = brk_end + 1;
 			tag_stack.push_front("font");
 
-		} else if (bbcode == "fade") {
-			int startIndex = 0;
-			int length = 10;
+		} else if (bbcode_name == "fade") {
+			int start_index = 0;
+			OptionMap::Element *start_option = bbcode_options.find("start");
+			if (start_option) {
+				start_index = start_option->value().to_int();
+			}
 
-			if (split_tag_block.size() > 1) {
-				split_tag_block.remove(0);
-				for (int i = 0; i < split_tag_block.size(); i++) {
-					String expr = split_tag_block[i];
-					if (expr.begins_with("start=")) {
-						String start_str = expr.substr(6, expr.length());
-						startIndex = start_str.to_int();
-					} else if (expr.begins_with("length=")) {
-						String end_str = expr.substr(7, expr.length());
-						length = end_str.to_int();
-					}
-				}
+			int length = 10;
+			OptionMap::Element *length_option = bbcode_options.find("length");
+			if (length_option) {
+				length = length_option->value().to_int();
 			}
 
-			push_fade(startIndex, length);
+			push_fade(start_index, length);
 			pos = brk_end + 1;
 			tag_stack.push_front("fade");
-		} else if (bbcode == "shake") {
+		} else if (bbcode_name == "shake") {
 			int strength = 5;
-			float rate = 20.0f;
+			OptionMap::Element *strength_option = bbcode_options.find("level");
+			if (strength_option) {
+				strength = strength_option->value().to_int();
+			}
 
-			if (split_tag_block.size() > 1) {
-				split_tag_block.remove(0);
-				for (int i = 0; i < split_tag_block.size(); i++) {
-					String expr = split_tag_block[i];
-					if (expr.begins_with("level=")) {
-						String str_str = expr.substr(6, expr.length());
-						strength = str_str.to_int();
-					} else if (expr.begins_with("rate=")) {
-						String rate_str = expr.substr(5, expr.length());
-						rate = rate_str.to_float();
-					}
-				}
+			float rate = 20.0f;
+			OptionMap::Element *rate_option = bbcode_options.find("rate");
+			if (rate_option) {
+				rate = rate_option->value().to_float();
 			}
 
 			push_shake(strength, rate);
 			pos = brk_end + 1;
 			tag_stack.push_front("shake");
 			set_process_internal(true);
-		} else if (bbcode == "wave") {
+		} else if (bbcode_name == "wave") {
 			float amplitude = 20.0f;
-			float period = 5.0f;
+			OptionMap::Element *amplitude_option = bbcode_options.find("amp");
+			if (amplitude_option) {
+				amplitude = amplitude_option->value().to_float();
+			}
 
-			if (split_tag_block.size() > 1) {
-				split_tag_block.remove(0);
-				for (int i = 0; i < split_tag_block.size(); i++) {
-					String expr = split_tag_block[i];
-					if (expr.begins_with("amp=")) {
-						String amp_str = expr.substr(4, expr.length());
-						amplitude = amp_str.to_float();
-					} else if (expr.begins_with("freq=")) {
-						String period_str = expr.substr(5, expr.length());
-						period = period_str.to_float();
-					}
-				}
+			float period = 5.0f;
+			OptionMap::Element *period_option = bbcode_options.find("freq");
+			if (period_option) {
+				period = period_option->value().to_float();
 			}
 
 			push_wave(period, amplitude);
 			pos = brk_end + 1;
 			tag_stack.push_front("wave");
 			set_process_internal(true);
-		} else if (bbcode == "tornado") {
+		} else if (bbcode_name == "tornado") {
 			float radius = 10.0f;
-			float frequency = 1.0f;
+			OptionMap::Element *radius_option = bbcode_options.find("radius");
+			if (radius_option) {
+				radius = radius_option->value().to_float();
+			}
 
-			if (split_tag_block.size() > 1) {
-				split_tag_block.remove(0);
-				for (int i = 0; i < split_tag_block.size(); i++) {
-					String expr = split_tag_block[i];
-					if (expr.begins_with("radius=")) {
-						String amp_str = expr.substr(7, expr.length());
-						radius = amp_str.to_float();
-					} else if (expr.begins_with("freq=")) {
-						String period_str = expr.substr(5, expr.length());
-						frequency = period_str.to_float();
-					}
-				}
+			float frequency = 1.0f;
+			OptionMap::Element *frequency_option = bbcode_options.find("freq");
+			if (frequency_option) {
+				frequency = frequency_option->value().to_float();
 			}
 
 			push_tornado(frequency, radius);
 			pos = brk_end + 1;
 			tag_stack.push_front("tornado");
 			set_process_internal(true);
-		} else if (bbcode == "rainbow") {
+		} else if (bbcode_name == "rainbow") {
 			float saturation = 0.8f;
+			OptionMap::Element *saturation_option = bbcode_options.find("sat");
+			if (saturation_option) {
+				saturation = saturation_option->value().to_float();
+			}
+
 			float value = 0.8f;
-			float frequency = 1.0f;
+			OptionMap::Element *value_option = bbcode_options.find("val");
+			if (value_option) {
+				value = value_option->value().to_float();
+			}
 
-			if (split_tag_block.size() > 1) {
-				split_tag_block.remove(0);
-				for (int i = 0; i < split_tag_block.size(); i++) {
-					String expr = split_tag_block[i];
-					if (expr.begins_with("sat=")) {
-						String sat_str = expr.substr(4, expr.length());
-						saturation = sat_str.to_float();
-					} else if (expr.begins_with("val=")) {
-						String val_str = expr.substr(4, expr.length());
-						value = val_str.to_float();
-					} else if (expr.begins_with("freq=")) {
-						String freq_str = expr.substr(5, expr.length());
-						frequency = freq_str.to_float();
-					}
-				}
+			float frequency = 1.0f;
+			OptionMap::Element *frequency_option = bbcode_options.find("freq");
+			if (frequency_option) {
+				frequency = frequency_option->value().to_float();
 			}
 
 			push_rainbow(saturation, value, frequency);
@@ -2634,7 +2639,7 @@ void RichTextLabel::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("get_text"), &RichTextLabel::get_text);
 	ClassDB::bind_method(D_METHOD("add_text", "text"), &RichTextLabel::add_text);
 	ClassDB::bind_method(D_METHOD("set_text", "text"), &RichTextLabel::set_text);
-	ClassDB::bind_method(D_METHOD("add_image", "image", "width", "height"), &RichTextLabel::add_image, DEFVAL(0), DEFVAL(0));
+	ClassDB::bind_method(D_METHOD("add_image", "image", "width", "height", "color"), &RichTextLabel::add_image, DEFVAL(0), DEFVAL(0), DEFVAL(Color(1.0, 1.0, 1.0)));
 	ClassDB::bind_method(D_METHOD("newline"), &RichTextLabel::add_newline);
 	ClassDB::bind_method(D_METHOD("remove_line", "line"), &RichTextLabel::remove_line);
 	ClassDB::bind_method(D_METHOD("push_font", "font"), &RichTextLabel::push_font);

+ 4 - 1
scene/gui/rich_text_label.h

@@ -149,6 +149,7 @@ private:
 	struct ItemImage : public Item {
 		Ref<Texture2D> image;
 		Size2 size;
+		Color color;
 		ItemImage() { type = ITEM_IMAGE; }
 	};
 
@@ -381,6 +382,8 @@ private:
 	bool _find_by_type(Item *p_item, ItemType p_type);
 	void _fetch_item_fx_stack(Item *p_item, Vector<ItemFX *> &r_stack);
 
+	static Color _get_color_from_string(const String &p_color_str, const Color &p_default_color);
+
 	void _update_scroll();
 	void _update_fx(ItemFrame *p_frame, float p_delta_time);
 	void _scroll_changed(double);
@@ -406,7 +409,7 @@ protected:
 public:
 	String get_text();
 	void add_text(const String &p_text);
-	void add_image(const Ref<Texture2D> &p_image, const int p_width = 0, const int p_height = 0);
+	void add_image(const Ref<Texture2D> &p_image, const int p_width = 0, const int p_height = 0, const Color &p_color = Color(1.0, 1.0, 1.0));
 	void add_newline();
 	bool remove_line(const int p_line);
 	void push_font(const Ref<Font> &p_font);