diff options
| author | Hugo Locurcio <hugo.locurcio@hugo.pro> | 2023-05-16 01:09:23 +0200 |
|---|---|---|
| committer | Hugo Locurcio <hugo.locurcio@hugo.pro> | 2023-06-05 18:45:00 +0200 |
| commit | 70e6c3cbb036aa76d730db8e2a237e67cbd41058 (patch) | |
| tree | 0e2b7c228029055837bb7b8e6fb9e0f8bc3ee566 | |
| parent | 0f76ff2115ae56e6638e1e2bdb8851d470e6e0e3 (diff) | |
| download | redot-engine-70e6c3cbb036aa76d730db8e2a237e67cbd41058.tar.gz | |
Add a `[pulse]` built-in effect to RichTextLabel
In games, blinking text is one of the more frequently used animations.
It can be (sparingly) used to bring attention to important messages
in a chat log or inventory tooltip, for instance.
This effect accepts the following options:
- `freq`: How fast text blinks (higher is faster).
- `color`: The target color multiplier for blinking.
The default mostly fades out text, but not entirely (for better accessibility).
- `ease`: The easing function exponent to use.
Negative values provide in-out easing, which is why `-2.0` is the default.
| -rw-r--r-- | scene/gui/rich_text_label.cpp | 47 | ||||
| -rw-r--r-- | scene/gui/rich_text_label.h | 10 |
2 files changed, 55 insertions, 2 deletions
diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp index 6f3b7d140e..cdb2e05288 100644 --- a/scene/gui/rich_text_label.cpp +++ b/scene/gui/rich_text_label.cpp @@ -1097,6 +1097,11 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o ItemRainbow *item_rainbow = static_cast<ItemRainbow *>(item_fx); font_color = font_color.from_hsv(item_rainbow->frequency * (item_rainbow->elapsed_time + ((p_ofs.x + gloff.x) / 50)), item_rainbow->saturation, item_rainbow->value, font_color.a); + } else if (item_fx->type == ITEM_PULSE) { + ItemPulse *item_pulse = static_cast<ItemPulse *>(item_fx); + + const float sined_time = (Math::ease(Math::pingpong(item_pulse->elapsed_time, 1.0 / item_pulse->frequency) * item_pulse->frequency, item_pulse->ease)); + font_color = font_color.lerp(font_color * item_pulse->color, sined_time); } } @@ -1315,6 +1320,11 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o ItemRainbow *item_rainbow = static_cast<ItemRainbow *>(item_fx); font_color = font_color.from_hsv(item_rainbow->frequency * (item_rainbow->elapsed_time + ((p_ofs.x + off.x) / 50)), item_rainbow->saturation, item_rainbow->value, font_color.a); + } else if (item_fx->type == ITEM_PULSE) { + ItemPulse *item_pulse = static_cast<ItemPulse *>(item_fx); + + const float sined_time = (Math::ease(Math::pingpong(item_pulse->elapsed_time, 1.0 / item_pulse->frequency) * item_pulse->frequency, item_pulse->ease)); + font_color = font_color.lerp(font_color * item_pulse->color, sined_time); } } @@ -1675,7 +1685,7 @@ void RichTextLabel::_update_fx(RichTextLabel::ItemFrame *p_frame, double p_delta while (it) { ItemFX *ifx = nullptr; - if (it->type == ITEM_CUSTOMFX || it->type == ITEM_SHAKE || it->type == ITEM_WAVE || it->type == ITEM_TORNADO || it->type == ITEM_RAINBOW) { + if (it->type == ITEM_CUSTOMFX || it->type == ITEM_SHAKE || it->type == ITEM_WAVE || it->type == ITEM_TORNADO || it->type == ITEM_RAINBOW || it->type == ITEM_PULSE) { ifx = static_cast<ItemFX *>(it); } @@ -2616,7 +2626,7 @@ bool RichTextLabel::_find_strikethrough(Item *p_item) { void RichTextLabel::_fetch_item_fx_stack(Item *p_item, Vector<ItemFX *> &r_stack) { Item *item = p_item; while (item) { - if (item->type == ITEM_CUSTOMFX || item->type == ITEM_SHAKE || item->type == ITEM_WAVE || item->type == ITEM_TORNADO || item->type == ITEM_RAINBOW) { + if (item->type == ITEM_CUSTOMFX || item->type == ITEM_SHAKE || item->type == ITEM_WAVE || item->type == ITEM_TORNADO || item->type == ITEM_RAINBOW || item->type == ITEM_PULSE) { r_stack.push_back(static_cast<ItemFX *>(item)); } @@ -3480,6 +3490,17 @@ void RichTextLabel::push_rainbow(float p_saturation, float p_value, float p_freq _add_item(item, true); } +void RichTextLabel::push_pulse(const Color &p_color, float p_frequency, float p_ease) { + _stop_thread(); + MutexLock data_lock(data_mutex); + + ItemPulse *item = memnew(ItemPulse); + item->color = p_color; + item->frequency = p_frequency; + item->ease = p_ease; + _add_item(item, true); +} + void RichTextLabel::push_bgcolor(const Color &p_color) { _stop_thread(); MutexLock data_lock(data_mutex); @@ -4663,7 +4684,29 @@ void RichTextLabel::append_text(const String &p_bbcode) { pos = brk_end + 1; tag_stack.push_front("rainbow"); set_process_internal(true); + } else if (bbcode_name == "pulse") { + Color color = Color(1, 1, 1, 0.25); + OptionMap::Iterator color_option = bbcode_options.find("color"); + if (color_option) { + color = Color::from_string(color_option->value, color); + } + + float frequency = 1.0; + OptionMap::Iterator freq_option = bbcode_options.find("freq"); + if (freq_option) { + frequency = freq_option->value.to_float(); + } + float ease = -2.0; + OptionMap::Iterator ease_option = bbcode_options.find("ease"); + if (ease_option) { + ease = ease_option->value.to_float(); + } + + push_pulse(color, frequency, ease); + pos = brk_end + 1; + tag_stack.push_front("pulse"); + set_process_internal(true); } else if (tag.begins_with("bgcolor=")) { String color_str = tag.substr(8, tag.length()).unquote(); Color color = Color::from_string(color_str, theme_cache.default_color); diff --git a/scene/gui/rich_text_label.h b/scene/gui/rich_text_label.h index b502e71a4f..a69dd04c82 100644 --- a/scene/gui/rich_text_label.h +++ b/scene/gui/rich_text_label.h @@ -70,6 +70,7 @@ public: ITEM_WAVE, ITEM_TORNADO, ITEM_RAINBOW, + ITEM_PULSE, ITEM_BGCOLOR, ITEM_FGCOLOR, ITEM_META, @@ -343,6 +344,14 @@ private: ItemRainbow() { type = ITEM_RAINBOW; } }; + struct ItemPulse : public ItemFX { + Color color = Color(1.0, 1.0, 1.0, 0.25); + float frequency = 1.0f; + float ease = -2.0f; + + ItemPulse() { type = ITEM_PULSE; } + }; + struct ItemBGColor : public Item { Color color; ItemBGColor() { type = ITEM_BGCOLOR; } @@ -610,6 +619,7 @@ public: void push_wave(float p_frequency, float p_amplitude, bool p_connected); void push_tornado(float p_frequency, float p_radius, bool p_connected); void push_rainbow(float p_saturation, float p_value, float p_frequency); + void push_pulse(const Color &p_color, float p_frequency, float p_ease); void push_bgcolor(const Color &p_color); void push_fgcolor(const Color &p_color); void push_customfx(Ref<RichTextEffect> p_custom_effect, Dictionary p_environment); |
