[Complex Text Layouts] Refactor RichTextLabel.

This commit is contained in:
bruvzg
2020-10-02 15:02:02 +03:00
parent 32c06dfc8d
commit 6b6f101983
8 changed files with 2336 additions and 1129 deletions
+14 -17
View File
@@ -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);
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");
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::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
View File
@@ -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; }
};
File diff suppressed because it is too large Load Diff
+154 -108
View File
@@ -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;
Item *from = nullptr;
Line() {
from = nullptr;
char_count = 0;
}
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;
Vector<Line> lines;
int first_invalid_line;
ItemFrame *parent_frame;
bool cell = false;
ItemFrame() {
type = ITEM_FRAME;
parent_frame = nullptr;
cell = false;
parent_line = 0;
}
Vector<Line> lines;
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;
int strength = 0;
float rate = 0.0f;
uint64_t _current_rng = 0;
uint64_t _previous_rng = 0;
ItemShake() {
strength = 0;
rate = 0.0f;
_current_rng = 0;
type = ITEM_SHAKE;
}
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;
float saturation = 0.8f;
float value = 0.8f;
float frequency = 1.0f;
ItemRainbow() {
saturation = 0.8f;
value = 0.8f;
frequency = 1.0f;
type = ITEM_RAINBOW;
}
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;