瀏覽代碼

[Complex Text Layouts] Refactor RichTextLabel.

bruvzg 5 年之前
父節點
當前提交
6b6f101983

+ 11 - 20
doc/classes/CharFXTransform.xml

@@ -13,24 +13,6 @@
 	<methods>
 	</methods>
 	<members>
-		<member name="absolute_index" type="int" setter="set_absolute_index" getter="get_absolute_index" default="0">
-			The index of the current character (starting from 0). Setting this property won't affect drawing.
-		</member>
-		<member name="character" type="int" setter="set_character" getter="get_character" default="0">
-			The Unicode codepoint the character will use. This only affects non-whitespace characters. [method @GDScript.ord] can be useful here. For example, the following will replace all characters with asterisks:
-			[codeblocks]
-			[gdscript]
-			# `char_fx` is the CharFXTransform parameter from `_process_custom_fx()`.
-			# See the RichTextEffect documentation for details.
-			char_fx.character = ord("*")
-			[/gdscript]
-			[csharp]
-			// `char_fx` is the CharFXTransform parameter from `_process_custom_fx()`.
-			// See the RichTextEffect documentation for details.
-			charFx.Character = char.GetNumericValue('*');
-			[/csharp]
-			[/codeblocks]
-		</member>
 		<member name="color" type="Color" setter="set_color" getter="get_color" default="Color( 0, 0, 0, 1 )">
 			The color the character will be drawn with.
 		</member>
@@ -45,11 +27,20 @@
 			{"foo": "hello", "bar": true, "baz": 42, "color": Color(1, 1, 1, 1)}
 			[/codeblock]
 		</member>
+		<member name="font" type="RID" setter="set_font" getter="get_font">
+			Font resource used to render glyph.
+		</member>
+		<member name="glyph_index" type="int" setter="set_glyph_index" getter="get_glyph_index" default="0">
+			Font specific glyph index.
+		</member>
 		<member name="offset" type="Vector2" setter="set_offset" getter="get_offset" default="Vector2( 0, 0 )">
 			The position offset the character will be drawn with (in pixels).
 		</member>
-		<member name="relative_index" type="int" setter="set_relative_index" getter="get_relative_index" default="0">
-			The index of the current character (starting from 0). Setting this property won't affect drawing.
+		<member name="outline" type="bool" setter="set_outline" getter="is_outline" default="false">
+			If [code]ture[/code], FX transform is called for outline drawing. Setting this property won't affect drawing.
+		</member>
+		<member name="range" type="Vector2i" setter="set_range" getter="get_range" default="Vector2i( 0, 0 )">
+			Absolute character range in the string, corresponding to the glyph. Setting this property won't affect drawing.
 		</member>
 		<member name="visible" type="bool" setter="set_visibility" getter="is_visible" default="true">
 			If [code]true[/code], the character will be drawn. If [code]false[/code], the character will be hidden. Characters around hidden characters will reflow to take the space of hidden characters. If this is not desired, set their [member color] to [code]Color(1, 1, 1, 0)[/code] instead.

+ 164 - 27
doc/classes/RichTextLabel.xml

@@ -25,6 +25,8 @@
 			</argument>
 			<argument index="3" name="color" type="Color" default="Color( 1, 1, 1, 1 )">
 			</argument>
+			<argument index="4" name="inline_align" type="int" enum="VAlign" default="0">
+			</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 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.
@@ -132,15 +134,6 @@
 				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_align">
-			<return type="void">
-			</return>
-			<argument index="0" name="align" type="int" enum="RichTextLabel.Align">
-			</argument>
-			<description>
-				Adds an [code][align][/code] tag based on the given [code]align[/code] value. See [enum Align] for possible values.
-			</description>
-		</method>
 		<method name="push_bold">
 			<return type="void">
 			</return>
@@ -180,6 +173,24 @@
 				Adds a [code][font][/code] tag to the tag stack. Overrides default fonts for its duration.
 			</description>
 		</method>
+		<method name="push_font_features">
+			<return type="void">
+			</return>
+			<argument index="0" name="opentype_features" type="Dictionary">
+			</argument>
+			<description>
+				Adds a [code][ot_feature][/code] tag to the tag stack. Overrides default OpenType font feature for its duration.
+			</description>
+		</method>
+		<method name="push_font_size">
+			<return type="void">
+			</return>
+			<argument index="0" name="font_size" type="int">
+			</argument>
+			<description>
+				Adds a [code][font_size][/code] tag to the tag stack. Overrides default font size for its duration.
+			</description>
+		</method>
 		<method name="push_indent">
 			<return type="void">
 			</return>
@@ -199,10 +210,14 @@
 		<method name="push_list">
 			<return type="void">
 			</return>
-			<argument index="0" name="type" type="int" enum="RichTextLabel.ListType">
+			<argument index="0" name="level" type="int">
+			</argument>
+			<argument index="1" name="type" type="int" enum="RichTextLabel.ListType">
+			</argument>
+			<argument index="2" name="capitalize" type="bool">
 			</argument>
 			<description>
-				Adds a [code][list][/code] tag to the tag stack. Similar to the BBCodes [code][ol][/code] or [code][ul][/code], but supports more list types. Not fully implemented!
+				Adds [code][ol][/code] or [code][ul][/code] tag to the tag stack. Multiplies [code]level[/code] by current [member tab_size] to determine new margin length.
 			</description>
 		</method>
 		<method name="push_meta">
@@ -228,6 +243,39 @@
 				Adds a [code][font][/code] tag with a normal font to the tag stack.
 			</description>
 		</method>
+		<method name="push_outline_color">
+			<return type="void">
+			</return>
+			<argument index="0" name="color" type="Color">
+			</argument>
+			<description>
+				Adds a [code][outline_color][/code] tag to the tag stack. Adds text outline for its duration.
+			</description>
+		</method>
+		<method name="push_outline_size">
+			<return type="void">
+			</return>
+			<argument index="0" name="outline_size" type="int">
+			</argument>
+			<description>
+				Adds a [code][outline_size][/code] tag to the tag stack. Overrides default text outline size for its duration.
+			</description>
+		</method>
+		<method name="push_paragraph">
+			<return type="void">
+			</return>
+			<argument index="0" name="align" type="int" enum="RichTextLabel.Align">
+			</argument>
+			<argument index="1" name="base_direction" type="int" enum="Control.TextDirection" default="0">
+			</argument>
+			<argument index="2" name="language" type="String" default="&quot;&quot;">
+			</argument>
+			<argument index="3" name="st_parser" type="int" enum="Control.StructuredTextParser" default="0">
+			</argument>
+			<description>
+				Adds a [code][p][/code] tag to the tag stack.
+			</description>
+		</method>
 		<method name="push_strikethrough">
 			<return type="void">
 			</return>
@@ -240,8 +288,10 @@
 			</return>
 			<argument index="0" name="columns" type="int">
 			</argument>
+			<argument index="1" name="inline_align" type="int" enum="VAlign" default="0">
+			</argument>
 			<description>
-				Adds a [code][table=columns][/code] tag to the tag stack.
+				Adds a [code][table=columns,inline_align][/code] tag to the tag stack.
 			</description>
 		</method>
 		<method name="push_underline">
@@ -270,6 +320,46 @@
 				Scrolls the window's top line to match [code]line[/code].
 			</description>
 		</method>
+		<method name="set_cell_border_color">
+			<return type="void">
+			</return>
+			<argument index="0" name="color" type="Color">
+			</argument>
+			<description>
+				Sets color of a table cell border.
+			</description>
+		</method>
+		<method name="set_cell_padding">
+			<return type="void">
+			</return>
+			<argument index="0" name="padding" type="Rect2">
+			</argument>
+			<description>
+				Sets inner padding of a table cell.
+			</description>
+		</method>
+		<method name="set_cell_row_background_color">
+			<return type="void">
+			</return>
+			<argument index="0" name="odd_row_bg" type="Color">
+			</argument>
+			<argument index="1" name="even_row_bg" type="Color">
+			</argument>
+			<description>
+				Sets color of a table cell. Separate colors for alternating rows can be specified.
+			</description>
+		</method>
+		<method name="set_cell_size_override">
+			<return type="void">
+			</return>
+			<argument index="0" name="min_size" type="Vector2">
+			</argument>
+			<argument index="1" name="max_size" type="Vector2">
+			</argument>
+			<description>
+				Sets minimum and maximum size overrides for a table cell.
+			</description>
+		</method>
 		<method name="set_table_column_expand">
 			<return type="void">
 			</return>
@@ -302,6 +392,9 @@
 			If [code]true[/code], the label's height will be automatically updated to fit its content.
 			[b]Note:[/b] This property is used as a workaround to fix issues with [RichTextLabel] in [Container]s, but it's unreliable in some cases and will be removed in future versions.
 		</member>
+		<member name="language" type="String" setter="set_language" getter="get_language" default="&quot;&quot;">
+			Language code used for line-breaking and text shaping algorithms, if left empty current locale is used instead.
+		</member>
 		<member name="meta_underlined" type="bool" setter="set_meta_underline" getter="is_meta_underlined" default="true">
 			If [code]true[/code], the label underlines meta tags such as [code][url]{text}[/url][/code].
 		</member>
@@ -322,6 +415,12 @@
 		<member name="selection_enabled" type="bool" setter="set_selection_enabled" getter="is_selection_enabled" default="false">
 			If [code]true[/code], the label allows text selection.
 		</member>
+		<member name="structured_text_bidi_override" type="int" setter="set_structured_text_bidi_override" getter="get_structured_text_bidi_override" enum="Control.StructuredTextParser" default="0">
+			Set BiDi algorithm override for the structured text.
+		</member>
+		<member name="structured_text_bidi_override_options" type="Array" setter="set_structured_text_bidi_override_options" getter="get_structured_text_bidi_override_options" default="[  ]">
+			Set additional options for BiDi override.
+		</member>
 		<member name="tab_size" type="int" setter="set_tab_size" getter="get_tab_size" default="4">
 			The number of spaces associated with a single tab length. Does not affect [code]\t[/code] in text tags, only indent tags.
 		</member>
@@ -329,6 +428,9 @@
 			The raw text of the label.
 			When set, clears the tag stack and adds a raw text tag to the top of it. Does not parse BBCodes. Does not modify [member bbcode_text].
 		</member>
+		<member name="text_direction" type="int" setter="set_text_direction" getter="get_text_direction" enum="Control.TextDirection" default="0">
+			Base text writing direction.
+		</member>
 		<member name="visible_characters" type="int" setter="set_visible_characters" getter="get_visible_characters" default="-1">
 			The restricted number of characters to display in the label. If [code]-1[/code], all characters will be displayed.
 		</member>
@@ -375,7 +477,10 @@
 		<constant name="LIST_LETTERS" value="1" enum="ListType">
 			Each list item has a letter marker.
 		</constant>
-		<constant name="LIST_DOTS" value="2" enum="ListType">
+		<constant name="LIST_ROMAN" value="2" enum="ListType">
+			Each list item has a roman number marker.
+		</constant>
+		<constant name="LIST_DOTS" value="3" enum="ListType">
 			Each list item has a filled circle marker.
 		</constant>
 		<constant name="ITEM_FRAME" value="0" enum="ItemType">
@@ -388,42 +493,56 @@
 		</constant>
 		<constant name="ITEM_FONT" value="4" enum="ItemType">
 		</constant>
-		<constant name="ITEM_COLOR" value="5" enum="ItemType">
+		<constant name="ITEM_FONT_SIZE" value="5" enum="ItemType">
+		</constant>
+		<constant name="ITEM_FONT_FEATURES" value="6" enum="ItemType">
 		</constant>
-		<constant name="ITEM_UNDERLINE" value="6" enum="ItemType">
+		<constant name="ITEM_COLOR" value="7" enum="ItemType">
 		</constant>
-		<constant name="ITEM_STRIKETHROUGH" value="7" enum="ItemType">
+		<constant name="ITEM_OUTLINE_SIZE" value="8" enum="ItemType">
 		</constant>
-		<constant name="ITEM_ALIGN" value="8" enum="ItemType">
+		<constant name="ITEM_OUTLINE_COLOR" value="9" enum="ItemType">
 		</constant>
-		<constant name="ITEM_INDENT" value="9" enum="ItemType">
+		<constant name="ITEM_UNDERLINE" value="10" enum="ItemType">
 		</constant>
-		<constant name="ITEM_LIST" value="10" enum="ItemType">
+		<constant name="ITEM_STRIKETHROUGH" value="11" enum="ItemType">
 		</constant>
-		<constant name="ITEM_TABLE" value="11" enum="ItemType">
+		<constant name="ITEM_PARAGRAPH" value="12" enum="ItemType">
 		</constant>
-		<constant name="ITEM_FADE" value="12" enum="ItemType">
+		<constant name="ITEM_INDENT" value="13" enum="ItemType">
 		</constant>
-		<constant name="ITEM_SHAKE" value="13" enum="ItemType">
+		<constant name="ITEM_LIST" value="14" enum="ItemType">
 		</constant>
-		<constant name="ITEM_WAVE" value="14" enum="ItemType">
+		<constant name="ITEM_TABLE" value="15" enum="ItemType">
 		</constant>
-		<constant name="ITEM_TORNADO" value="15" enum="ItemType">
+		<constant name="ITEM_FADE" value="16" enum="ItemType">
 		</constant>
-		<constant name="ITEM_RAINBOW" value="16" enum="ItemType">
+		<constant name="ITEM_SHAKE" value="17" enum="ItemType">
 		</constant>
-		<constant name="ITEM_CUSTOMFX" value="18" enum="ItemType">
+		<constant name="ITEM_WAVE" value="18" enum="ItemType">
 		</constant>
-		<constant name="ITEM_META" value="17" enum="ItemType">
+		<constant name="ITEM_TORNADO" value="19" enum="ItemType">
+		</constant>
+		<constant name="ITEM_RAINBOW" value="20" enum="ItemType">
+		</constant>
+		<constant name="ITEM_CUSTOMFX" value="22" enum="ItemType">
+		</constant>
+		<constant name="ITEM_META" value="21" enum="ItemType">
 		</constant>
 	</constants>
 	<theme_items>
 		<theme_item name="bold_font" type="Font">
 			The font used for bold text.
 		</theme_item>
+		<theme_item name="bold_font_size" type="int">
+			The font size used for bold text.
+		</theme_item>
 		<theme_item name="bold_italics_font" type="Font">
 			The font used for bold italics text.
 		</theme_item>
+		<theme_item name="bold_italics_font_size" type="int">
+			The font size used for bold italics text.
+		</theme_item>
 		<theme_item name="default_color" type="Color" default="Color( 1, 1, 1, 1 )">
 			The default text color.
 		</theme_item>
@@ -439,18 +558,27 @@
 		<theme_item name="italics_font" type="Font">
 			The font used for italics text.
 		</theme_item>
+		<theme_item name="italics_font_size" type="int">
+			The font size used for italics text.
+		</theme_item>
 		<theme_item name="line_separation" type="int" default="1">
 			The vertical space between lines.
 		</theme_item>
 		<theme_item name="mono_font" type="Font">
 			The font used for monospace text.
 		</theme_item>
+		<theme_item name="mono_font_size" type="int">
+			The font size used for monospace text.
+		</theme_item>
 		<theme_item name="normal" type="StyleBox">
 			The normal background for the [RichTextLabel].
 		</theme_item>
 		<theme_item name="normal_font" type="Font">
 			The default text font.
 		</theme_item>
+		<theme_item name="normal_font_size" type="int">
+			The default text font size.
+		</theme_item>
 		<theme_item name="selection_color" type="Color" default="Color( 0.1, 0.1, 1, 0.8 )">
 			The color of the selection box.
 		</theme_item>
@@ -463,9 +591,18 @@
 		<theme_item name="shadow_offset_y" type="int" default="1">
 			The vertical offset of the font's shadow.
 		</theme_item>
+		<theme_item name="table_border" type="Color" default="Color( 0, 0, 0, 0 )">
+			The default cell border color.
+		</theme_item>
+		<theme_item name="table_even_row_bg" type="Color" default="Color( 0, 0, 0, 0 )">
+			The default background color for even rows.
+		</theme_item>
 		<theme_item name="table_hseparation" type="int" default="3">
 			The horizontal separation of elements in a table.
 		</theme_item>
+		<theme_item name="table_odd_row_bg" type="Color" default="Color( 0, 0, 0, 0 )">
+			The default background color for odd rows.
+		</theme_item>
 		<theme_item name="table_vseparation" type="int" default="3">
 			The vertical separation of elements in a table.
 		</theme_item>

+ 4 - 4
editor/editor_help.cpp

@@ -230,7 +230,7 @@ void EditorHelp::_add_method(const DocData::MethodDoc &p_method, bool p_overview
 
 	if (p_overview) {
 		class_desc->push_cell();
-		class_desc->push_align(RichTextLabel::ALIGN_RIGHT);
+		class_desc->push_paragraph(RichTextLabel::ALIGN_RIGHT, Control::TEXT_DIRECTION_AUTO, "");
 	} else {
 		static const char32_t prefix[3] = { 0x25CF /* filled circle */, ' ', 0 };
 		class_desc->add_text(String(prefix));
@@ -528,7 +528,7 @@ void EditorHelp::_update_doc() {
 			property_line[cd.properties[i].name] = class_desc->get_line_count() - 2; //gets overridden if description
 
 			class_desc->push_cell();
-			class_desc->push_align(RichTextLabel::ALIGN_RIGHT);
+			class_desc->push_paragraph(RichTextLabel::ALIGN_RIGHT, Control::TEXT_DIRECTION_AUTO, "");
 			class_desc->push_font(doc_code_font);
 			_add_type(cd.properties[i].type, cd.properties[i].enumeration);
 			class_desc->pop();
@@ -729,7 +729,7 @@ void EditorHelp::_update_doc() {
 			theme_property_line[cd.theme_properties[i].name] = class_desc->get_line_count() - 2; //gets overridden if description
 
 			class_desc->push_cell();
-			class_desc->push_align(RichTextLabel::ALIGN_RIGHT);
+			class_desc->push_paragraph(RichTextLabel::ALIGN_RIGHT, Control::TEXT_DIRECTION_AUTO, "");
 			class_desc->push_font(doc_code_font);
 			_add_type(cd.theme_properties[i].type);
 			class_desc->pop();
@@ -1500,7 +1500,7 @@ static void _add_text_to_rt(const String &p_bbcode, RichTextLabel *p_rt) {
 			tag_stack.push_front(tag);
 		} else if (tag == "center") {
 			//align to center
-			p_rt->push_align(RichTextLabel::ALIGN_CENTER);
+			p_rt->push_paragraph(RichTextLabel::ALIGN_CENTER, Control::TEXT_DIRECTION_AUTO, "");
 			pos = brk_end + 1;
 			tag_stack.push_front(tag);
 		} else if (tag == "br") {

+ 14 - 17
scene/gui/rich_text_effect.cpp

@@ -64,11 +64,8 @@ RichTextEffect::RichTextEffect() {
 }
 
 void CharFXTransform::_bind_methods() {
-	ClassDB::bind_method(D_METHOD("get_relative_index"), &CharFXTransform::get_relative_index);
-	ClassDB::bind_method(D_METHOD("set_relative_index", "index"), &CharFXTransform::set_relative_index);
-
-	ClassDB::bind_method(D_METHOD("get_absolute_index"), &CharFXTransform::get_absolute_index);
-	ClassDB::bind_method(D_METHOD("set_absolute_index", "index"), &CharFXTransform::set_absolute_index);
+	ClassDB::bind_method(D_METHOD("get_range"), &CharFXTransform::get_range);
+	ClassDB::bind_method(D_METHOD("set_range", "range"), &CharFXTransform::set_range);
 
 	ClassDB::bind_method(D_METHOD("get_elapsed_time"), &CharFXTransform::get_elapsed_time);
 	ClassDB::bind_method(D_METHOD("set_elapsed_time", "time"), &CharFXTransform::set_elapsed_time);
@@ -76,6 +73,9 @@ void CharFXTransform::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("is_visible"), &CharFXTransform::is_visible);
 	ClassDB::bind_method(D_METHOD("set_visibility", "visibility"), &CharFXTransform::set_visibility);
 
+	ClassDB::bind_method(D_METHOD("is_outline"), &CharFXTransform::is_outline);
+	ClassDB::bind_method(D_METHOD("set_outline", "outline"), &CharFXTransform::set_outline);
+
 	ClassDB::bind_method(D_METHOD("get_offset"), &CharFXTransform::get_offset);
 	ClassDB::bind_method(D_METHOD("set_offset", "offset"), &CharFXTransform::set_offset);
 
@@ -85,27 +85,24 @@ void CharFXTransform::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("get_environment"), &CharFXTransform::get_environment);
 	ClassDB::bind_method(D_METHOD("set_environment", "environment"), &CharFXTransform::set_environment);
 
-	ClassDB::bind_method(D_METHOD("get_character"), &CharFXTransform::get_character);
-	ClassDB::bind_method(D_METHOD("set_character", "character"), &CharFXTransform::set_character);
+	ClassDB::bind_method(D_METHOD("get_glyph_index"), &CharFXTransform::get_glyph_index);
+	ClassDB::bind_method(D_METHOD("set_glyph_index", "glyph_index"), &CharFXTransform::set_glyph_index);
+
+	ClassDB::bind_method(D_METHOD("get_font"), &CharFXTransform::get_font);
+	ClassDB::bind_method(D_METHOD("set_font", "font"), &CharFXTransform::set_font);
 
-	ADD_PROPERTY(PropertyInfo(Variant::INT, "relative_index"), "set_relative_index", "get_relative_index");
-	ADD_PROPERTY(PropertyInfo(Variant::INT, "absolute_index"), "set_absolute_index", "get_absolute_index");
+	ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "range"), "set_range", "get_range");
 	ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "elapsed_time"), "set_elapsed_time", "get_elapsed_time");
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "visible"), "set_visibility", "is_visible");
+	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "outline"), "set_outline", "is_outline");
 	ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "offset"), "set_offset", "get_offset");
 	ADD_PROPERTY(PropertyInfo(Variant::COLOR, "color"), "set_color", "get_color");
 	ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "env"), "set_environment", "get_environment");
-	ADD_PROPERTY(PropertyInfo(Variant::INT, "character"), "set_character", "get_character");
+	ADD_PROPERTY(PropertyInfo(Variant::INT, "glyph_index"), "set_glyph_index", "get_glyph_index");
+	ADD_PROPERTY(PropertyInfo(Variant::RID, "font"), "set_font", "get_font");
 }
 
 CharFXTransform::CharFXTransform() {
-	relative_index = 0;
-	absolute_index = 0;
-	visibility = true;
-	offset = Point2();
-	color = Color();
-	character = 0;
-	elapsed_time = 0.0f;
 }
 
 CharFXTransform::~CharFXTransform() {

+ 17 - 12
scene/gui/rich_text_effect.h

@@ -54,32 +54,37 @@ protected:
 	static void _bind_methods();
 
 public:
-	uint64_t relative_index;
-	uint64_t absolute_index;
-	bool visibility;
+	Vector2i range;
+	bool visibility = true;
+	bool outline = false;
 	Point2 offset;
 	Color color;
-	char32_t character;
-	float elapsed_time;
+	float elapsed_time = 0.0f;
 	Dictionary environment;
+	uint32_t glpyh_index = 0;
+	RID font;
 
 	CharFXTransform();
 	~CharFXTransform();
 
-	uint64_t get_relative_index() { return relative_index; }
-	void set_relative_index(uint64_t p_index) { relative_index = p_index; }
-	uint64_t get_absolute_index() { return absolute_index; }
-	void set_absolute_index(uint64_t p_index) { absolute_index = p_index; }
+	Vector2i get_range() { return range; }
+	void set_range(const Vector2i &p_range) { range = p_range; }
 	float get_elapsed_time() { return elapsed_time; }
 	void set_elapsed_time(float p_elapsed_time) { elapsed_time = p_elapsed_time; }
 	bool is_visible() { return visibility; }
-	void set_visibility(bool p_vis) { visibility = p_vis; }
+	void set_visibility(bool p_visibility) { visibility = p_visibility; }
+	bool is_outline() { return outline; }
+	void set_outline(bool p_outline) { outline = p_outline; }
 	Point2 get_offset() { return offset; }
 	void set_offset(Point2 p_offset) { offset = p_offset; }
 	Color get_color() { return color; }
 	void set_color(Color p_color) { color = p_color; }
-	int get_character() { return (int)character; }
-	void set_character(int p_char) { character = (char32_t)p_char; }
+
+	uint32_t get_glyph_index() const { return glpyh_index; };
+	void set_glyph_index(uint32_t p_glpyh_index) { glpyh_index = p_glpyh_index; };
+	RID get_font() const { return font; };
+	void set_font(RID p_font) { font = p_font; };
+
 	Dictionary get_environment() { return environment; }
 	void set_environment(Dictionary p_environment) { environment = p_environment; }
 };

文件差異過大導致無法顯示
+ 959 - 612
scene/gui/rich_text_label.cpp


+ 157 - 111
scene/gui/rich_text_label.h

@@ -33,6 +33,7 @@
 
 #include "rich_text_effect.h"
 #include "scene/gui/scroll_bar.h"
+#include "scene/resources/text_paragraph.h"
 
 class RichTextLabel : public Control {
 	GDCLASS(RichTextLabel, Control);
@@ -48,6 +49,7 @@ public:
 	enum ListType {
 		LIST_NUMBERS,
 		LIST_LETTERS,
+		LIST_ROMAN,
 		LIST_DOTS
 	};
 
@@ -57,10 +59,14 @@ public:
 		ITEM_IMAGE,
 		ITEM_NEWLINE,
 		ITEM_FONT,
+		ITEM_FONT_SIZE,
+		ITEM_FONT_FEATURES,
 		ITEM_COLOR,
+		ITEM_OUTLINE_SIZE,
+		ITEM_OUTLINE_COLOR,
 		ITEM_UNDERLINE,
 		ITEM_STRIKETHROUGH,
-		ITEM_ALIGN,
+		ITEM_PARAGRAPH,
 		ITEM_INDENT,
 		ITEM_LIST,
 		ITEM_TABLE,
@@ -80,31 +86,25 @@ private:
 	struct Item;
 
 	struct Line {
-		Item *from;
-		Vector<int> offset_caches;
-		Vector<int> height_caches;
-		Vector<int> ascent_caches;
-		Vector<int> descent_caches;
-		Vector<int> space_caches;
-		int height_cache;
-		int height_accum_cache;
-		int char_count;
-		int minimum_width;
-		int maximum_width;
-
-		Line() {
-			from = nullptr;
-			char_count = 0;
-		}
+		Item *from = nullptr;
+
+		Ref<TextParagraph> text_buf;
+
+		Vector2 offset;
+		int char_offset = 0;
+		int char_count = 0;
+
+		Line() { text_buf.instance(); }
 	};
 
 	struct Item {
-		int index;
-		Item *parent;
-		ItemType type;
+		int index = 0;
+		int char_ofs = 0;
+		Item *parent = nullptr;
+		ItemType type = ITEM_FRAME;
 		List<Item *> subitems;
-		List<Item *>::Element *E;
-		int line;
+		List<Item *>::Element *E = nullptr;
+		int line = 0;
 
 		void _clear_children() {
 			while (subitems.size()) {
@@ -113,29 +113,26 @@ private:
 			}
 		}
 
-		Item() {
-			parent = nullptr;
-			E = nullptr;
-			line = 0;
-			index = 0;
-			type = ITEM_FRAME;
-		}
 		virtual ~Item() { _clear_children(); }
 	};
 
 	struct ItemFrame : public Item {
-		int parent_line;
-		bool cell;
+		bool cell = false;
+
 		Vector<Line> lines;
-		int first_invalid_line;
-		ItemFrame *parent_frame;
-
-		ItemFrame() {
-			type = ITEM_FRAME;
-			parent_frame = nullptr;
-			cell = false;
-			parent_line = 0;
-		}
+		int first_invalid_line = 0;
+		int first_resized_line = 0;
+
+		ItemFrame *parent_frame = nullptr;
+
+		Color odd_row_bg = Color(0, 0, 0, 0);
+		Color even_row_bg = Color(0, 0, 0, 0);
+		Color border = Color(0, 0, 0, 0);
+		Size2 min_size_over = Size2(-1, -1);
+		Size2 max_size_over = Size2(-1, -1);
+		Rect2 padding;
+
+		ItemFrame() { type = ITEM_FRAME; }
 	};
 
 	struct ItemText : public Item {
@@ -145,6 +142,7 @@ private:
 
 	struct ItemImage : public Item {
 		Ref<Texture2D> image;
+		VAlign inline_align = VALIGN_TOP;
 		Size2 size;
 		Color color;
 		ItemImage() { type = ITEM_IMAGE; }
@@ -155,11 +153,31 @@ private:
 		ItemFont() { type = ITEM_FONT; }
 	};
 
+	struct ItemFontSize : public Item {
+		int font_size = 16;
+		ItemFontSize() { type = ITEM_FONT_SIZE; }
+	};
+
+	struct ItemFontFeatures : public Item {
+		Dictionary opentype_features;
+		ItemFontFeatures() { type = ITEM_FONT_FEATURES; }
+	};
+
 	struct ItemColor : public Item {
 		Color color;
 		ItemColor() { type = ITEM_COLOR; }
 	};
 
+	struct ItemOutlineSize : public Item {
+		int outline_size = 0;
+		ItemOutlineSize() { type = ITEM_OUTLINE_SIZE; }
+	};
+
+	struct ItemOutlineColor : public Item {
+		Color color;
+		ItemOutlineColor() { type = ITEM_OUTLINE_COLOR; }
+	};
+
 	struct ItemUnderline : public Item {
 		ItemUnderline() { type = ITEM_UNDERLINE; }
 	};
@@ -173,18 +191,23 @@ private:
 		ItemMeta() { type = ITEM_META; }
 	};
 
-	struct ItemAlign : public Item {
-		Align align;
-		ItemAlign() { type = ITEM_ALIGN; }
+	struct ItemParagraph : public Item {
+		Align align = ALIGN_LEFT;
+		String language;
+		Control::TextDirection direction = Control::TEXT_DIRECTION_AUTO;
+		Control::StructuredTextParser st_parser = STRUCTURED_TEXT_DEFAULT;
+		ItemParagraph() { type = ITEM_PARAGRAPH; }
 	};
 
 	struct ItemIndent : public Item {
-		int level;
+		int level = 0;
 		ItemIndent() { type = ITEM_INDENT; }
 	};
 
 	struct ItemList : public Item {
-		ListType list_type;
+		ListType list_type = LIST_DOTS;
+		bool capitalize = false;
+		int level = 0;
 		ItemList() { type = ITEM_LIST; }
 	};
 
@@ -202,37 +225,32 @@ private:
 		};
 
 		Vector<Column> columns;
-		int total_width;
+		Vector<float> rows;
+
+		int total_width = 0;
+		int total_height = 0;
+		VAlign inline_align = VALIGN_TOP;
 		ItemTable() { type = ITEM_TABLE; }
 	};
 
 	struct ItemFade : public Item {
-		int starting_index;
-		int length;
+		int starting_index = 0;
+		int length = 0;
 
 		ItemFade() { type = ITEM_FADE; }
 	};
 
 	struct ItemFX : public Item {
-		float elapsed_time;
-
-		ItemFX() {
-			elapsed_time = 0.0f;
-		}
+		float elapsed_time = 0.f;
 	};
 
 	struct ItemShake : public ItemFX {
-		int strength;
-		float rate;
-		uint64_t _current_rng;
-		uint64_t _previous_rng;
-
-		ItemShake() {
-			strength = 0;
-			rate = 0.0f;
-			_current_rng = 0;
-			type = ITEM_SHAKE;
-		}
+		int strength = 0;
+		float rate = 0.0f;
+		uint64_t _current_rng = 0;
+		uint64_t _previous_rng = 0;
+
+		ItemShake() { type = ITEM_SHAKE; }
 
 		void reroll_random() {
 			_previous_rng = _current_rng;
@@ -251,38 +269,25 @@ private:
 	};
 
 	struct ItemWave : public ItemFX {
-		float frequency;
-		float amplitude;
+		float frequency = 1.0f;
+		float amplitude = 1.0f;
 
-		ItemWave() {
-			frequency = 1.0f;
-			amplitude = 1.0f;
-			type = ITEM_WAVE;
-		}
+		ItemWave() { type = ITEM_WAVE; }
 	};
 
 	struct ItemTornado : public ItemFX {
-		float radius;
-		float frequency;
+		float radius = 1.0f;
+		float frequency = 1.0f;
 
-		ItemTornado() {
-			radius = 1.0f;
-			frequency = 1.0f;
-			type = ITEM_TORNADO;
-		}
+		ItemTornado() { type = ITEM_TORNADO; }
 	};
 
 	struct ItemRainbow : public ItemFX {
-		float saturation;
-		float value;
-		float frequency;
-
-		ItemRainbow() {
-			saturation = 0.8f;
-			value = 0.8f;
-			frequency = 1.0f;
-			type = ITEM_RAINBOW;
-		}
+		float saturation = 0.8f;
+		float value = 0.8f;
+		float frequency = 1.0f;
+
+		ItemRainbow() { type = ITEM_RAINBOW; }
 	};
 
 	struct ItemCustomFX : public ItemFX {
@@ -291,7 +296,6 @@ private:
 
 		ItemCustomFX() {
 			type = ITEM_CUSTOMFX;
-
 			char_fx_transform.instance();
 		}
 
@@ -316,7 +320,8 @@ private:
 	int scroll_w;
 	bool scroll_updated;
 	bool updating_scroll;
-	int current_idx;
+	int current_idx = 1;
+	int current_char_ofs = 0;
 	int visible_line_count;
 
 	int tab_size;
@@ -336,23 +341,25 @@ private:
 	void _add_item(Item *p_item, bool p_enter = false, bool p_ensure_newline = false);
 	void _remove_item(Item *p_item, const int p_line, const int p_subitem_line);
 
-	struct ProcessState {
-		int line_width;
-	};
-
-	enum ProcessMode {
-		PROCESS_CACHE,
-		PROCESS_DRAW,
-		PROCESS_POINTER
-	};
+	String language;
+	TextDirection text_direction = TEXT_DIRECTION_AUTO;
+	Control::StructuredTextParser st_parser = STRUCTURED_TEXT_DEFAULT;
+	Array st_args;
 
 	struct Selection {
-		Item *click;
+		ItemFrame *click_frame;
+		int click_line;
+		Item *click_item;
 		int click_char;
 
-		Item *from;
+		ItemFrame *from_frame;
+		int from_line;
+		Item *from_item;
 		int from_char;
-		Item *to;
+
+		ItemFrame *to_frame;
+		int to_line;
+		Item *to_item;
 		int to_char;
 
 		bool active; // anything selected? i.e. from, to, etc. valid?
@@ -364,13 +371,34 @@ private:
 	int visible_characters;
 	float percent_visible;
 
-	int _process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int &y, int p_width, int p_line, ProcessMode p_mode, const Ref<Font> &p_base_font, const Color &p_base_color, const Color &p_font_color_shadow, bool p_shadow_as_outline, const Point2 &shadow_ofs, const Point2i &p_click_pos = Point2i(), Item **r_click_item = nullptr, int *r_click_char = nullptr, bool *r_outside = nullptr, int p_char_count = 0);
-	void _find_click(ItemFrame *p_frame, const Point2i &p_click, Item **r_click_item = nullptr, int *r_click_char = nullptr, bool *r_outside = nullptr);
+	void _find_click(ItemFrame *p_frame, const Point2i &p_click, ItemFrame **r_click_frame = nullptr, int *r_click_line = nullptr, Item **r_click_item = nullptr, int *r_click_char = nullptr, bool *r_outside = nullptr);
+
+	String _get_line_text(ItemFrame *p_frame, int p_line, Selection p_sel);
+	bool _search_line(ItemFrame *p_frame, int p_line, const String &p_string, Item *p_from, Item *p_to);
+
+	void _shape_line(ItemFrame *p_frame, int p_line, const Ref<Font> &p_base_font, int p_base_font_size, int p_width, int *r_char_offset);
+	void _resize_line(ItemFrame *p_frame, int p_line, const Ref<Font> &p_base_font, int p_base_font_size, int p_width);
+	float _draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_ofs, int p_width, const Color &p_base_color, int p_outline_size, const Color &p_outline_color, const Color &p_font_color_shadow, bool p_shadow_as_outline, const Point2 &shadow_ofs);
+	float _find_click_in_line(ItemFrame *p_frame, int p_line, const Vector2 &p_ofs, int p_width, const Point2i &p_click, ItemFrame **r_click_frame = nullptr, int *r_click_line = nullptr, Item **r_click_item = nullptr, int *r_click_char = nullptr);
+
+	String _roman(int p_num, bool p_capitalize) const;
+	String _letters(int p_num, bool p_capitalize) const;
 
+	Item *_get_item_at_pos(Item *p_item_from, Item *p_item_to, int p_position);
+	void _find_frame(Item *p_item, ItemFrame **r_frame, int *r_line);
 	Ref<Font> _find_font(Item *p_item);
-	int _find_margin(Item *p_item, const Ref<Font> &p_base_font);
+	int _find_font_size(Item *p_item);
+	Dictionary _find_font_features(Item *p_item);
+	int _find_outline_size(Item *p_item);
+	ItemList *_find_list_item(Item *p_item);
+	int _find_list(Item *p_item, Vector<int> &r_index, Vector<ItemList *> &r_list);
+	int _find_margin(Item *p_item, const Ref<Font> &p_base_font, int p_base_font_size);
 	Align _find_align(Item *p_item);
+	TextServer::Direction _find_direction(Item *p_item);
+	Control::StructuredTextParser _find_stt(Item *p_item);
+	String _find_language(Item *p_item);
 	Color _find_color(Item *p_item, const Color &p_default_color);
+	Color _find_outline_color(Item *p_item, const Color &p_default_color);
 	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);
@@ -394,8 +422,6 @@ private:
 	bool use_bbcode;
 	String bbcode;
 
-	void _update_all_lines();
-
 	int fixed_width;
 
 	bool fit_content_height;
@@ -406,23 +432,27 @@ 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, const Color &p_color = Color(1.0, 1.0, 1.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), VAlign p_align = VALIGN_TOP);
 	void add_newline();
 	bool remove_line(const int p_line);
 	void push_font(const Ref<Font> &p_font);
+	void push_font_size(int p_font_size);
+	void push_font_features(const Dictionary &p_features);
+	void push_outline_size(int p_font_size);
 	void push_normal();
 	void push_bold();
 	void push_bold_italics();
 	void push_italics();
 	void push_mono();
 	void push_color(const Color &p_color);
+	void push_outline_color(const Color &p_color);
 	void push_underline();
 	void push_strikethrough();
-	void push_align(Align p_align);
+	void push_paragraph(Align p_align, Control::TextDirection p_direction = Control::TEXT_DIRECTION_INHERITED, const String &p_language = "", Control::StructuredTextParser p_st_parser = STRUCTURED_TEXT_DEFAULT);
 	void push_indent(int p_level);
-	void push_list(ListType p_list);
+	void push_list(int p_level, ListType p_list, bool p_capitalize);
 	void push_meta(const Variant &p_meta);
-	void push_table(int p_columns);
+	void push_table(int p_columns, VAlign p_align = VALIGN_TOP);
 	void push_fade(int p_start_index, int p_length);
 	void push_shake(int p_strength, float p_rate);
 	void push_wave(float p_frequency, float p_amplitude);
@@ -430,6 +460,10 @@ public:
 	void push_rainbow(float p_saturation, float p_value, float p_frequency);
 	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);
+	void set_cell_border_color(const Color &p_color);
+	void set_cell_size_override(const Size2 &p_min_size, const Size2 &p_max_size);
+	void set_cell_padding(const Rect2 &p_padding);
 	int get_current_table_column() const;
 	void push_cell();
 	void pop();
@@ -484,6 +518,18 @@ public:
 
 	void set_text(const String &p_string);
 
+	void set_text_direction(TextDirection p_text_direction);
+	TextDirection get_text_direction() const;
+
+	void set_language(const String &p_language);
+	String get_language() const;
+
+	void set_structured_text_bidi_override(Control::StructuredTextParser p_parser);
+	Control::StructuredTextParser get_structured_text_bidi_override() const;
+
+	void set_structured_text_bidi_override_options(Array p_args);
+	Array get_structured_text_bidi_override_options() const;
+
 	void set_visible_characters(int p_visible);
 	int get_visible_characters() const;
 	int get_total_character_count() const;

+ 9 - 0
scene/resources/default_theme/default_theme.cpp

@@ -803,6 +803,12 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
 	theme->set_font("bold_italics_font", "RichTextLabel", Ref<Font>());
 	theme->set_font("mono_font", "RichTextLabel", Ref<Font>());
 
+	theme->set_font_size("normal_font_size", "RichTextLabel", -1);
+	theme->set_font_size("bold_font_size", "RichTextLabel", -1);
+	theme->set_font_size("italics_font_size", "RichTextLabel", -1);
+	theme->set_font_size("bold_italics_font_size", "RichTextLabel", -1);
+	theme->set_font_size("mono_font_size", "RichTextLabel", -1);
+
 	theme->set_color("default_color", "RichTextLabel", Color(1, 1, 1));
 	theme->set_color("font_color_selected", "RichTextLabel", font_color_selection);
 	theme->set_color("selection_color", "RichTextLabel", Color(0.1, 0.1, 1, 0.8));
@@ -817,6 +823,9 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
 	theme->set_constant("table_hseparation", "RichTextLabel", 3 * scale);
 	theme->set_constant("table_vseparation", "RichTextLabel", 3 * scale);
 
+	theme->set_color("table_odd_row_bg", "RichTextLabel", Color(0, 0, 0, 0));
+	theme->set_color("table_even_row_bg", "RichTextLabel", Color(0, 0, 0, 0));
+	theme->set_color("table_border", "RichTextLabel", Color(0, 0, 0, 0));
 	// Containers
 
 	theme->set_stylebox("bg", "VSplitContainer", make_stylebox(vsplit_bg_png, 1, 1, 1, 1));

部分文件因文件數量過多而無法顯示