mirror of
https://github.com/godotengine/godot.git
synced 2024-11-14 08:03:05 +00:00
Add different "visible characters" behavior modes.
This commit is contained in:
parent
3a7d5a1c64
commit
ad4408d413
@ -82,6 +82,7 @@
|
||||
<member name="mouse_filter" type="int" setter="set_mouse_filter" getter="get_mouse_filter" overrides="Control" enum="Control.MouseFilter" default="2" />
|
||||
<member name="percent_visible" type="float" setter="set_percent_visible" getter="get_percent_visible" default="1.0">
|
||||
Limits the amount of visible characters. If you set [code]percent_visible[/code] to 0.5, only up to half of the text's characters will display on screen. Useful to animate the text in a dialog box.
|
||||
[b]Note:[/b] Setting this property updates [member visible_characters] based on current [method get_total_character_count].
|
||||
</member>
|
||||
<member name="size_flags_vertical" type="int" setter="set_v_size_flags" getter="get_v_size_flags" overrides="Control" default="4" />
|
||||
<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">
|
||||
@ -107,6 +108,10 @@
|
||||
</member>
|
||||
<member name="visible_characters" type="int" setter="set_visible_characters" getter="get_visible_characters" default="-1">
|
||||
Restricts the number of characters to display. Set to -1 to disable.
|
||||
[b]Note:[/b] Setting this property updates [member percent_visible] based on current [method get_total_character_count].
|
||||
</member>
|
||||
<member name="visible_characters_behavior" type="int" setter="set_visible_characters_behavior" getter="get_visible_characters_behavior" enum="Label.VisibleCharactersBehavior" default="0">
|
||||
Sets the clipping behavior when [member visible_characters] or [member percent_visible] is set. See [enum VisibleCharactersBehavior] for more info.
|
||||
</member>
|
||||
</members>
|
||||
<constants>
|
||||
@ -161,6 +166,21 @@
|
||||
<constant name="OVERRUN_TRIM_WORD_ELLIPSIS" value="4" enum="OverrunBehavior">
|
||||
Trims the text per word and adds an ellipsis to indicate that parts are hidden.
|
||||
</constant>
|
||||
<constant name="VC_CHARS_BEFORE_SHAPING" value="0" enum="VisibleCharactersBehavior">
|
||||
Trims text before the shaping. e.g, increasing [member visible_characters] value is visually identical to typing the text.
|
||||
</constant>
|
||||
<constant name="VC_CHARS_AFTER_SHAPING" value="1" enum="VisibleCharactersBehavior">
|
||||
Displays glyphs that are mapped to the first [member visible_characters] characters from the beginning of the text.
|
||||
</constant>
|
||||
<constant name="VC_GLYPHS_AUTO" value="2" enum="VisibleCharactersBehavior">
|
||||
Displays [member percent_visible] glyphs, starting from the left or from the right, depending on [member Control.layout_direction] value.
|
||||
</constant>
|
||||
<constant name="VC_GLYPHS_LTR" value="3" enum="VisibleCharactersBehavior">
|
||||
Displays [member percent_visible] glyphs, starting from the left.
|
||||
</constant>
|
||||
<constant name="VC_GLYPHS_RTL" value="4" enum="VisibleCharactersBehavior">
|
||||
Displays [member percent_visible] glyphs, starting from the right.
|
||||
</constant>
|
||||
</constants>
|
||||
<theme_items>
|
||||
<theme_item name="font_color" data_type="color" type="Color" default="Color(1, 1, 1, 1)">
|
||||
|
@ -429,6 +429,9 @@
|
||||
The restricted number of characters to display in the label. If [code]-1[/code], all characters will be displayed.
|
||||
[b]Note:[/b] Setting this property updates [member percent_visible] based on current [method get_total_character_count].
|
||||
</member>
|
||||
<member name="visible_characters_behavior" type="int" setter="set_visible_characters_behavior" getter="get_visible_characters_behavior" enum="RichTextLabel.VisibleCharactersBehavior" default="0">
|
||||
Sets the clipping behavior when [member visible_characters] or [member percent_visible] is set. See [enum VisibleCharactersBehavior] for more info.
|
||||
</member>
|
||||
</members>
|
||||
<signals>
|
||||
<signal name="meta_clicked">
|
||||
@ -527,6 +530,21 @@
|
||||
</constant>
|
||||
<constant name="ITEM_CUSTOMFX" value="25" enum="ItemType">
|
||||
</constant>
|
||||
<constant name="VC_CHARS_BEFORE_SHAPING" value="0" enum="VisibleCharactersBehavior">
|
||||
Trims text before the shaping. e.g, increasing [member visible_characters] value is visually identical to typing the text.
|
||||
</constant>
|
||||
<constant name="VC_CHARS_AFTER_SHAPING" value="1" enum="VisibleCharactersBehavior">
|
||||
Displays glyphs that are mapped to the first [member visible_characters] characters from the beginning of the text.
|
||||
</constant>
|
||||
<constant name="VC_GLYPHS_AUTO" value="2" enum="VisibleCharactersBehavior">
|
||||
Displays [member percent_visible] glyphs, starting from the left or from the right, depending on [member Control.layout_direction] value.
|
||||
</constant>
|
||||
<constant name="VC_GLYPHS_LTR" value="3" enum="VisibleCharactersBehavior">
|
||||
Displays [member percent_visible] glyphs, starting from the left.
|
||||
</constant>
|
||||
<constant name="VC_GLYPHS_RTL" value="4" enum="VisibleCharactersBehavior">
|
||||
Displays [member percent_visible] glyphs, starting from the right.
|
||||
</constant>
|
||||
</constants>
|
||||
<theme_items>
|
||||
<theme_item name="default_color" data_type="color" type="Color" default="Color(1, 1, 1, 1)">
|
||||
|
@ -93,7 +93,7 @@ void Label::_shape() {
|
||||
int font_size = get_theme_font_size(SNAME("font_size"));
|
||||
ERR_FAIL_COND(font.is_null());
|
||||
String text = (uppercase) ? xl_text.to_upper() : xl_text;
|
||||
if (visible_chars >= 0) {
|
||||
if (visible_chars >= 0 && visible_chars_behavior == VC_CHARS_BEFORE_SHAPING) {
|
||||
text = text.substr(0, visible_chars);
|
||||
}
|
||||
TS->shaped_text_add_string(text_rid, text, font->get_rids(), font_size, opentype_features, (language != "") ? language : TranslationServer::get_singleton()->get_tool_locale());
|
||||
@ -316,12 +316,19 @@ void Label::_notification(int p_what) {
|
||||
}
|
||||
|
||||
int last_line = MIN(lines_rid.size(), lines_visible + lines_skipped);
|
||||
bool trim_chars = (visible_chars >= 0) && (visible_chars_behavior == VC_CHARS_AFTER_SHAPING);
|
||||
bool trim_glyphs_ltr = (visible_chars >= 0) && ((visible_chars_behavior == VC_GLYPHS_LTR) || ((visible_chars_behavior == VC_GLYPHS_AUTO) && !rtl_layout));
|
||||
bool trim_glyphs_rtl = (visible_chars >= 0) && ((visible_chars_behavior == VC_GLYPHS_RTL) || ((visible_chars_behavior == VC_GLYPHS_AUTO) && rtl_layout));
|
||||
|
||||
// Get real total height.
|
||||
int total_glyphs = 0;
|
||||
total_h = 0;
|
||||
for (int64_t i = lines_skipped; i < last_line; i++) {
|
||||
total_h += TS->shaped_text_get_size(lines_rid[i]).y + font->get_spacing(TextServer::SPACING_TOP) + font->get_spacing(TextServer::SPACING_BOTTOM) + line_spacing;
|
||||
total_glyphs += TS->shaped_text_get_glyph_count(lines_rid[i]) + TS->shaped_text_get_ellipsis_glyph_count(lines_rid[i]);
|
||||
}
|
||||
int visible_glyphs = total_glyphs * percent_visible;
|
||||
int processed_glyphs = 0;
|
||||
total_h += style->get_margin(SIDE_TOP) + style->get_margin(SIDE_BOTTOM);
|
||||
|
||||
int vbegin = 0, vsep = 0;
|
||||
@ -395,14 +402,19 @@ void Label::_notification(int p_what) {
|
||||
int ellipsis_gl_size = TS->shaped_text_get_ellipsis_glyph_count(lines_rid[i]);
|
||||
|
||||
// Draw outline. Note: Do not merge this into the single loop with the main text, to prevent overlaps.
|
||||
int processed_glyphs_ol = processed_glyphs;
|
||||
if ((outline_size > 0 && font_outline_color.a != 0) || (font_shadow_color.a != 0)) {
|
||||
Vector2 offset = ofs;
|
||||
// Draw RTL ellipsis string when necessary.
|
||||
if (rtl && ellipsis_pos >= 0) {
|
||||
for (int gl_idx = ellipsis_gl_size - 1; gl_idx >= 0; gl_idx--) {
|
||||
for (int j = 0; j < ellipsis_glyphs[gl_idx].repeat; j++) {
|
||||
bool skip = (trim_chars && ellipsis_glyphs[gl_idx].end > visible_chars) || (trim_glyphs_ltr && (processed_glyphs_ol >= visible_glyphs)) || (trim_glyphs_rtl && (processed_glyphs_ol < total_glyphs - visible_glyphs));
|
||||
//Draw glyph outlines and shadow.
|
||||
draw_glyph_outline(ellipsis_glyphs[gl_idx], ci, font_color, font_shadow_color, font_outline_color, shadow_outline_size, outline_size, offset, shadow_ofs);
|
||||
if (!skip) {
|
||||
draw_glyph_outline(ellipsis_glyphs[gl_idx], ci, font_color, font_shadow_color, font_outline_color, shadow_outline_size, outline_size, offset, shadow_ofs);
|
||||
}
|
||||
processed_glyphs_ol++;
|
||||
offset.x += ellipsis_glyphs[gl_idx].advance;
|
||||
}
|
||||
}
|
||||
@ -423,9 +435,13 @@ void Label::_notification(int p_what) {
|
||||
}
|
||||
}
|
||||
}
|
||||
bool skip = (trim_chars && glyphs[j].end > visible_chars) || (trim_glyphs_ltr && (processed_glyphs_ol >= visible_glyphs)) || (trim_glyphs_rtl && (processed_glyphs_ol < total_glyphs - visible_glyphs));
|
||||
|
||||
// Draw glyph outlines and shadow.
|
||||
draw_glyph_outline(glyphs[j], ci, font_color, font_shadow_color, font_outline_color, shadow_outline_size, outline_size, offset, shadow_ofs);
|
||||
if (!skip) {
|
||||
draw_glyph_outline(glyphs[j], ci, font_color, font_shadow_color, font_outline_color, shadow_outline_size, outline_size, offset, shadow_ofs);
|
||||
}
|
||||
processed_glyphs_ol++;
|
||||
offset.x += glyphs[j].advance;
|
||||
}
|
||||
}
|
||||
@ -433,8 +449,12 @@ void Label::_notification(int p_what) {
|
||||
if (!rtl && ellipsis_pos >= 0) {
|
||||
for (int gl_idx = 0; gl_idx < ellipsis_gl_size; gl_idx++) {
|
||||
for (int j = 0; j < ellipsis_glyphs[gl_idx].repeat; j++) {
|
||||
bool skip = (trim_chars && ellipsis_glyphs[gl_idx].end > visible_chars) || (trim_glyphs_ltr && (processed_glyphs_ol >= visible_glyphs)) || (trim_glyphs_rtl && (processed_glyphs_ol < total_glyphs - visible_glyphs));
|
||||
//Draw glyph outlines and shadow.
|
||||
draw_glyph_outline(ellipsis_glyphs[gl_idx], ci, font_color, font_shadow_color, font_outline_color, shadow_outline_size, outline_size, offset, shadow_ofs);
|
||||
if (!skip) {
|
||||
draw_glyph_outline(ellipsis_glyphs[gl_idx], ci, font_color, font_shadow_color, font_outline_color, shadow_outline_size, outline_size, offset, shadow_ofs);
|
||||
}
|
||||
processed_glyphs_ol++;
|
||||
offset.x += ellipsis_glyphs[gl_idx].advance;
|
||||
}
|
||||
}
|
||||
@ -447,8 +467,12 @@ void Label::_notification(int p_what) {
|
||||
if (rtl && ellipsis_pos >= 0) {
|
||||
for (int gl_idx = ellipsis_gl_size - 1; gl_idx >= 0; gl_idx--) {
|
||||
for (int j = 0; j < ellipsis_glyphs[gl_idx].repeat; j++) {
|
||||
bool skip = (trim_chars && ellipsis_glyphs[gl_idx].end > visible_chars) || (trim_glyphs_ltr && (processed_glyphs >= visible_glyphs)) || (trim_glyphs_rtl && (processed_glyphs < total_glyphs - visible_glyphs));
|
||||
//Draw glyph outlines and shadow.
|
||||
draw_glyph(ellipsis_glyphs[gl_idx], ci, font_color, ofs);
|
||||
if (!skip) {
|
||||
draw_glyph(ellipsis_glyphs[gl_idx], ci, font_color, ofs);
|
||||
}
|
||||
processed_glyphs++;
|
||||
ofs.x += ellipsis_glyphs[gl_idx].advance;
|
||||
}
|
||||
}
|
||||
@ -469,9 +493,13 @@ void Label::_notification(int p_what) {
|
||||
}
|
||||
}
|
||||
}
|
||||
bool skip = (trim_chars && glyphs[j].end > visible_chars) || (trim_glyphs_ltr && (processed_glyphs >= visible_glyphs)) || (trim_glyphs_rtl && (processed_glyphs < total_glyphs - visible_glyphs));
|
||||
|
||||
// Draw glyph outlines and shadow.
|
||||
draw_glyph(glyphs[j], ci, font_color, ofs);
|
||||
if (!skip) {
|
||||
draw_glyph(glyphs[j], ci, font_color, ofs);
|
||||
}
|
||||
processed_glyphs++;
|
||||
ofs.x += glyphs[j].advance;
|
||||
}
|
||||
}
|
||||
@ -479,8 +507,12 @@ void Label::_notification(int p_what) {
|
||||
if (!rtl && ellipsis_pos >= 0) {
|
||||
for (int gl_idx = 0; gl_idx < ellipsis_gl_size; gl_idx++) {
|
||||
for (int j = 0; j < ellipsis_glyphs[gl_idx].repeat; j++) {
|
||||
bool skip = (trim_chars && ellipsis_glyphs[gl_idx].end > visible_chars) || (trim_glyphs_ltr && (processed_glyphs >= visible_glyphs)) || (trim_glyphs_rtl && (processed_glyphs < total_glyphs - visible_glyphs));
|
||||
//Draw glyph outlines and shadow.
|
||||
draw_glyph(ellipsis_glyphs[gl_idx], ci, font_color, ofs);
|
||||
if (!skip) {
|
||||
draw_glyph(ellipsis_glyphs[gl_idx], ci, font_color, ofs);
|
||||
}
|
||||
processed_glyphs++;
|
||||
ofs.x += ellipsis_glyphs[gl_idx].advance;
|
||||
}
|
||||
}
|
||||
@ -702,7 +734,9 @@ void Label::set_visible_characters(int p_amount) {
|
||||
} else {
|
||||
percent_visible = 1.0;
|
||||
}
|
||||
dirty = true;
|
||||
if (visible_chars_behavior == VC_CHARS_BEFORE_SHAPING) {
|
||||
dirty = true;
|
||||
}
|
||||
update();
|
||||
}
|
||||
}
|
||||
@ -720,7 +754,9 @@ void Label::set_percent_visible(float p_percent) {
|
||||
visible_chars = get_total_character_count() * p_percent;
|
||||
percent_visible = p_percent;
|
||||
}
|
||||
dirty = true;
|
||||
if (visible_chars_behavior == VC_CHARS_BEFORE_SHAPING) {
|
||||
dirty = true;
|
||||
}
|
||||
update();
|
||||
}
|
||||
}
|
||||
@ -729,6 +765,18 @@ float Label::get_percent_visible() const {
|
||||
return percent_visible;
|
||||
}
|
||||
|
||||
Label::VisibleCharactersBehavior Label::get_visible_characters_behavior() const {
|
||||
return visible_chars_behavior;
|
||||
}
|
||||
|
||||
void Label::set_visible_characters_behavior(Label::VisibleCharactersBehavior p_behavior) {
|
||||
if (visible_chars_behavior != p_behavior) {
|
||||
visible_chars_behavior = p_behavior;
|
||||
dirty = true;
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
void Label::set_lines_skipped(int p_lines) {
|
||||
ERR_FAIL_COND(p_lines < 0);
|
||||
lines_skipped = p_lines;
|
||||
@ -836,6 +884,8 @@ void Label::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("get_total_character_count"), &Label::get_total_character_count);
|
||||
ClassDB::bind_method(D_METHOD("set_visible_characters", "amount"), &Label::set_visible_characters);
|
||||
ClassDB::bind_method(D_METHOD("get_visible_characters"), &Label::get_visible_characters);
|
||||
ClassDB::bind_method(D_METHOD("get_visible_characters_behavior"), &Label::get_visible_characters_behavior);
|
||||
ClassDB::bind_method(D_METHOD("set_visible_characters_behavior", "behavior"), &Label::set_visible_characters_behavior);
|
||||
ClassDB::bind_method(D_METHOD("set_percent_visible", "percent_visible"), &Label::set_percent_visible);
|
||||
ClassDB::bind_method(D_METHOD("get_percent_visible"), &Label::get_percent_visible);
|
||||
ClassDB::bind_method(D_METHOD("set_lines_skipped", "lines_skipped"), &Label::set_lines_skipped);
|
||||
@ -868,6 +918,12 @@ void Label::_bind_methods() {
|
||||
BIND_ENUM_CONSTANT(OVERRUN_TRIM_ELLIPSIS);
|
||||
BIND_ENUM_CONSTANT(OVERRUN_TRIM_WORD_ELLIPSIS);
|
||||
|
||||
BIND_ENUM_CONSTANT(VC_CHARS_BEFORE_SHAPING);
|
||||
BIND_ENUM_CONSTANT(VC_CHARS_AFTER_SHAPING);
|
||||
BIND_ENUM_CONSTANT(VC_GLYPHS_AUTO);
|
||||
BIND_ENUM_CONSTANT(VC_GLYPHS_LTR);
|
||||
BIND_ENUM_CONSTANT(VC_GLYPHS_RTL);
|
||||
|
||||
ADD_PROPERTY(PropertyInfo(Variant::STRING, "text", PROPERTY_HINT_MULTILINE_TEXT, "", PROPERTY_USAGE_DEFAULT_INTL), "set_text", "get_text");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "text_direction", PROPERTY_HINT_ENUM, "Auto,Left-to-Right,Right-to-Left,Inherited"), "set_text_direction", "get_text_direction");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::STRING, "language"), "set_language", "get_language");
|
||||
@ -878,6 +934,7 @@ void Label::_bind_methods() {
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "text_overrun_behavior", PROPERTY_HINT_ENUM, "Trim Nothing,Trim Characters,Trim Words,Ellipsis,Word Ellipsis"), "set_text_overrun_behavior", "get_text_overrun_behavior");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "uppercase"), "set_uppercase", "is_uppercase");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "visible_characters", PROPERTY_HINT_RANGE, "-1,128000,1"), "set_visible_characters", "get_visible_characters");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "visible_characters_behavior", PROPERTY_HINT_ENUM, "Characters Before Shaping,Characters After Shaping,Glyphs (Layout Direction),Glyphs (Left-to-Right),Glyphs (Right-to-Left)"), "set_visible_characters_behavior", "get_visible_characters_behavior");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "percent_visible", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_percent_visible", "get_percent_visible");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "lines_skipped", PROPERTY_HINT_RANGE, "0,999,1"), "set_lines_skipped", "get_lines_skipped");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "max_lines_visible", PROPERTY_HINT_RANGE, "-1,999,1"), "set_max_lines_visible", "get_max_lines_visible");
|
||||
|
@ -66,6 +66,14 @@ public:
|
||||
OVERRUN_TRIM_WORD_ELLIPSIS,
|
||||
};
|
||||
|
||||
enum VisibleCharactersBehavior {
|
||||
VC_CHARS_BEFORE_SHAPING,
|
||||
VC_CHARS_AFTER_SHAPING,
|
||||
VC_GLYPHS_AUTO,
|
||||
VC_GLYPHS_LTR,
|
||||
VC_GLYPHS_RTL,
|
||||
};
|
||||
|
||||
private:
|
||||
Align align = ALIGN_LEFT;
|
||||
VAlign valign = VALIGN_TOP;
|
||||
@ -90,6 +98,7 @@ private:
|
||||
|
||||
float percent_visible = 1.0;
|
||||
|
||||
VisibleCharactersBehavior visible_chars_behavior = VC_CHARS_BEFORE_SHAPING;
|
||||
int visible_chars = -1;
|
||||
int lines_skipped = 0;
|
||||
int max_lines_visible = -1;
|
||||
@ -140,6 +149,9 @@ public:
|
||||
void set_uppercase(bool p_uppercase);
|
||||
bool is_uppercase() const;
|
||||
|
||||
VisibleCharactersBehavior get_visible_characters_behavior() const;
|
||||
void set_visible_characters_behavior(VisibleCharactersBehavior p_behavior);
|
||||
|
||||
void set_visible_characters(int p_amount);
|
||||
int get_visible_characters() const;
|
||||
int get_total_character_count() const;
|
||||
@ -171,5 +183,6 @@ VARIANT_ENUM_CAST(Label::Align);
|
||||
VARIANT_ENUM_CAST(Label::VAlign);
|
||||
VARIANT_ENUM_CAST(Label::AutowrapMode);
|
||||
VARIANT_ENUM_CAST(Label::OverrunBehavior);
|
||||
VARIANT_ENUM_CAST(Label::VisibleCharactersBehavior);
|
||||
|
||||
#endif
|
||||
|
@ -397,7 +397,7 @@ void RichTextLabel::_shape_line(ItemFrame *p_frame, int p_line, const Ref<Font>
|
||||
Item *it_to = (p_line + 1 < p_frame->lines.size()) ? p_frame->lines[p_line + 1].from : nullptr;
|
||||
int remaining_characters = visible_characters - l.char_offset;
|
||||
for (Item *it = l.from; it && it != it_to; it = _get_next_item(it)) {
|
||||
if (visible_characters >= 0 && remaining_characters <= 0) {
|
||||
if (visible_chars_behavior == VC_CHARS_BEFORE_SHAPING && visible_characters >= 0 && remaining_characters <= 0) {
|
||||
break;
|
||||
}
|
||||
switch (it->type) {
|
||||
@ -440,7 +440,7 @@ void RichTextLabel::_shape_line(ItemFrame *p_frame, int p_line, const Ref<Font>
|
||||
Dictionary font_ftr = _find_font_features(it);
|
||||
String lang = _find_language(it);
|
||||
String tx = t->text;
|
||||
if (visible_characters >= 0 && remaining_characters >= 0) {
|
||||
if (visible_chars_behavior == VC_CHARS_BEFORE_SHAPING && visible_characters >= 0 && remaining_characters >= 0) {
|
||||
tx = tx.substr(0, remaining_characters);
|
||||
}
|
||||
remaining_characters -= tx.length();
|
||||
@ -621,7 +621,7 @@ void RichTextLabel::_shape_line(ItemFrame *p_frame, int p_line, const Ref<Font>
|
||||
}
|
||||
}
|
||||
|
||||
int RichTextLabel::_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_shadow_color, int p_shadow_outline_size, const Point2 &p_shadow_ofs) {
|
||||
int RichTextLabel::_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_shadow_color, int p_shadow_outline_size, const Point2 &p_shadow_ofs, int &r_processed_glyphs) {
|
||||
Vector2 off;
|
||||
|
||||
ERR_FAIL_COND_V(p_frame == nullptr, 0);
|
||||
@ -641,6 +641,12 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
|
||||
bool rtl = (l.text_buf->get_direction() == TextServer::DIRECTION_RTL);
|
||||
bool lrtl = is_layout_rtl();
|
||||
|
||||
bool trim_chars = (visible_characters >= 0) && (visible_chars_behavior == VC_CHARS_AFTER_SHAPING);
|
||||
bool trim_glyphs_ltr = (visible_characters >= 0) && ((visible_chars_behavior == VC_GLYPHS_LTR) || ((visible_chars_behavior == VC_GLYPHS_AUTO) && !lrtl));
|
||||
bool trim_glyphs_rtl = (visible_characters >= 0) && ((visible_chars_behavior == VC_GLYPHS_RTL) || ((visible_chars_behavior == VC_GLYPHS_AUTO) && lrtl));
|
||||
int total_glyphs = (trim_glyphs_ltr || trim_glyphs_rtl) ? get_total_glyph_count() : 0;
|
||||
int visible_glyphs = total_glyphs * percent_visible;
|
||||
|
||||
Vector<int> list_index;
|
||||
Vector<ItemList *> list_items;
|
||||
_find_list(l.from, list_index, list_items);
|
||||
@ -804,7 +810,7 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
|
||||
}
|
||||
|
||||
for (int j = 0; j < frame->lines.size(); j++) {
|
||||
_draw_line(frame, j, p_ofs + rect.position + off + Vector2(0, frame->lines[j].offset.y), rect.size.x, p_base_color, p_outline_size, p_outline_color, p_font_shadow_color, p_shadow_outline_size, p_shadow_ofs);
|
||||
_draw_line(frame, j, p_ofs + rect.position + off + Vector2(0, frame->lines[j].offset.y), rect.size.x, p_base_color, p_outline_size, p_outline_color, p_font_shadow_color, p_shadow_outline_size, p_shadow_ofs, r_processed_glyphs);
|
||||
}
|
||||
idx++;
|
||||
}
|
||||
@ -820,6 +826,7 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
|
||||
|
||||
Vector2 gloff = off;
|
||||
// Draw oulines and shadow.
|
||||
int processed_glyphs_ol = r_processed_glyphs;
|
||||
for (int i = 0; i < gl_size; i++) {
|
||||
Item *it = _get_item_at_pos(it_from, it_to, glyphs[i].start);
|
||||
int size = _find_outline_size(it, p_outline_size);
|
||||
@ -947,7 +954,8 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
|
||||
// Draw glyph outlines.
|
||||
for (int j = 0; j < glyphs[i].repeat; j++) {
|
||||
if (visible) {
|
||||
if (frid != RID()) {
|
||||
bool skip = (trim_chars && l.char_offset + glyphs[i].end > visible_characters) || (trim_glyphs_ltr && (processed_glyphs_ol >= visible_glyphs)) || (trim_glyphs_rtl && (processed_glyphs_ol < total_glyphs - visible_glyphs));
|
||||
if (!skip && frid != RID()) {
|
||||
if (font_shadow_color.a > 0) {
|
||||
TS->font_draw_glyph(frid, ci, glyphs[i].font_size, p_ofs + fx_offset + gloff + p_shadow_ofs, gl, font_shadow_color);
|
||||
}
|
||||
@ -958,6 +966,7 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
|
||||
TS->font_draw_glyph_outline(frid, ci, glyphs[i].font_size, size, p_ofs + fx_offset + gloff, gl, font_color);
|
||||
}
|
||||
}
|
||||
processed_glyphs_ol++;
|
||||
}
|
||||
gloff.x += glyphs[i].advance;
|
||||
}
|
||||
@ -1124,11 +1133,15 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
|
||||
// Draw glyphs.
|
||||
for (int j = 0; j < glyphs[i].repeat; j++) {
|
||||
if (visible) {
|
||||
if (frid != RID()) {
|
||||
TS->font_draw_glyph(frid, ci, glyphs[i].font_size, p_ofs + fx_offset + off, gl, selected ? selection_fg : font_color);
|
||||
} else if ((glyphs[i].flags & TextServer::GRAPHEME_IS_VIRTUAL) != TextServer::GRAPHEME_IS_VIRTUAL) {
|
||||
TS->draw_hex_code_box(ci, glyphs[i].font_size, p_ofs + fx_offset + off, gl, selected ? selection_fg : font_color);
|
||||
bool skip = (trim_chars && l.char_offset + glyphs[i].end > visible_characters) || (trim_glyphs_ltr && (r_processed_glyphs >= visible_glyphs)) || (trim_glyphs_rtl && (r_processed_glyphs < total_glyphs - visible_glyphs));
|
||||
if (!skip) {
|
||||
if (frid != RID()) {
|
||||
TS->font_draw_glyph(frid, ci, glyphs[i].font_size, p_ofs + fx_offset + off, gl, selected ? selection_fg : font_color);
|
||||
} else if ((glyphs[i].flags & TextServer::GRAPHEME_IS_VIRTUAL) != TextServer::GRAPHEME_IS_VIRTUAL) {
|
||||
TS->draw_hex_code_box(ci, glyphs[i].font_size, p_ofs + fx_offset + off, gl, selected ? selection_fg : font_color);
|
||||
}
|
||||
}
|
||||
r_processed_glyphs++;
|
||||
}
|
||||
off.x += glyphs[i].advance;
|
||||
}
|
||||
@ -1481,9 +1494,10 @@ void RichTextLabel::_notification(int p_what) {
|
||||
|
||||
// New cache draw.
|
||||
Point2 ofs = text_rect.get_position() + Vector2(0, main->lines[from_line].offset.y - vofs);
|
||||
int processed_glyphs = 0;
|
||||
while (ofs.y < size.height && from_line < main->lines.size()) {
|
||||
visible_paragraph_count++;
|
||||
visible_line_count += _draw_line(main, from_line, ofs, text_rect.size.x, base_color, outline_size, outline_color, font_shadow_color, shadow_outline_size, shadow_ofs);
|
||||
visible_line_count += _draw_line(main, from_line, ofs, text_rect.size.x, base_color, outline_size, outline_color, font_shadow_color, shadow_outline_size, shadow_ofs, processed_glyphs);
|
||||
ofs.y += main->lines[from_line].text_buf->get_size().y + get_theme_constant(SNAME("line_separation"));
|
||||
from_line++;
|
||||
}
|
||||
@ -3993,8 +4007,10 @@ void RichTextLabel::set_percent_visible(float p_percent) {
|
||||
visible_characters = get_total_character_count() * p_percent;
|
||||
percent_visible = p_percent;
|
||||
}
|
||||
main->first_invalid_line = 0; //invalidate ALL
|
||||
_validate_line_caches(main);
|
||||
if (visible_chars_behavior == VC_CHARS_BEFORE_SHAPING) {
|
||||
main->first_invalid_line = 0; //invalidate ALL
|
||||
_validate_line_caches(main);
|
||||
}
|
||||
update();
|
||||
}
|
||||
}
|
||||
@ -4135,6 +4151,9 @@ void RichTextLabel::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("set_visible_characters", "amount"), &RichTextLabel::set_visible_characters);
|
||||
ClassDB::bind_method(D_METHOD("get_visible_characters"), &RichTextLabel::get_visible_characters);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("get_visible_characters_behavior"), &RichTextLabel::get_visible_characters_behavior);
|
||||
ClassDB::bind_method(D_METHOD("set_visible_characters_behavior", "behavior"), &RichTextLabel::set_visible_characters_behavior);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_percent_visible", "percent_visible"), &RichTextLabel::set_percent_visible);
|
||||
ClassDB::bind_method(D_METHOD("get_percent_visible"), &RichTextLabel::get_percent_visible);
|
||||
|
||||
@ -4160,6 +4179,8 @@ void RichTextLabel::_bind_methods() {
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "visible_characters", PROPERTY_HINT_RANGE, "-1,128000,1"), "set_visible_characters", "get_visible_characters");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "percent_visible", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_percent_visible", "get_percent_visible");
|
||||
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "visible_characters_behavior", PROPERTY_HINT_ENUM, "Characters Before Shaping,Characters After Shaping,Glyphs (Layout Direction),Glyphs (Left-to-Right),Glyphs (Right-to-Left)"), "set_visible_characters_behavior", "get_visible_characters_behavior");
|
||||
|
||||
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "meta_underlined"), "set_meta_underline", "is_meta_underlined");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "tab_size", PROPERTY_HINT_RANGE, "0,24,1"), "set_tab_size", "get_tab_size");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::STRING, "text", PROPERTY_HINT_MULTILINE_TEXT), "set_text", "get_text");
|
||||
@ -4224,6 +4245,25 @@ void RichTextLabel::_bind_methods() {
|
||||
BIND_ENUM_CONSTANT(ITEM_META);
|
||||
BIND_ENUM_CONSTANT(ITEM_DROPCAP);
|
||||
BIND_ENUM_CONSTANT(ITEM_CUSTOMFX);
|
||||
|
||||
BIND_ENUM_CONSTANT(VC_CHARS_BEFORE_SHAPING);
|
||||
BIND_ENUM_CONSTANT(VC_CHARS_AFTER_SHAPING);
|
||||
BIND_ENUM_CONSTANT(VC_GLYPHS_AUTO);
|
||||
BIND_ENUM_CONSTANT(VC_GLYPHS_LTR);
|
||||
BIND_ENUM_CONSTANT(VC_GLYPHS_RTL);
|
||||
}
|
||||
|
||||
RichTextLabel::VisibleCharactersBehavior RichTextLabel::get_visible_characters_behavior() const {
|
||||
return visible_chars_behavior;
|
||||
}
|
||||
|
||||
void RichTextLabel::set_visible_characters_behavior(RichTextLabel::VisibleCharactersBehavior p_behavior) {
|
||||
if (visible_chars_behavior != p_behavior) {
|
||||
visible_chars_behavior = p_behavior;
|
||||
main->first_invalid_line = 0; //invalidate ALL
|
||||
_validate_line_caches(main);
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
void RichTextLabel::set_visible_characters(int p_visible) {
|
||||
@ -4237,8 +4277,10 @@ void RichTextLabel::set_visible_characters(int p_visible) {
|
||||
percent_visible = (float)p_visible / (float)total_char_count;
|
||||
}
|
||||
}
|
||||
main->first_invalid_line = 0; //invalidate ALL
|
||||
_validate_line_caches(main);
|
||||
if (visible_chars_behavior == VC_CHARS_BEFORE_SHAPING) {
|
||||
main->first_invalid_line = 0; //invalidate ALL
|
||||
_validate_line_caches(main);
|
||||
}
|
||||
update();
|
||||
}
|
||||
}
|
||||
@ -4266,6 +4308,22 @@ int RichTextLabel::get_total_character_count() const {
|
||||
return tc;
|
||||
}
|
||||
|
||||
int RichTextLabel::get_total_glyph_count() const {
|
||||
int tg = 0;
|
||||
Item *it = main;
|
||||
while (it) {
|
||||
if (it->type == ITEM_FRAME) {
|
||||
ItemFrame *f = static_cast<ItemFrame *>(it);
|
||||
for (int i = 0; i < f->lines.size(); i++) {
|
||||
tg += TS->shaped_text_get_glyph_count(f->lines[i].text_buf->get_rid());
|
||||
}
|
||||
}
|
||||
it = _get_next_item(it, true);
|
||||
}
|
||||
|
||||
return tg;
|
||||
}
|
||||
|
||||
void RichTextLabel::set_fixed_size_to_width(int p_width) {
|
||||
fixed_width = p_width;
|
||||
minimum_size_changed();
|
||||
|
@ -82,6 +82,14 @@ public:
|
||||
ITEM_CUSTOMFX
|
||||
};
|
||||
|
||||
enum VisibleCharactersBehavior {
|
||||
VC_CHARS_BEFORE_SHAPING,
|
||||
VC_CHARS_AFTER_SHAPING,
|
||||
VC_GLYPHS_AUTO,
|
||||
VC_GLYPHS_LTR,
|
||||
VC_GLYPHS_RTL,
|
||||
};
|
||||
|
||||
protected:
|
||||
void _notification(int p_what);
|
||||
static void _bind_methods();
|
||||
@ -403,6 +411,7 @@ private:
|
||||
|
||||
int visible_characters = -1;
|
||||
float percent_visible = 1.0;
|
||||
VisibleCharactersBehavior visible_chars_behavior = VC_CHARS_BEFORE_SHAPING;
|
||||
|
||||
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);
|
||||
|
||||
@ -412,7 +421,7 @@ private:
|
||||
|
||||
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);
|
||||
int _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_shadow_color, int p_shadow_outline_size, const Point2 &p_shadow_ofs);
|
||||
int _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_shadow_color, int p_shadow_outline_size, const Point2 &p_shadow_ofs, int &r_processed_glyphs);
|
||||
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;
|
||||
@ -579,10 +588,14 @@ public:
|
||||
void set_visible_characters(int p_visible);
|
||||
int get_visible_characters() const;
|
||||
int get_total_character_count() const;
|
||||
int get_total_glyph_count() const;
|
||||
|
||||
void set_percent_visible(float p_percent);
|
||||
float get_percent_visible() const;
|
||||
|
||||
VisibleCharactersBehavior get_visible_characters_behavior() const;
|
||||
void set_visible_characters_behavior(VisibleCharactersBehavior p_behavior);
|
||||
|
||||
void set_effects(Array p_effects);
|
||||
Array get_effects();
|
||||
|
||||
@ -598,5 +611,6 @@ public:
|
||||
VARIANT_ENUM_CAST(RichTextLabel::Align);
|
||||
VARIANT_ENUM_CAST(RichTextLabel::ListType);
|
||||
VARIANT_ENUM_CAST(RichTextLabel::ItemType);
|
||||
VARIANT_ENUM_CAST(RichTextLabel::VisibleCharactersBehavior);
|
||||
|
||||
#endif // RICH_TEXT_LABEL_H
|
||||
|
Loading…
Reference in New Issue
Block a user