Skip to content

Commit ac931c3

Browse files
Delsin-YuMickeonAThousandShips
committed
Implmement stackable text effects on label type through label settings
Co-authored-by: Micky <[email protected]> Co-authored-by: A Thousand Ships <[email protected]>
1 parent 7598b08 commit ac931c3

File tree

5 files changed

+496
-90
lines changed

5 files changed

+496
-90
lines changed

doc/classes/LabelSettings.xml

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,127 @@
88
</description>
99
<tutorials>
1010
</tutorials>
11+
<methods>
12+
<method name="add_stacked_outline">
13+
<return type="void" />
14+
<param index="0" name="index" type="int" default="-1" />
15+
<description>
16+
Adds a new stacked outline to the label at the given [param index]. If [param index] is [code]-1[/code], the new stacked outline will be added at the end of the list.
17+
</description>
18+
</method>
19+
<method name="add_stacked_shadow">
20+
<return type="void" />
21+
<param index="0" name="index" type="int" default="-1" />
22+
<description>
23+
Adds a new stacked shadow to the label at the given [param index]. If [param index] is [code]-1[/code], the new stacked shadow will be added at the end of the list.
24+
</description>
25+
</method>
26+
<method name="get_stacked_outline_color" qualifiers="const">
27+
<return type="Color" />
28+
<param index="0" name="index" type="int" />
29+
<description>
30+
Returns the color of the stacked outline at [param index].
31+
</description>
32+
</method>
33+
<method name="get_stacked_outline_size" qualifiers="const">
34+
<return type="int" />
35+
<param index="0" name="index" type="int" />
36+
<description>
37+
Returns the size of the stacked outline at [param index].
38+
</description>
39+
</method>
40+
<method name="get_stacked_shadow_color" qualifiers="const">
41+
<return type="Color" />
42+
<param index="0" name="index" type="int" />
43+
<description>
44+
Returns the color of the stacked shadow at [param index].
45+
</description>
46+
</method>
47+
<method name="get_stacked_shadow_offset" qualifiers="const">
48+
<return type="Vector2" />
49+
<param index="0" name="index" type="int" />
50+
<description>
51+
Returns the offset of the stacked shadow at [param index].
52+
</description>
53+
</method>
54+
<method name="get_stacked_shadow_outline_size" qualifiers="const">
55+
<return type="int" />
56+
<param index="0" name="index" type="int" />
57+
<description>
58+
Returns the outline size of the stacked shadow at [param index].
59+
</description>
60+
</method>
61+
<method name="move_stacked_outline">
62+
<return type="void" />
63+
<param index="0" name="from_index" type="int" />
64+
<param index="1" name="to_position" type="int" />
65+
<description>
66+
Moves the stacked outline at index [param from_index] to the given position [param to_position] in the array.
67+
</description>
68+
</method>
69+
<method name="move_stacked_shadow">
70+
<return type="void" />
71+
<param index="0" name="from_index" type="int" />
72+
<param index="1" name="to_position" type="int" />
73+
<description>
74+
Moves the stacked shadow at index [param from_index] to the given position [param to_position] in the array.
75+
</description>
76+
</method>
77+
<method name="remove_stacked_outline">
78+
<return type="void" />
79+
<param index="0" name="index" type="int" />
80+
<description>
81+
Removes the stacked outline at index [param index].
82+
</description>
83+
</method>
84+
<method name="remove_stacked_shadow">
85+
<return type="void" />
86+
<param index="0" name="index" type="int" />
87+
<description>
88+
Removes the stacked shadow at index [param index].
89+
</description>
90+
</method>
91+
<method name="set_stacked_outline_color">
92+
<return type="void" />
93+
<param index="0" name="index" type="int" />
94+
<param index="1" name="color" type="Color" />
95+
<description>
96+
Sets the color of the stacked outline identified by the given [param index] to [param color].
97+
</description>
98+
</method>
99+
<method name="set_stacked_outline_size">
100+
<return type="void" />
101+
<param index="0" name="index" type="int" />
102+
<param index="1" name="size" type="int" />
103+
<description>
104+
Sets the size of the stacked outline identified by the given [param index] to [param size].
105+
</description>
106+
</method>
107+
<method name="set_stacked_shadow_color">
108+
<return type="void" />
109+
<param index="0" name="index" type="int" />
110+
<param index="1" name="color" type="Color" />
111+
<description>
112+
Sets the color of the stacked shadow identified by the given [param index] to [param color].
113+
</description>
114+
</method>
115+
<method name="set_stacked_shadow_offset">
116+
<return type="void" />
117+
<param index="0" name="index" type="int" />
118+
<param index="1" name="offset" type="Vector2" />
119+
<description>
120+
Sets the offset of the stacked shadow identified by the given [param index] to [param offset].
121+
</description>
122+
</method>
123+
<method name="set_stacked_shadow_outline_size">
124+
<return type="void" />
125+
<param index="0" name="index" type="int" />
126+
<param index="1" name="size" type="int" />
127+
<description>
128+
Sets the outline size of the stacked shadow identified by the given [param index] to [param size].
129+
</description>
130+
</method>
131+
</methods>
11132
<members>
12133
<member name="font" type="Font" setter="set_font" getter="get_font">
13134
[Font] used for the text.
@@ -39,5 +160,11 @@
39160
<member name="shadow_size" type="int" setter="set_shadow_size" getter="get_shadow_size" default="1">
40161
Size of the shadow effect.
41162
</member>
163+
<member name="stacked_outline_count" type="int" setter="set_stacked_outline_count" getter="get_stacked_outline_count" default="0">
164+
The number of stacked outlines.
165+
</member>
166+
<member name="stacked_shadow_count" type="int" setter="set_stacked_shadow_count" getter="get_stacked_shadow_count" default="0">
167+
Returns the stacked shadow count.
168+
</member>
42169
</members>
43170
</class>

scene/gui/label.cpp

Lines changed: 56 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -430,13 +430,13 @@ inline void draw_glyph_shadow(const Glyph &p_gl, const RID &p_canvas, const Colo
430430
}
431431
}
432432

433-
inline void draw_glyph_shadow_outline(const Glyph &p_gl, const RID &p_canvas, const Color &p_font_shadow_color, int p_shadow_outline_size, const Vector2 &p_ofs, const Vector2 &shadow_ofs) {
433+
inline void draw_glyph_shadow_outline(const Glyph &p_gl, const RID &p_canvas, const Color &p_font_shadow_color, const Vector2 &p_ofs, int p_shadow_outline_size, const Vector2 &shadow_ofs) {
434434
if (p_gl.font_rid != RID()) {
435435
TS->font_draw_glyph_outline(p_gl.font_rid, p_canvas, p_gl.font_size, p_shadow_outline_size, p_ofs + Vector2(p_gl.x_off, p_gl.y_off) + shadow_ofs, p_gl.index, p_font_shadow_color);
436436
}
437437
}
438438

439-
inline void draw_glyph_outline(const Glyph &p_gl, const RID &p_canvas, const Color &p_font_outline_color, int p_outline_size, const Vector2 &p_ofs) {
439+
inline void draw_glyph_outline(const Glyph &p_gl, const RID &p_canvas, const Color &p_font_outline_color, const Vector2 &p_ofs, int p_outline_size) {
440440
if (p_gl.font_rid != RID()) {
441441
if (p_font_outline_color.a != 0.0 && p_outline_size > 0) {
442442
TS->font_draw_glyph_outline(p_gl.font_rid, p_canvas, p_gl.font_size, p_outline_size, p_ofs + Vector2(p_gl.x_off, p_gl.y_off), p_gl.index, p_font_outline_color);
@@ -747,6 +747,8 @@ void Label::_notification(int p_what) {
747747
Color font_outline_color = has_settings ? settings->get_outline_color() : theme_cache.font_outline_color;
748748
int outline_size = has_settings ? settings->get_outline_size() : theme_cache.font_outline_size;
749749
int shadow_outline_size = has_settings ? settings->get_shadow_size() : theme_cache.font_shadow_outline_size;
750+
Vector<LabelSettings::StackedOutlineData> stacked_outline_datas = has_settings ? settings->get_stacked_outline_data() : Vector<LabelSettings::StackedOutlineData>();
751+
Vector<LabelSettings::StackedShadowData> stacked_shadow_datas = has_settings ? settings->get_stacked_shadow_data() : Vector<LabelSettings::StackedShadowData>();
750752
bool rtl_layout = is_layout_rtl();
751753

752754
style->draw(ci, Rect2(Point2(0, 0), get_size()));
@@ -798,95 +800,67 @@ void Label::_notification(int p_what) {
798800

799801
ofs.y += asc;
800802

801-
// Draw shadow, outline and text. Note: Do not merge this into the single loop iteration, to prevent overlaps.
803+
// Draw text effects and main texts. Note: Do not merge this into the single loop iteration, to prevent overlaps.
802804
int processed_glyphs_step = 0;
803-
for (int step = DRAW_STEP_SHADOW_OUTLINE; step < DRAW_STEP_MAX; step++) {
804-
if (step == DRAW_STEP_SHADOW_OUTLINE && (font_shadow_color.a == 0 || shadow_outline_size <= 0)) {
805-
continue;
806-
}
807-
if (step == DRAW_STEP_SHADOW && (font_shadow_color.a == 0)) {
808-
continue;
809-
}
810-
if (step == DRAW_STEP_OUTLINE && (outline_size <= 0 || font_outline_color.a == 0)) {
811-
continue;
812-
}
813805

814-
processed_glyphs_step = processed_glyphs;
815-
Vector2 offset_step = ofs;
816-
// Draw RTL ellipsis string when necessary.
817-
if (rtl && ellipsis_pos >= 0) {
818-
for (int gl_idx = ellipsis_gl_size - 1; gl_idx >= 0; gl_idx--) {
819-
for (int j = 0; j < ellipsis_glyphs[gl_idx].repeat; j++) {
820-
bool skip = (trim_chars && ellipsis_glyphs[gl_idx].end + para.start > visible_chars) || (trim_glyphs_ltr && (processed_glyphs_step >= visible_glyphs)) || (trim_glyphs_rtl && (processed_glyphs_step < total_glyphs - visible_glyphs));
821-
if (!skip) {
822-
if (step == DRAW_STEP_SHADOW_OUTLINE) {
823-
draw_glyph_shadow_outline(ellipsis_glyphs[gl_idx], ci, font_shadow_color, shadow_outline_size, offset_step, shadow_ofs);
824-
} else if (step == DRAW_STEP_SHADOW) {
825-
draw_glyph_shadow(ellipsis_glyphs[gl_idx], ci, font_shadow_color, offset_step, shadow_ofs);
826-
} else if (step == DRAW_STEP_OUTLINE) {
827-
draw_glyph_outline(ellipsis_glyphs[gl_idx], ci, font_outline_color, outline_size, offset_step);
828-
} else if (step == DRAW_STEP_TEXT) {
829-
draw_glyph(ellipsis_glyphs[gl_idx], ci, font_color, offset_step);
830-
}
831-
}
832-
processed_glyphs_step++;
833-
offset_step.x += ellipsis_glyphs[gl_idx].advance;
834-
}
806+
// Draw shadow outline.
807+
if (font_shadow_color.a != 0 && shadow_outline_size > 0) {
808+
draw_text(rtl, ellipsis_pos, ellipsis_gl_size, ellipsis_glyphs, trim_chars, para.start, visible_chars, trim_glyphs_ltr, processed_glyphs_step, processed_glyphs, visible_glyphs, trim_glyphs_rtl, total_glyphs, ci, ofs, gl_size, trim_pos, glyphs, font_shadow_color, draw_glyph_shadow_outline, shadow_outline_size, shadow_ofs);
809+
}
810+
811+
// Draw shadow.
812+
if (font_shadow_color.a > 0) {
813+
draw_text(rtl, ellipsis_pos, ellipsis_gl_size, ellipsis_glyphs, trim_chars, para.start, visible_chars, trim_glyphs_ltr, processed_glyphs_step, processed_glyphs, visible_glyphs, trim_glyphs_rtl, total_glyphs, ci, ofs, gl_size, trim_pos, glyphs, font_shadow_color, draw_glyph_shadow, shadow_ofs);
814+
}
815+
816+
// Draw stacked shadow.
817+
if (stacked_shadow_datas.size() != 0) {
818+
int draw_iterations = stacked_shadow_datas.size();
819+
820+
for (int draw_iteration_index = draw_iterations - 1; draw_iteration_index >= 0; --draw_iteration_index) {
821+
LabelSettings::StackedShadowData stacked_shadow_data = stacked_shadow_datas[draw_iteration_index];
822+
if (stacked_shadow_data.outline_size > 0) {
823+
draw_text(rtl, ellipsis_pos, ellipsis_gl_size, ellipsis_glyphs, trim_chars, para.start, visible_chars, trim_glyphs_ltr, processed_glyphs_step, processed_glyphs, visible_glyphs, trim_glyphs_rtl, total_glyphs, ci, ofs, gl_size, trim_pos, glyphs, stacked_shadow_data.color, draw_glyph_shadow_outline, stacked_shadow_data.outline_size, stacked_shadow_data.offset);
835824
}
825+
826+
draw_text(rtl, ellipsis_pos, ellipsis_gl_size, ellipsis_glyphs, trim_chars, para.start, visible_chars, trim_glyphs_ltr, processed_glyphs_step, processed_glyphs, visible_glyphs, trim_glyphs_rtl, total_glyphs, ci, ofs, gl_size, trim_pos, glyphs, stacked_shadow_data.color, draw_glyph_shadow, stacked_shadow_data.offset);
836827
}
837-
// Draw main text.
838-
for (int j = 0; j < gl_size; j++) {
839-
// Trim when necessary.
840-
if (trim_pos >= 0) {
841-
if (rtl) {
842-
if (j < trim_pos) {
843-
continue;
844-
}
845-
} else {
846-
if (j >= trim_pos) {
847-
break;
848-
}
849-
}
850-
}
851-
for (int k = 0; k < glyphs[j].repeat; k++) {
852-
bool skip = (trim_chars && glyphs[j].end + para.start > visible_chars) || (trim_glyphs_ltr && (processed_glyphs_step >= visible_glyphs)) || (trim_glyphs_rtl && (processed_glyphs_step < total_glyphs - visible_glyphs));
853-
if (!skip) {
854-
if (step == DRAW_STEP_SHADOW_OUTLINE) {
855-
draw_glyph_shadow_outline(glyphs[j], ci, font_shadow_color, shadow_outline_size, offset_step, shadow_ofs);
856-
} else if (step == DRAW_STEP_SHADOW) {
857-
draw_glyph_shadow(glyphs[j], ci, font_shadow_color, offset_step, shadow_ofs);
858-
} else if (step == DRAW_STEP_OUTLINE) {
859-
draw_glyph_outline(glyphs[j], ci, font_outline_color, outline_size, offset_step);
860-
} else if (step == DRAW_STEP_TEXT) {
861-
draw_glyph(glyphs[j], ci, font_color, offset_step);
862-
}
863-
}
864-
processed_glyphs_step++;
865-
offset_step.x += glyphs[j].advance;
828+
}
829+
830+
// Draw stacked outline.
831+
if (stacked_outline_datas.size() != 0) {
832+
int stacked_outline_draw_size = outline_size;
833+
834+
int draw_iterations = stacked_outline_datas.size();
835+
836+
for (int j = 0; j < draw_iterations; j++) {
837+
int stacked_outline_size = stacked_outline_datas[j].size;
838+
if (stacked_outline_size <= 0) {
839+
continue;
866840
}
841+
stacked_outline_draw_size += stacked_outline_size;
867842
}
868-
// Draw LTR ellipsis string when necessary.
869-
if (!rtl && ellipsis_pos >= 0) {
870-
for (int gl_idx = 0; gl_idx < ellipsis_gl_size; gl_idx++) {
871-
for (int j = 0; j < ellipsis_glyphs[gl_idx].repeat; j++) {
872-
bool skip = (trim_chars && ellipsis_glyphs[gl_idx].end + para.start > visible_chars) || (trim_glyphs_ltr && (processed_glyphs_step >= visible_glyphs)) || (trim_glyphs_rtl && (processed_glyphs_step < total_glyphs - visible_glyphs));
873-
if (!skip) {
874-
if (step == DRAW_STEP_SHADOW_OUTLINE) {
875-
draw_glyph_shadow_outline(ellipsis_glyphs[gl_idx], ci, font_shadow_color, shadow_outline_size, offset_step, shadow_ofs);
876-
} else if (step == DRAW_STEP_SHADOW) {
877-
draw_glyph_shadow(ellipsis_glyphs[gl_idx], ci, font_shadow_color, offset_step, shadow_ofs);
878-
} else if (step == DRAW_STEP_OUTLINE) {
879-
draw_glyph_outline(ellipsis_glyphs[gl_idx], ci, font_outline_color, outline_size, offset_step);
880-
} else if (step == DRAW_STEP_TEXT) {
881-
draw_glyph(ellipsis_glyphs[gl_idx], ci, font_color, offset_step);
882-
}
883-
}
884-
processed_glyphs_step++;
885-
offset_step.x += ellipsis_glyphs[gl_idx].advance;
886-
}
843+
844+
for (int draw_iteration_index = draw_iterations - 1; draw_iteration_index >= 0; --draw_iteration_index) {
845+
LabelSettings::StackedOutlineData stacked_outline_data = stacked_outline_datas[draw_iteration_index];
846+
if (stacked_outline_data.size <= 0) {
847+
continue;
887848
}
849+
draw_text(rtl, ellipsis_pos, ellipsis_gl_size, ellipsis_glyphs, trim_chars, para.start, visible_chars, trim_glyphs_ltr, processed_glyphs_step, processed_glyphs, visible_glyphs, trim_glyphs_rtl, total_glyphs, ci, ofs, gl_size, trim_pos, glyphs, stacked_outline_data.color, draw_glyph_outline, stacked_outline_draw_size);
850+
stacked_outline_draw_size -= stacked_outline_data.size;
888851
}
889852
}
853+
854+
// Draw outline.
855+
if (outline_size > 0 && font_outline_color.a != 0) {
856+
draw_text(rtl, ellipsis_pos, ellipsis_gl_size, ellipsis_glyphs, trim_chars, para.start, visible_chars, trim_glyphs_ltr, processed_glyphs_step, processed_glyphs, visible_glyphs, trim_glyphs_rtl, total_glyphs, ci, ofs, gl_size, trim_pos, glyphs, font_outline_color, draw_glyph_outline, outline_size);
857+
}
858+
859+
// Draw text.
860+
{
861+
draw_text(rtl, ellipsis_pos, ellipsis_gl_size, ellipsis_glyphs, trim_chars, para.start, visible_chars, trim_glyphs_ltr, processed_glyphs_step, processed_glyphs, visible_glyphs, trim_glyphs_rtl, total_glyphs, ci, ofs, gl_size, trim_pos, glyphs, font_color, draw_glyph);
862+
}
863+
890864
processed_glyphs = processed_glyphs_step;
891865
ofs.y += dsc + line_spacing;
892866
}

scene/gui/label.h

Lines changed: 51 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -37,14 +37,6 @@ class Label : public Control {
3737
GDCLASS(Label, Control);
3838

3939
private:
40-
enum LabelDrawStep {
41-
DRAW_STEP_SHADOW_OUTLINE,
42-
DRAW_STEP_SHADOW,
43-
DRAW_STEP_OUTLINE,
44-
DRAW_STEP_TEXT,
45-
DRAW_STEP_MAX,
46-
};
47-
4840
HorizontalAlignment horizontal_alignment = HORIZONTAL_ALIGNMENT_LEFT;
4941
VerticalAlignment vertical_alignment = VERTICAL_ALIGNMENT_TOP;
5042
String text;
@@ -199,4 +191,55 @@ class Label : public Control {
199191

200192
Label(const String &p_text = String());
201193
~Label();
194+
195+
template <typename... VarArgsFunc, typename... VarArgs>
196+
void draw_text(bool p_rtl, int p_ellipsis_pos, int p_ellipsis_gl_size, const Glyph *p_ellipsis_glyphs, bool p_trim_chars, int p_para_start, int p_visible_chars, bool p_trim_glyphs_ltr, int &p_processed_glyphs_step, int p_processed_glyphs, int p_visible_glyphs, bool p_trim_glyphs_rtl, int p_total_glyphs, const RID &p_ci, const Vector2 &p_ofs, int p_gl_size, int p_trim_pos, const Glyph *p_glyphs, const Color &p_color, void (*p_draw_func)(const Glyph &p_gl, const RID &p_canvas, const Color &p_font_outline_color, const Vector2 &p_ofs, VarArgsFunc... p_args), VarArgs &&...p_args) {
197+
p_processed_glyphs_step = p_processed_glyphs;
198+
Vector2 offset_step = p_ofs; /* Draw RTL ellipsis string when necessary. */
199+
if (p_rtl && p_ellipsis_pos >= 0) {
200+
for (int gl_idx = p_ellipsis_gl_size - 1; gl_idx >= 0; gl_idx--) {
201+
for (int j = 0; j < p_ellipsis_glyphs[gl_idx].repeat; j++) {
202+
bool skip = (p_trim_chars && p_ellipsis_glyphs[gl_idx].end + p_para_start > p_visible_chars) || (p_trim_glyphs_ltr && (p_processed_glyphs_step >= p_visible_glyphs)) || (p_trim_glyphs_rtl && (p_processed_glyphs_step < p_total_glyphs - p_visible_glyphs));
203+
if (!skip) {
204+
p_draw_func(p_ellipsis_glyphs[gl_idx], p_ci, p_color, offset_step, std::forward<VarArgs>(p_args)...);
205+
}
206+
p_processed_glyphs_step++;
207+
offset_step.x += p_ellipsis_glyphs[gl_idx].advance;
208+
}
209+
}
210+
} /* Draw main text. */
211+
for (int j = 0; j < p_gl_size; j++) { /* Trim when necessary. */
212+
if (p_trim_pos >= 0) {
213+
if (p_rtl) {
214+
if (j < p_trim_pos) {
215+
continue;
216+
}
217+
} else {
218+
if (j >= p_trim_pos) {
219+
break;
220+
}
221+
}
222+
}
223+
for (int k = 0; k < p_glyphs[j].repeat; k++) {
224+
bool skip = (p_trim_chars && p_glyphs[j].end + p_para_start > p_visible_chars) || (p_trim_glyphs_ltr && (p_processed_glyphs_step >= p_visible_glyphs)) || (p_trim_glyphs_rtl && (p_processed_glyphs_step < p_total_glyphs - p_visible_glyphs));
225+
if (!skip) {
226+
p_draw_func(p_glyphs[j], p_ci, p_color, offset_step, std::forward<VarArgs>(p_args)...);
227+
}
228+
p_processed_glyphs_step++;
229+
offset_step.x += p_glyphs[j].advance;
230+
}
231+
} /* Draw LTR ellipsis string when necessary. */
232+
if (!p_rtl && p_ellipsis_pos >= 0) {
233+
for (int gl_idx = 0; gl_idx < p_ellipsis_gl_size; gl_idx++) {
234+
for (int j = 0; j < p_ellipsis_glyphs[gl_idx].repeat; j++) {
235+
bool skip = (p_trim_chars && p_ellipsis_glyphs[gl_idx].end + p_para_start > p_visible_chars) || (p_trim_glyphs_ltr && (p_processed_glyphs_step >= p_visible_glyphs)) || (p_trim_glyphs_rtl && (p_processed_glyphs_step < p_total_glyphs - p_visible_glyphs));
236+
if (!skip) {
237+
p_draw_func(p_ellipsis_glyphs[gl_idx], p_ci, p_color, offset_step, std::forward<VarArgs>(p_args)...);
238+
}
239+
p_processed_glyphs_step++;
240+
offset_step.x += p_ellipsis_glyphs[gl_idx].advance;
241+
}
242+
}
243+
}
244+
}
202245
};

0 commit comments

Comments
 (0)