You've already forked godot
mirror of
https://github.com/godotengine/godot.git
synced 2025-11-05 12:10:55 +00:00
Merge pull request #104731 from Delsin-Yu/stackable-text-effect
[GUI] Implement Stackable Text Outline on `Label`
This commit is contained in:
@@ -8,6 +8,127 @@
|
||||
</description>
|
||||
<tutorials>
|
||||
</tutorials>
|
||||
<methods>
|
||||
<method name="add_stacked_outline">
|
||||
<return type="void" />
|
||||
<param index="0" name="index" type="int" default="-1" />
|
||||
<description>
|
||||
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.
|
||||
</description>
|
||||
</method>
|
||||
<method name="add_stacked_shadow">
|
||||
<return type="void" />
|
||||
<param index="0" name="index" type="int" default="-1" />
|
||||
<description>
|
||||
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.
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_stacked_outline_color" qualifiers="const">
|
||||
<return type="Color" />
|
||||
<param index="0" name="index" type="int" />
|
||||
<description>
|
||||
Returns the color of the stacked outline at [param index].
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_stacked_outline_size" qualifiers="const">
|
||||
<return type="int" />
|
||||
<param index="0" name="index" type="int" />
|
||||
<description>
|
||||
Returns the size of the stacked outline at [param index].
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_stacked_shadow_color" qualifiers="const">
|
||||
<return type="Color" />
|
||||
<param index="0" name="index" type="int" />
|
||||
<description>
|
||||
Returns the color of the stacked shadow at [param index].
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_stacked_shadow_offset" qualifiers="const">
|
||||
<return type="Vector2" />
|
||||
<param index="0" name="index" type="int" />
|
||||
<description>
|
||||
Returns the offset of the stacked shadow at [param index].
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_stacked_shadow_outline_size" qualifiers="const">
|
||||
<return type="int" />
|
||||
<param index="0" name="index" type="int" />
|
||||
<description>
|
||||
Returns the outline size of the stacked shadow at [param index].
|
||||
</description>
|
||||
</method>
|
||||
<method name="move_stacked_outline">
|
||||
<return type="void" />
|
||||
<param index="0" name="from_index" type="int" />
|
||||
<param index="1" name="to_position" type="int" />
|
||||
<description>
|
||||
Moves the stacked outline at index [param from_index] to the given position [param to_position] in the array.
|
||||
</description>
|
||||
</method>
|
||||
<method name="move_stacked_shadow">
|
||||
<return type="void" />
|
||||
<param index="0" name="from_index" type="int" />
|
||||
<param index="1" name="to_position" type="int" />
|
||||
<description>
|
||||
Moves the stacked shadow at index [param from_index] to the given position [param to_position] in the array.
|
||||
</description>
|
||||
</method>
|
||||
<method name="remove_stacked_outline">
|
||||
<return type="void" />
|
||||
<param index="0" name="index" type="int" />
|
||||
<description>
|
||||
Removes the stacked outline at index [param index].
|
||||
</description>
|
||||
</method>
|
||||
<method name="remove_stacked_shadow">
|
||||
<return type="void" />
|
||||
<param index="0" name="index" type="int" />
|
||||
<description>
|
||||
Removes the stacked shadow at index [param index].
|
||||
</description>
|
||||
</method>
|
||||
<method name="set_stacked_outline_color">
|
||||
<return type="void" />
|
||||
<param index="0" name="index" type="int" />
|
||||
<param index="1" name="color" type="Color" />
|
||||
<description>
|
||||
Sets the color of the stacked outline identified by the given [param index] to [param color].
|
||||
</description>
|
||||
</method>
|
||||
<method name="set_stacked_outline_size">
|
||||
<return type="void" />
|
||||
<param index="0" name="index" type="int" />
|
||||
<param index="1" name="size" type="int" />
|
||||
<description>
|
||||
Sets the size of the stacked outline identified by the given [param index] to [param size].
|
||||
</description>
|
||||
</method>
|
||||
<method name="set_stacked_shadow_color">
|
||||
<return type="void" />
|
||||
<param index="0" name="index" type="int" />
|
||||
<param index="1" name="color" type="Color" />
|
||||
<description>
|
||||
Sets the color of the stacked shadow identified by the given [param index] to [param color].
|
||||
</description>
|
||||
</method>
|
||||
<method name="set_stacked_shadow_offset">
|
||||
<return type="void" />
|
||||
<param index="0" name="index" type="int" />
|
||||
<param index="1" name="offset" type="Vector2" />
|
||||
<description>
|
||||
Sets the offset of the stacked shadow identified by the given [param index] to [param offset].
|
||||
</description>
|
||||
</method>
|
||||
<method name="set_stacked_shadow_outline_size">
|
||||
<return type="void" />
|
||||
<param index="0" name="index" type="int" />
|
||||
<param index="1" name="size" type="int" />
|
||||
<description>
|
||||
Sets the outline size of the stacked shadow identified by the given [param index] to [param size].
|
||||
</description>
|
||||
</method>
|
||||
</methods>
|
||||
<members>
|
||||
<member name="font" type="Font" setter="set_font" getter="get_font">
|
||||
[Font] used for the text.
|
||||
@@ -39,5 +160,11 @@
|
||||
<member name="shadow_size" type="int" setter="set_shadow_size" getter="get_shadow_size" default="1">
|
||||
Size of the shadow effect.
|
||||
</member>
|
||||
<member name="stacked_outline_count" type="int" setter="set_stacked_outline_count" getter="get_stacked_outline_count" default="0">
|
||||
The number of stacked outlines.
|
||||
</member>
|
||||
<member name="stacked_shadow_count" type="int" setter="set_stacked_shadow_count" getter="get_stacked_shadow_count" default="0">
|
||||
Returns the stacked shadow count.
|
||||
</member>
|
||||
</members>
|
||||
</class>
|
||||
|
||||
@@ -431,13 +431,13 @@ inline void draw_glyph_shadow(const Glyph &p_gl, const RID &p_canvas, const Colo
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
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) {
|
||||
if (p_gl.font_rid != RID()) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
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) {
|
||||
if (p_gl.font_rid != RID()) {
|
||||
if (p_font_outline_color.a != 0.0 && p_outline_size > 0) {
|
||||
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);
|
||||
@@ -758,6 +758,8 @@ void Label::_notification(int p_what) {
|
||||
Color font_outline_color = has_settings ? settings->get_outline_color() : theme_cache.font_outline_color;
|
||||
int outline_size = has_settings ? settings->get_outline_size() : theme_cache.font_outline_size;
|
||||
int shadow_outline_size = has_settings ? settings->get_shadow_size() : theme_cache.font_shadow_outline_size;
|
||||
Vector<LabelSettings::StackedOutlineData> stacked_outline_datas = has_settings ? settings->get_stacked_outline_data() : Vector<LabelSettings::StackedOutlineData>();
|
||||
Vector<LabelSettings::StackedShadowData> stacked_shadow_datas = has_settings ? settings->get_stacked_shadow_data() : Vector<LabelSettings::StackedShadowData>();
|
||||
bool rtl_layout = is_layout_rtl();
|
||||
|
||||
if (has_focus()) {
|
||||
@@ -813,95 +815,67 @@ void Label::_notification(int p_what) {
|
||||
|
||||
ofs.y += asc;
|
||||
|
||||
// Draw shadow, outline and text. Note: Do not merge this into the single loop iteration, to prevent overlaps.
|
||||
// Draw text effects and main texts. Note: Do not merge this into the single loop iteration, to prevent overlaps.
|
||||
int processed_glyphs_step = 0;
|
||||
for (int step = DRAW_STEP_SHADOW_OUTLINE; step < DRAW_STEP_MAX; step++) {
|
||||
if (step == DRAW_STEP_SHADOW_OUTLINE && (font_shadow_color.a == 0 || shadow_outline_size <= 0)) {
|
||||
continue;
|
||||
}
|
||||
if (step == DRAW_STEP_SHADOW && (font_shadow_color.a == 0)) {
|
||||
continue;
|
||||
}
|
||||
if (step == DRAW_STEP_OUTLINE && (outline_size <= 0 || font_outline_color.a == 0)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
processed_glyphs_step = processed_glyphs;
|
||||
Vector2 offset_step = 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 + para.start > visible_chars) || (trim_glyphs_ltr && (processed_glyphs_step >= visible_glyphs)) || (trim_glyphs_rtl && (processed_glyphs_step < total_glyphs - visible_glyphs));
|
||||
if (!skip) {
|
||||
if (step == DRAW_STEP_SHADOW_OUTLINE) {
|
||||
draw_glyph_shadow_outline(ellipsis_glyphs[gl_idx], ci, font_shadow_color, shadow_outline_size, offset_step, shadow_ofs);
|
||||
} else if (step == DRAW_STEP_SHADOW) {
|
||||
draw_glyph_shadow(ellipsis_glyphs[gl_idx], ci, font_shadow_color, offset_step, shadow_ofs);
|
||||
} else if (step == DRAW_STEP_OUTLINE) {
|
||||
draw_glyph_outline(ellipsis_glyphs[gl_idx], ci, font_outline_color, outline_size, offset_step);
|
||||
} else if (step == DRAW_STEP_TEXT) {
|
||||
draw_glyph(ellipsis_glyphs[gl_idx], ci, font_color, offset_step);
|
||||
}
|
||||
}
|
||||
processed_glyphs_step++;
|
||||
offset_step.x += ellipsis_glyphs[gl_idx].advance;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Draw main text.
|
||||
for (int j = 0; j < gl_size; j++) {
|
||||
// Trim when necessary.
|
||||
if (trim_pos >= 0) {
|
||||
if (rtl) {
|
||||
if (j < trim_pos) {
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
if (j >= trim_pos) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int k = 0; k < glyphs[j].repeat; k++) {
|
||||
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));
|
||||
if (!skip) {
|
||||
if (step == DRAW_STEP_SHADOW_OUTLINE) {
|
||||
draw_glyph_shadow_outline(glyphs[j], ci, font_shadow_color, shadow_outline_size, offset_step, shadow_ofs);
|
||||
} else if (step == DRAW_STEP_SHADOW) {
|
||||
draw_glyph_shadow(glyphs[j], ci, font_shadow_color, offset_step, shadow_ofs);
|
||||
} else if (step == DRAW_STEP_OUTLINE) {
|
||||
draw_glyph_outline(glyphs[j], ci, font_outline_color, outline_size, offset_step);
|
||||
} else if (step == DRAW_STEP_TEXT) {
|
||||
draw_glyph(glyphs[j], ci, font_color, offset_step);
|
||||
}
|
||||
}
|
||||
processed_glyphs_step++;
|
||||
offset_step.x += glyphs[j].advance;
|
||||
}
|
||||
}
|
||||
// Draw LTR ellipsis string when necessary.
|
||||
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 + para.start > visible_chars) || (trim_glyphs_ltr && (processed_glyphs_step >= visible_glyphs)) || (trim_glyphs_rtl && (processed_glyphs_step < total_glyphs - visible_glyphs));
|
||||
if (!skip) {
|
||||
if (step == DRAW_STEP_SHADOW_OUTLINE) {
|
||||
draw_glyph_shadow_outline(ellipsis_glyphs[gl_idx], ci, font_shadow_color, shadow_outline_size, offset_step, shadow_ofs);
|
||||
} else if (step == DRAW_STEP_SHADOW) {
|
||||
draw_glyph_shadow(ellipsis_glyphs[gl_idx], ci, font_shadow_color, offset_step, shadow_ofs);
|
||||
} else if (step == DRAW_STEP_OUTLINE) {
|
||||
draw_glyph_outline(ellipsis_glyphs[gl_idx], ci, font_outline_color, outline_size, offset_step);
|
||||
} else if (step == DRAW_STEP_TEXT) {
|
||||
draw_glyph(ellipsis_glyphs[gl_idx], ci, font_color, offset_step);
|
||||
}
|
||||
}
|
||||
processed_glyphs_step++;
|
||||
offset_step.x += ellipsis_glyphs[gl_idx].advance;
|
||||
}
|
||||
// Draw shadow outline.
|
||||
if (font_shadow_color.a != 0 && shadow_outline_size > 0) {
|
||||
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);
|
||||
}
|
||||
|
||||
// Draw shadow.
|
||||
if (font_shadow_color.a > 0) {
|
||||
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);
|
||||
}
|
||||
|
||||
// Draw stacked shadow.
|
||||
if (stacked_shadow_datas.size() != 0) {
|
||||
int draw_iterations = stacked_shadow_datas.size();
|
||||
|
||||
for (int draw_iteration_index = draw_iterations - 1; draw_iteration_index >= 0; --draw_iteration_index) {
|
||||
LabelSettings::StackedShadowData stacked_shadow_data = stacked_shadow_datas[draw_iteration_index];
|
||||
if (stacked_shadow_data.outline_size > 0) {
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
// Draw stacked outline.
|
||||
if (stacked_outline_datas.size() != 0) {
|
||||
int stacked_outline_draw_size = outline_size;
|
||||
|
||||
int draw_iterations = stacked_outline_datas.size();
|
||||
|
||||
for (int j = 0; j < draw_iterations; j++) {
|
||||
int stacked_outline_size = stacked_outline_datas[j].size;
|
||||
if (stacked_outline_size <= 0) {
|
||||
continue;
|
||||
}
|
||||
stacked_outline_draw_size += stacked_outline_size;
|
||||
}
|
||||
|
||||
for (int draw_iteration_index = draw_iterations - 1; draw_iteration_index >= 0; --draw_iteration_index) {
|
||||
LabelSettings::StackedOutlineData stacked_outline_data = stacked_outline_datas[draw_iteration_index];
|
||||
if (stacked_outline_data.size <= 0) {
|
||||
continue;
|
||||
}
|
||||
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);
|
||||
stacked_outline_draw_size -= stacked_outline_data.size;
|
||||
}
|
||||
}
|
||||
|
||||
// Draw outline.
|
||||
if (outline_size > 0 && font_outline_color.a != 0) {
|
||||
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);
|
||||
}
|
||||
|
||||
// Draw text.
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
processed_glyphs = processed_glyphs_step;
|
||||
ofs.y += dsc + line_spacing;
|
||||
}
|
||||
|
||||
@@ -37,14 +37,6 @@ class Label : public Control {
|
||||
GDCLASS(Label, Control);
|
||||
|
||||
private:
|
||||
enum LabelDrawStep {
|
||||
DRAW_STEP_SHADOW_OUTLINE,
|
||||
DRAW_STEP_SHADOW,
|
||||
DRAW_STEP_OUTLINE,
|
||||
DRAW_STEP_TEXT,
|
||||
DRAW_STEP_MAX,
|
||||
};
|
||||
|
||||
HorizontalAlignment horizontal_alignment = HORIZONTAL_ALIGNMENT_LEFT;
|
||||
VerticalAlignment vertical_alignment = VERTICAL_ALIGNMENT_TOP;
|
||||
String text;
|
||||
@@ -200,4 +192,55 @@ public:
|
||||
|
||||
Label(const String &p_text = String());
|
||||
~Label();
|
||||
|
||||
template <typename... VarArgsFunc, typename... VarArgs>
|
||||
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) {
|
||||
p_processed_glyphs_step = p_processed_glyphs;
|
||||
Vector2 offset_step = p_ofs; /* Draw RTL ellipsis string when necessary. */
|
||||
if (p_rtl && p_ellipsis_pos >= 0) {
|
||||
for (int gl_idx = p_ellipsis_gl_size - 1; gl_idx >= 0; gl_idx--) {
|
||||
for (int j = 0; j < p_ellipsis_glyphs[gl_idx].repeat; j++) {
|
||||
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));
|
||||
if (!skip) {
|
||||
p_draw_func(p_ellipsis_glyphs[gl_idx], p_ci, p_color, offset_step, std::forward<VarArgs>(p_args)...);
|
||||
}
|
||||
p_processed_glyphs_step++;
|
||||
offset_step.x += p_ellipsis_glyphs[gl_idx].advance;
|
||||
}
|
||||
}
|
||||
} /* Draw main text. */
|
||||
for (int j = 0; j < p_gl_size; j++) { /* Trim when necessary. */
|
||||
if (p_trim_pos >= 0) {
|
||||
if (p_rtl) {
|
||||
if (j < p_trim_pos) {
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
if (j >= p_trim_pos) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int k = 0; k < p_glyphs[j].repeat; k++) {
|
||||
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));
|
||||
if (!skip) {
|
||||
p_draw_func(p_glyphs[j], p_ci, p_color, offset_step, std::forward<VarArgs>(p_args)...);
|
||||
}
|
||||
p_processed_glyphs_step++;
|
||||
offset_step.x += p_glyphs[j].advance;
|
||||
}
|
||||
} /* Draw LTR ellipsis string when necessary. */
|
||||
if (!p_rtl && p_ellipsis_pos >= 0) {
|
||||
for (int gl_idx = 0; gl_idx < p_ellipsis_gl_size; gl_idx++) {
|
||||
for (int j = 0; j < p_ellipsis_glyphs[gl_idx].repeat; j++) {
|
||||
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));
|
||||
if (!skip) {
|
||||
p_draw_func(p_ellipsis_glyphs[gl_idx], p_ci, p_color, offset_step, std::forward<VarArgs>(p_args)...);
|
||||
}
|
||||
p_processed_glyphs_step++;
|
||||
offset_step.x += p_ellipsis_glyphs[gl_idx].advance;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -65,6 +65,30 @@ void LabelSettings::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("set_shadow_offset", "offset"), &LabelSettings::set_shadow_offset);
|
||||
ClassDB::bind_method(D_METHOD("get_shadow_offset"), &LabelSettings::get_shadow_offset);
|
||||
|
||||
// Stacked outlines
|
||||
ClassDB::bind_method(D_METHOD("get_stacked_outline_count"), &LabelSettings::get_stacked_outline_count);
|
||||
ClassDB::bind_method(D_METHOD("set_stacked_outline_count", "count"), &LabelSettings::set_stacked_outline_count);
|
||||
ClassDB::bind_method(D_METHOD("add_stacked_outline", "index"), &LabelSettings::add_stacked_outline, DEFVAL(-1));
|
||||
ClassDB::bind_method(D_METHOD("move_stacked_outline", "from_index", "to_position"), &LabelSettings::move_stacked_outline);
|
||||
ClassDB::bind_method(D_METHOD("remove_stacked_outline", "index"), &LabelSettings::remove_stacked_outline);
|
||||
ClassDB::bind_method(D_METHOD("set_stacked_outline_size", "index", "size"), &LabelSettings::set_stacked_outline_size);
|
||||
ClassDB::bind_method(D_METHOD("get_stacked_outline_size", "index"), &LabelSettings::get_stacked_outline_size);
|
||||
ClassDB::bind_method(D_METHOD("set_stacked_outline_color", "index", "color"), &LabelSettings::set_stacked_outline_color);
|
||||
ClassDB::bind_method(D_METHOD("get_stacked_outline_color", "index"), &LabelSettings::get_stacked_outline_color);
|
||||
|
||||
// Stacked shadows
|
||||
ClassDB::bind_method(D_METHOD("get_stacked_shadow_count"), &LabelSettings::get_stacked_shadow_count);
|
||||
ClassDB::bind_method(D_METHOD("set_stacked_shadow_count", "count"), &LabelSettings::set_stacked_shadow_count);
|
||||
ClassDB::bind_method(D_METHOD("add_stacked_shadow", "index"), &LabelSettings::add_stacked_shadow, DEFVAL(-1));
|
||||
ClassDB::bind_method(D_METHOD("move_stacked_shadow", "from_index", "to_position"), &LabelSettings::move_stacked_shadow);
|
||||
ClassDB::bind_method(D_METHOD("remove_stacked_shadow", "index"), &LabelSettings::remove_stacked_shadow);
|
||||
ClassDB::bind_method(D_METHOD("set_stacked_shadow_offset", "index", "offset"), &LabelSettings::set_stacked_shadow_offset);
|
||||
ClassDB::bind_method(D_METHOD("get_stacked_shadow_offset", "index"), &LabelSettings::get_stacked_shadow_offset);
|
||||
ClassDB::bind_method(D_METHOD("set_stacked_shadow_color", "index", "color"), &LabelSettings::set_stacked_shadow_color);
|
||||
ClassDB::bind_method(D_METHOD("get_stacked_shadow_color", "index"), &LabelSettings::get_stacked_shadow_color);
|
||||
ClassDB::bind_method(D_METHOD("set_stacked_shadow_outline_size", "index", "size"), &LabelSettings::set_stacked_shadow_outline_size);
|
||||
ClassDB::bind_method(D_METHOD("get_stacked_shadow_outline_size", "index"), &LabelSettings::get_stacked_shadow_outline_size);
|
||||
|
||||
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "line_spacing", PROPERTY_HINT_NONE, "suffix:px"), "set_line_spacing", "get_line_spacing");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "paragraph_spacing", PROPERTY_HINT_NONE, "suffix:px"), "set_paragraph_spacing", "get_paragraph_spacing");
|
||||
|
||||
@@ -81,6 +105,27 @@ void LabelSettings::_bind_methods() {
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "shadow_size", PROPERTY_HINT_RANGE, "0,127,1,or_greater,suffix:px"), "set_shadow_size", "get_shadow_size");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "shadow_color"), "set_shadow_color", "get_shadow_color");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "shadow_offset", PROPERTY_HINT_NONE, "suffix:px"), "set_shadow_offset", "get_shadow_offset");
|
||||
|
||||
ADD_GROUP("Stacked Effects", "");
|
||||
ADD_ARRAY_COUNT("Stacked Outlines", "stacked_outline_count", "set_stacked_outline_count", "get_stacked_outline_count", "stacked_outline_");
|
||||
ADD_ARRAY_COUNT("Stacked Shadows", "stacked_shadow_count", "set_stacked_shadow_count", "get_stacked_shadow_count", "stacked_shadow_");
|
||||
|
||||
constexpr StackedOutlineData stacked_outline_defaults;
|
||||
|
||||
stacked_outline_base_property_helper.set_prefix("stacked_outline_");
|
||||
stacked_outline_base_property_helper.set_array_length_getter(&LabelSettings::get_stacked_outline_count);
|
||||
stacked_outline_base_property_helper.register_property(PropertyInfo(Variant::INT, "size", PROPERTY_HINT_NONE, "0,127,1,or_greater,suffix:px"), stacked_outline_defaults.size, &LabelSettings::set_stacked_outline_size, &LabelSettings::get_stacked_outline_size);
|
||||
stacked_outline_base_property_helper.register_property(PropertyInfo(Variant::COLOR, "color"), stacked_outline_defaults.color, &LabelSettings::set_stacked_outline_color, &LabelSettings::get_stacked_outline_color);
|
||||
PropertyListHelper::register_base_helper(&stacked_outline_base_property_helper);
|
||||
|
||||
constexpr StackedShadowData stacked_shadow_defaults;
|
||||
|
||||
stacked_shadow_base_property_helper.set_prefix("stacked_shadow_");
|
||||
stacked_shadow_base_property_helper.set_array_length_getter(&LabelSettings::get_stacked_shadow_count);
|
||||
stacked_shadow_base_property_helper.register_property(PropertyInfo(Variant::VECTOR2, "offset", PROPERTY_HINT_NONE, "suffix:px"), stacked_shadow_defaults.offset, &LabelSettings::set_stacked_shadow_offset, &LabelSettings::get_stacked_shadow_offset);
|
||||
stacked_shadow_base_property_helper.register_property(PropertyInfo(Variant::COLOR, "color"), stacked_shadow_defaults.color, &LabelSettings::set_stacked_shadow_color, &LabelSettings::get_stacked_shadow_color);
|
||||
stacked_shadow_base_property_helper.register_property(PropertyInfo(Variant::INT, "outline_size", PROPERTY_HINT_NONE, "0,127,1,or_greater,suffix:px"), stacked_shadow_defaults.outline_size, &LabelSettings::set_stacked_shadow_outline_size, &LabelSettings::get_stacked_shadow_outline_size);
|
||||
PropertyListHelper::register_base_helper(&stacked_shadow_base_property_helper);
|
||||
}
|
||||
|
||||
void LabelSettings::set_line_spacing(real_t p_spacing) {
|
||||
@@ -198,3 +243,154 @@ void LabelSettings::set_shadow_offset(const Vector2 &p_offset) {
|
||||
Vector2 LabelSettings::get_shadow_offset() const {
|
||||
return shadow_offset;
|
||||
}
|
||||
|
||||
Vector<LabelSettings::StackedOutlineData> LabelSettings::get_stacked_outline_data() const {
|
||||
return stacked_outline_data;
|
||||
}
|
||||
|
||||
int LabelSettings::get_stacked_outline_count() const {
|
||||
return stacked_outline_data.size();
|
||||
}
|
||||
|
||||
void LabelSettings::set_stacked_outline_count(int p_count) {
|
||||
ERR_FAIL_COND(p_count < 0);
|
||||
if (stacked_outline_data.size() != p_count) {
|
||||
stacked_outline_data.resize(p_count);
|
||||
notify_property_list_changed();
|
||||
emit_changed();
|
||||
}
|
||||
}
|
||||
|
||||
void LabelSettings::add_stacked_outline(int p_index) {
|
||||
if (p_index < 0) {
|
||||
p_index = stacked_outline_data.size();
|
||||
}
|
||||
ERR_FAIL_INDEX(p_index, stacked_outline_data.size() + 1);
|
||||
stacked_outline_data.insert(p_index, StackedOutlineData());
|
||||
notify_property_list_changed();
|
||||
emit_changed();
|
||||
}
|
||||
|
||||
void LabelSettings::move_stacked_outline(int p_from_index, int p_to_position) {
|
||||
ERR_FAIL_INDEX(p_from_index, stacked_outline_data.size());
|
||||
ERR_FAIL_INDEX(p_to_position, stacked_outline_data.size() + 1);
|
||||
stacked_outline_data.insert(p_to_position, stacked_outline_data[p_from_index]);
|
||||
stacked_outline_data.remove_at(p_to_position < p_from_index ? p_from_index + 1 : p_from_index);
|
||||
notify_property_list_changed();
|
||||
emit_changed();
|
||||
}
|
||||
|
||||
void LabelSettings::remove_stacked_outline(int p_index) {
|
||||
ERR_FAIL_INDEX(p_index, stacked_outline_data.size());
|
||||
stacked_outline_data.remove_at(p_index);
|
||||
notify_property_list_changed();
|
||||
emit_changed();
|
||||
}
|
||||
|
||||
void LabelSettings::set_stacked_outline_size(int p_index, int p_size) {
|
||||
ERR_FAIL_INDEX(p_index, stacked_outline_data.size());
|
||||
if (stacked_outline_data[p_index].size != p_size) {
|
||||
stacked_outline_data.write[p_index].size = p_size;
|
||||
emit_changed();
|
||||
}
|
||||
}
|
||||
|
||||
int LabelSettings::get_stacked_outline_size(int p_index) const {
|
||||
ERR_FAIL_INDEX_V(p_index, stacked_outline_data.size(), 0);
|
||||
return stacked_outline_data[p_index].size;
|
||||
}
|
||||
|
||||
void LabelSettings::set_stacked_outline_color(int p_index, const Color &p_color) {
|
||||
ERR_FAIL_INDEX(p_index, stacked_outline_data.size());
|
||||
if (stacked_outline_data[p_index].color != p_color) {
|
||||
stacked_outline_data.write[p_index].color = p_color;
|
||||
emit_changed();
|
||||
}
|
||||
}
|
||||
|
||||
Color LabelSettings::get_stacked_outline_color(int p_index) const {
|
||||
ERR_FAIL_INDEX_V(p_index, stacked_outline_data.size(), Color());
|
||||
return stacked_outline_data[p_index].color;
|
||||
}
|
||||
|
||||
Vector<LabelSettings::StackedShadowData> LabelSettings::get_stacked_shadow_data() const {
|
||||
return stacked_shadow_data;
|
||||
}
|
||||
|
||||
int LabelSettings::get_stacked_shadow_count() const {
|
||||
return stacked_shadow_data.size();
|
||||
}
|
||||
|
||||
void LabelSettings::set_stacked_shadow_count(int p_count) {
|
||||
ERR_FAIL_COND(p_count < 0);
|
||||
if (stacked_shadow_data.size() != p_count) {
|
||||
stacked_shadow_data.resize(p_count);
|
||||
notify_property_list_changed();
|
||||
emit_changed();
|
||||
}
|
||||
}
|
||||
|
||||
void LabelSettings::add_stacked_shadow(int p_index) {
|
||||
if (p_index < 0) {
|
||||
p_index = stacked_shadow_data.size();
|
||||
}
|
||||
ERR_FAIL_INDEX(p_index, stacked_shadow_data.size() + 1);
|
||||
stacked_shadow_data.insert(p_index, StackedShadowData());
|
||||
notify_property_list_changed();
|
||||
emit_changed();
|
||||
}
|
||||
|
||||
void LabelSettings::move_stacked_shadow(int p_from_index, int p_to_position) {
|
||||
ERR_FAIL_INDEX(p_from_index, stacked_shadow_data.size());
|
||||
ERR_FAIL_INDEX(p_to_position, stacked_shadow_data.size() + 1);
|
||||
stacked_shadow_data.insert(p_to_position, stacked_shadow_data[p_from_index]);
|
||||
stacked_shadow_data.remove_at(p_to_position < p_from_index ? p_from_index + 1 : p_from_index);
|
||||
notify_property_list_changed();
|
||||
emit_changed();
|
||||
}
|
||||
|
||||
void LabelSettings::remove_stacked_shadow(int p_index) {
|
||||
ERR_FAIL_INDEX(p_index, stacked_shadow_data.size());
|
||||
stacked_shadow_data.remove_at(p_index);
|
||||
notify_property_list_changed();
|
||||
emit_changed();
|
||||
}
|
||||
|
||||
void LabelSettings::set_stacked_shadow_offset(int p_index, const Vector2 &p_offset) {
|
||||
ERR_FAIL_INDEX(p_index, stacked_shadow_data.size());
|
||||
if (stacked_shadow_data[p_index].offset != p_offset) {
|
||||
stacked_shadow_data.write[p_index].offset = p_offset;
|
||||
emit_changed();
|
||||
}
|
||||
}
|
||||
|
||||
Vector2 LabelSettings::get_stacked_shadow_offset(int p_index) const {
|
||||
ERR_FAIL_INDEX_V(p_index, stacked_shadow_data.size(), Vector2());
|
||||
return stacked_shadow_data[p_index].offset;
|
||||
}
|
||||
|
||||
void LabelSettings::set_stacked_shadow_color(int p_index, const Color &p_color) {
|
||||
ERR_FAIL_INDEX(p_index, stacked_shadow_data.size());
|
||||
if (stacked_shadow_data[p_index].color != p_color) {
|
||||
stacked_shadow_data.write[p_index].color = p_color;
|
||||
emit_changed();
|
||||
}
|
||||
}
|
||||
|
||||
Color LabelSettings::get_stacked_shadow_color(int p_index) const {
|
||||
ERR_FAIL_INDEX_V(p_index, stacked_shadow_data.size(), Color());
|
||||
return stacked_shadow_data[p_index].color;
|
||||
}
|
||||
|
||||
void LabelSettings::set_stacked_shadow_outline_size(int p_index, int p_size) {
|
||||
ERR_FAIL_INDEX(p_index, stacked_shadow_data.size());
|
||||
if (stacked_shadow_data[p_index].outline_size != p_size) {
|
||||
stacked_shadow_data.write[p_index].outline_size = p_size;
|
||||
emit_changed();
|
||||
}
|
||||
}
|
||||
|
||||
int LabelSettings::get_stacked_shadow_outline_size(int p_index) const {
|
||||
ERR_FAIL_INDEX_V(p_index, stacked_shadow_data.size(), 0);
|
||||
return stacked_shadow_data[p_index].outline_size;
|
||||
}
|
||||
|
||||
@@ -32,12 +32,25 @@
|
||||
|
||||
#include "core/io/resource.h"
|
||||
#include "font.h"
|
||||
#include "scene/property_list_helper.h"
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
class LabelSettings : public Resource {
|
||||
GDCLASS(LabelSettings, Resource);
|
||||
|
||||
public:
|
||||
struct StackedOutlineData {
|
||||
int32_t size = 0;
|
||||
Color color;
|
||||
};
|
||||
struct StackedShadowData {
|
||||
Vector2i offset = Vector2i(1, 1);
|
||||
Color color;
|
||||
int32_t outline_size = 0;
|
||||
};
|
||||
|
||||
private:
|
||||
real_t line_spacing = 3;
|
||||
real_t paragraph_spacing = 0;
|
||||
|
||||
@@ -52,10 +65,34 @@ class LabelSettings : public Resource {
|
||||
Color shadow_color = Color(0, 0, 0, 0);
|
||||
Vector2 shadow_offset = Vector2(1, 1);
|
||||
|
||||
Vector<StackedOutlineData> stacked_outline_data;
|
||||
Vector<StackedShadowData> stacked_shadow_data;
|
||||
|
||||
static inline PropertyListHelper stacked_outline_base_property_helper;
|
||||
static inline PropertyListHelper stacked_shadow_base_property_helper;
|
||||
PropertyListHelper stacked_outline_property_helper;
|
||||
PropertyListHelper stacked_shadow_property_helper;
|
||||
|
||||
void _font_changed();
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
bool _set(const StringName &p_name, const Variant &p_value) {
|
||||
return stacked_outline_property_helper.property_set_value(p_name, p_value) || stacked_shadow_property_helper.property_set_value(p_name, p_value);
|
||||
}
|
||||
bool _get(const StringName &p_name, Variant &r_ret) const {
|
||||
return stacked_outline_property_helper.property_get_value(p_name, r_ret) || stacked_shadow_property_helper.property_get_value(p_name, r_ret);
|
||||
}
|
||||
void _get_property_list(List<PropertyInfo> *p_list) const {
|
||||
stacked_outline_property_helper.get_property_list(p_list);
|
||||
stacked_shadow_property_helper.get_property_list(p_list);
|
||||
}
|
||||
bool _property_can_revert(const StringName &p_name) const {
|
||||
return stacked_outline_property_helper.property_can_revert(p_name) || stacked_shadow_property_helper.property_can_revert(p_name);
|
||||
}
|
||||
bool _property_get_revert(const StringName &p_name, Variant &r_property) const {
|
||||
return stacked_outline_property_helper.property_get_revert(p_name, r_property) || stacked_shadow_property_helper.property_get_revert(p_name, r_property);
|
||||
}
|
||||
|
||||
public:
|
||||
void set_line_spacing(real_t p_spacing);
|
||||
@@ -87,4 +124,33 @@ public:
|
||||
|
||||
void set_shadow_offset(const Vector2 &p_offset);
|
||||
Vector2 get_shadow_offset() const;
|
||||
|
||||
Vector<StackedOutlineData> get_stacked_outline_data() const;
|
||||
int get_stacked_outline_count() const;
|
||||
void set_stacked_outline_count(int p_count);
|
||||
void add_stacked_outline(int p_index = -1);
|
||||
void move_stacked_outline(int p_from_index, int p_to_position);
|
||||
void remove_stacked_outline(int p_index);
|
||||
void set_stacked_outline_size(int p_index, int p_size);
|
||||
int get_stacked_outline_size(int p_index) const;
|
||||
void set_stacked_outline_color(int p_index, const Color &p_color);
|
||||
Color get_stacked_outline_color(int p_index) const;
|
||||
|
||||
Vector<StackedShadowData> get_stacked_shadow_data() const;
|
||||
int get_stacked_shadow_count() const;
|
||||
void set_stacked_shadow_count(int p_count);
|
||||
void add_stacked_shadow(int p_index = -1);
|
||||
void move_stacked_shadow(int p_from_index, int p_to_position);
|
||||
void remove_stacked_shadow(int p_index);
|
||||
void set_stacked_shadow_offset(int p_index, const Vector2 &p_offset);
|
||||
Vector2 get_stacked_shadow_offset(int p_index) const;
|
||||
void set_stacked_shadow_color(int p_index, const Color &p_color);
|
||||
Color get_stacked_shadow_color(int p_index) const;
|
||||
void set_stacked_shadow_outline_size(int p_index, int p_size);
|
||||
int get_stacked_shadow_outline_size(int p_index) const;
|
||||
|
||||
LabelSettings() {
|
||||
stacked_outline_property_helper.setup_for_instance(stacked_outline_base_property_helper, this);
|
||||
stacked_shadow_property_helper.setup_for_instance(stacked_shadow_base_property_helper, this);
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user