Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Complex Text Layouts] Add drop-cap support to RTL. #43691

Merged
merged 1 commit into from
Dec 29, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 25 additions & 2 deletions doc/classes/RichTextLabel.xml
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,27 @@
Adds a [code][color][/code] tag to the tag stack.
</description>
</method>
<method name="push_dropcap">
<return type="void">
</return>
<argument index="0" name="string" type="String">
</argument>
<argument index="1" name="font" type="Font">
</argument>
<argument index="2" name="size" type="int">
</argument>
<argument index="3" name="dropcap_margins" type="Rect2" default="Rect2( 0, 0, 0, 0 )">
</argument>
<argument index="4" name="color" type="Color" default="Color( 1, 1, 1, 1 )">
</argument>
<argument index="5" name="outline_size" type="int" default="0">
</argument>
<argument index="6" name="outline_color" type="Color" default="Color( 0, 0, 0, 0 )">
</argument>
<description>
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_font">
<return type="void">
</return>
Expand Down Expand Up @@ -525,10 +546,12 @@
</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>
<constant name="ITEM_DROPCAP" value="22" enum="ItemType">
</constant>
<constant name="ITEM_CUSTOMFX" value="23" enum="ItemType">
</constant>
</constants>
<theme_items>
<theme_item name="bold_font" type="Font">
Expand Down
90 changes: 85 additions & 5 deletions doc/classes/TextParagraph.xml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,13 @@
Clears text paragraph (removes text and inline objects).
</description>
</method>
<method name="clear_dropcap">
<return type="void">
</return>
<description>
Removes dropcap.
</description>
</method>
<method name="draw" qualifiers="const">
<return type="void">
</return>
Expand All @@ -58,8 +65,38 @@
</argument>
<argument index="2" name="color" type="Color" default="Color( 1, 1, 1, 1 )">
</argument>
<argument index="3" name="dc_color" type="Color" default="Color( 1, 1, 1, 1 )">
</argument>
<description>
Draw text into a canvas item at a given position, with [code]color[/code]. [code]pos[/code] specifies the top left corner of the bounding box.
Draw all lines of the text and drop cap into a canvas item at a given position, with [code]color[/code]. [code]pos[/code] specifies the top left corner of the bounding box.
</description>
</method>
<method name="draw_dropcap" qualifiers="const">
<return type="void">
</return>
<argument index="0" name="canvas" type="RID">
</argument>
<argument index="1" name="pos" type="Vector2">
</argument>
<argument index="2" name="color" type="Color" default="Color( 1, 1, 1, 1 )">
</argument>
<description>
Draw drop cap into a canvas item at a given position, with [code]color[/code]. [code]pos[/code] specifies the top left corner of the bounding box.
</description>
</method>
<method name="draw_dropcap_outline" qualifiers="const">
<return type="void">
</return>
<argument index="0" name="canvas" type="RID">
</argument>
<argument index="1" name="pos" type="Vector2">
</argument>
<argument index="2" name="outline_size" type="int" default="1">
</argument>
<argument index="3" name="color" type="Color" default="Color( 1, 1, 1, 1 )">
</argument>
<description>
Draw drop cap outline into a canvas item at a given position, with [code]color[/code]. [code]pos[/code] specifies the top left corner of the bounding box.
</description>
</method>
<method name="draw_line" qualifiers="const">
Expand Down Expand Up @@ -99,14 +136,37 @@
</return>
<argument index="0" name="canvas" type="RID">
</argument>
<argument index="1" name="outline_size" type="Vector2">
<argument index="1" name="pos" type="Vector2">
</argument>
<argument index="2" name="outline_size" type="int" default="1">
</argument>
<argument index="2" name="color" type="int" default="1">
<argument index="3" name="color" type="Color" default="Color( 1, 1, 1, 1 )">
</argument>
<argument index="3" name="arg3" type="Color" default="Color( 1, 1, 1, 1 )">
<argument index="4" name="dc_color" type="Color" default="Color( 1, 1, 1, 1 )">
</argument>
<description>
Draw outline of the text into a canvas item at a given position, with [code]color[/code]. [code]pos[/code] specifies the top left corner of the bounding box.
Draw outilines of all lines of the text and drop cap into a canvas item at a given position, with [code]color[/code]. [code]pos[/code] specifies the top left corner of the bounding box.
</description>
</method>
<method name="get_dropcap_lines" qualifiers="const">
<return type="int">
</return>
<description>
Returns number of lines used by dropcap.
</description>
</method>
<method name="get_dropcap_rid" qualifiers="const">
<return type="RID">
</return>
<description>
Return drop cap text buffer RID.
</description>
</method>
<method name="get_dropcap_size" qualifiers="const">
<return type="Vector2">
</return>
<description>
Returns drop cap bounding box size.
</description>
</method>
<method name="get_line_ascent" qualifiers="const">
Expand Down Expand Up @@ -261,6 +321,26 @@
Override ranges should cover full source text without overlaps. BiDi algorithm will be used on each range separately.
</description>
</method>
<method name="set_dropcap">
<return type="bool">
</return>
<argument index="0" name="text" type="String">
</argument>
<argument index="1" name="fonts" type="Font">
</argument>
<argument index="2" name="size" type="int">
</argument>
<argument index="3" name="dropcap_margins" type="Rect2" default="Rect2( 0, 0, 0, 0 )">
</argument>
<argument index="4" name="opentype_features" type="Dictionary" default="{
}">
</argument>
<argument index="5" name="language" type="String" default="&quot;&quot;">
</argument>
<description>
Sets drop cap, overrides previously set drop cap. 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="tab_align">
<return type="void">
</return>
Expand Down
113 changes: 111 additions & 2 deletions scene/gui/rich_text_label.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -404,6 +404,18 @@ void RichTextLabel::_shape_line(ItemFrame *p_frame, int p_line, const Ref<Font>
break;
}
switch (it->type) {
case ITEM_DROPCAP: {
// Add dropcap.
const ItemDropcap *dc = (ItemDropcap *)it;
if (dc != nullptr) {
l.text_buf->set_dropcap(dc->text, dc->font, dc->font_size, dc->dropcap_margins);
l.dc_color = dc->color;
l.dc_ol_size = dc->ol_size;
l.dc_ol_color = dc->ol_color;
} else {
l.text_buf->clear_dropcap();
}
} break;
case ITEM_NEWLINE: {
Ref<Font> font = _find_font(it);
if (font.is_null()) {
Expand Down Expand Up @@ -679,6 +691,14 @@ float RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p
}
}

// Draw dropcap.
int dc_lines = l.text_buf->get_dropcap_lines();
float h_off = l.text_buf->get_dropcap_size().x;
if (l.dc_ol_size > 0) {
l.text_buf->draw_dropcap_outline(ci, p_ofs + ((rtl) ? Vector2() : Vector2(l.offset.x, 0)), l.dc_ol_size, l.dc_ol_color);
}
l.text_buf->draw_dropcap(ci, p_ofs + ((rtl) ? Vector2() : Vector2(l.offset.x, 0)), l.dc_color);

// Draw text.
for (int line = 0; line < l.text_buf->get_line_count(); line++) {
RID rid = l.text_buf->get_line_rid(line);
Expand Down Expand Up @@ -718,6 +738,14 @@ float RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p
} break;
}

if (line <= dc_lines) {
if (rtl) {
off.x -= h_off;
} else {
off.x += h_off;
}
}

//draw_rect(Rect2(p_ofs + off, TS->shaped_text_get_size(rid)), Color(1,0,0), false, 2); //DEBUG_RECTS

off.y += TS->shaped_text_get_ascent(rid);
Expand Down Expand Up @@ -1743,6 +1771,19 @@ Dictionary RichTextLabel::_find_font_features(Item *p_item) {
return Dictionary();
}

RichTextLabel::ItemDropcap *RichTextLabel::_find_dc_item(Item *p_item) {
Item *item = p_item;

while (item) {
if (item->type == ITEM_DROPCAP) {
return static_cast<ItemDropcap *>(item);
}
item = item->parent;
}

return nullptr;
}

RichTextLabel::ItemList *RichTextLabel::_find_list_item(Item *p_item) {
Item *item = p_item;

Expand Down Expand Up @@ -2317,6 +2358,24 @@ bool RichTextLabel::remove_line(const int p_line) {
return true;
}

void RichTextLabel::push_dropcap(const String &p_string, const Ref<Font> &p_font, int p_size, const Rect2 &p_dropcap_margins, const Color &p_color, int p_ol_size, const Color &p_ol_color) {
ERR_FAIL_COND(current->type == ITEM_TABLE);
ERR_FAIL_COND(p_string.empty());
ERR_FAIL_COND(p_font.is_null());
ERR_FAIL_COND(p_size <= 0);

ItemDropcap *item = memnew(ItemDropcap);

item->text = p_string;
item->font = p_font;
item->font_size = p_size;
item->color = p_color;
item->ol_size = p_ol_size;
item->ol_color = p_ol_color;
item->dropcap_margins = p_dropcap_margins;
_add_item(item, false);
}

void RichTextLabel::push_font(const Ref<Font> &p_font) {
ERR_FAIL_COND(current->type == ITEM_TABLE);
ERR_FAIL_COND(p_font.is_null());
Expand Down Expand Up @@ -2766,7 +2825,7 @@ Error RichTextLabel::append_bbcode(const String &p_bbcode) {

tag_stack.pop_front();
pos = brk_end + 1;
if (tag != "/img") {
if (tag != "/img" && tag != "/dropcap") {
pop();
}

Expand Down Expand Up @@ -3042,6 +3101,54 @@ Error RichTextLabel::append_bbcode(const String &p_bbcode) {
push_meta(url);
pos = brk_end + 1;
tag_stack.push_front("url");
} else if (tag.begins_with("dropcap")) {
Vector<String> subtag = tag.substr(5, tag.length()).split(" ");
Ref<Font> f = get_theme_font("normal_font");
int fs = get_theme_font_size("normal_font_size") * 3;
Color color = get_theme_color("default_color");
Color outline_color = get_theme_color("outline_color");
int outline_size = get_theme_constant("outline_size");
Rect2 dropcap_margins = Rect2();

for (int i = 0; i < subtag.size(); i++) {
Vector<String> subtag_a = subtag[i].split("=");
if (subtag_a.size() == 2) {
if (subtag_a[0] == "font" || subtag_a[0] == "f") {
String fnt = subtag_a[1];
Ref<Font> font = ResourceLoader::load(fnt, "Font");
if (font.is_valid()) {
f = font;
}
} else if (subtag_a[0] == "font_size") {
fs = subtag_a[1].to_int();
} else if (subtag_a[0] == "margins") {
Vector<String> subtag_b = subtag_a[1].split(",");
if (subtag_b.size() == 4) {
dropcap_margins.position.x = subtag_b[0].to_float();
dropcap_margins.position.y = subtag_b[1].to_float();
dropcap_margins.size.x = subtag_b[2].to_float();
dropcap_margins.size.y = subtag_b[3].to_float();
}
} else if (subtag_a[0] == "outline_size") {
outline_size = subtag_a[1].to_int();
} else if (subtag_a[0] == "color") {
color = _get_color_from_string(subtag_a[1], color);
} else if (subtag_a[0] == "outline_color") {
outline_color = _get_color_from_string(subtag_a[1], outline_color);
}
}
}
int end = p_bbcode.find("[", brk_end);
if (end == -1) {
end = p_bbcode.length();
}

String txt = p_bbcode.substr(brk_end + 1, end - brk_end - 1);

push_dropcap(txt, f, fs, dropcap_margins, color, outline_size, outline_color);

pos = end;
tag_stack.push_front(bbcode_name);
} else if (tag.begins_with("img")) {
VAlign align = VALIGN_TOP;
if (tag.begins_with("img=")) {
Expand Down Expand Up @@ -3680,6 +3787,7 @@ void RichTextLabel::_bind_methods() {
ClassDB::bind_method(D_METHOD("push_underline"), &RichTextLabel::push_underline);
ClassDB::bind_method(D_METHOD("push_strikethrough"), &RichTextLabel::push_strikethrough);
ClassDB::bind_method(D_METHOD("push_table", "columns", "inline_align"), &RichTextLabel::push_table, DEFVAL(VALIGN_TOP));
ClassDB::bind_method(D_METHOD("push_dropcap", "string", "font", "size", "dropcap_margins", "color", "outline_size", "outline_color"), &RichTextLabel::push_dropcap, DEFVAL(Rect2()), DEFVAL(Color(1, 1, 1)), DEFVAL(0), DEFVAL(Color(0, 0, 0, 0)));
ClassDB::bind_method(D_METHOD("set_table_column_expand", "column", "expand", "ratio"), &RichTextLabel::set_table_column_expand);
ClassDB::bind_method(D_METHOD("set_cell_row_background_color", "odd_row_bg", "even_row_bg"), &RichTextLabel::set_cell_row_background_color);
ClassDB::bind_method(D_METHOD("set_cell_border_color", "color"), &RichTextLabel::set_cell_border_color);
Expand Down Expand Up @@ -3815,8 +3923,9 @@ void RichTextLabel::_bind_methods() {
BIND_ENUM_CONSTANT(ITEM_WAVE);
BIND_ENUM_CONSTANT(ITEM_TORNADO);
BIND_ENUM_CONSTANT(ITEM_RAINBOW);
BIND_ENUM_CONSTANT(ITEM_CUSTOMFX);
BIND_ENUM_CONSTANT(ITEM_META);
BIND_ENUM_CONSTANT(ITEM_DROPCAP);
BIND_ENUM_CONSTANT(ITEM_CUSTOMFX);
}

void RichTextLabel::set_visible_characters(int p_visible) {
Expand Down
17 changes: 17 additions & 0 deletions scene/gui/rich_text_label.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ class RichTextLabel : public Control {
ITEM_TORNADO,
ITEM_RAINBOW,
ITEM_META,
ITEM_DROPCAP,
ITEM_CUSTOMFX
};

Expand All @@ -89,6 +90,9 @@ class RichTextLabel : public Control {
Item *from = nullptr;

Ref<TextParagraph> text_buf;
Color dc_color;
int dc_ol_size = 0;
Color dc_ol_color;

Vector2 offset;
int char_offset = 0;
Expand Down Expand Up @@ -140,6 +144,17 @@ class RichTextLabel : public Control {
ItemText() { type = ITEM_TEXT; }
};

struct ItemDropcap : public Item {
String text;
Ref<Font> font;
int font_size;
Color color;
int ol_size;
Color ol_color;
Rect2 dropcap_margins;
ItemDropcap() { type = ITEM_DROPCAP; }
};

struct ItemImage : public Item {
Ref<Texture2D> image;
VAlign inline_align = VALIGN_TOP;
Expand Down Expand Up @@ -391,6 +406,7 @@ class RichTextLabel : public Control {
Dictionary _find_font_features(Item *p_item);
int _find_outline_size(Item *p_item);
ItemList *_find_list_item(Item *p_item);
ItemDropcap *_find_dc_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);
Expand Down Expand Up @@ -435,6 +451,7 @@ class RichTextLabel : public Control {
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_dropcap(const String &p_string, const Ref<Font> &p_font, int p_size, const Rect2 &p_dropcap_margins = Rect2(), const Color &p_color = Color(1, 1, 1), int p_ol_size = 0, const Color &p_ol_color = Color(0, 0, 0, 0));
void push_font(const Ref<Font> &p_font);
void push_font_size(int p_font_size);
void push_font_features(const Dictionary &p_features);
Expand Down
Loading