diff --git a/docs/overview/style-props.md b/docs/overview/style-props.md
index 3eeaa8dd0..ed924ee99 100644
--- a/docs/overview/style-props.md
+++ b/docs/overview/style-props.md
@@ -253,7 +253,7 @@ Set the point from which the background's gradient color should start. 0 means t
### bg_grad
-Set the gradient definition. The pointed instance must exist while the object is alive. NULL to disable. It wraps `BG_GRAD_COLOR`, `BG_GRAD_DIR`, `BG_MAIN_STOP` and `BG_GRAD_STOP` into one descriptor and allows craeting gradients with more colors too.
+Set the gradient definition. The pointed instance must exist while the object is alive. NULL to disable. It wraps `BG_GRAD_COLOR`, `BG_GRAD_DIR`, `BG_MAIN_STOP` and `BG_GRAD_STOP` into one descriptor and allows creating gradients with more colors too.
- Default `NULL`
- Inherited No
@@ -708,6 +708,15 @@ The intensity of mixing of color filter.
- Ext. draw No
+### anim
+The animation template for the object's animation. Should be a pointer to `lv_anim_t`. The animation parameters are widget specific, e.g. animation time could be the E.g. blink time of the cursor on the text area or scroll time of a roller. See the widgets' documentation to learn more.
+
+- Default `NULL`
+- Inherited No
+- Layout No
+- Ext. draw No
+
+
### anim_time
The animation time in milliseconds. Its meaning is widget specific. E.g. blink time of the cursor on the text area or scroll time of a roller. See the widgets' documentation to learn more.
diff --git a/docs/widgets/core/label.md b/docs/widgets/core/label.md
index 591174848..6dbd70c19 100644
--- a/docs/widgets/core/label.md
+++ b/docs/widgets/core/label.md
@@ -58,6 +58,10 @@ The whole mechanism (click and select the text as you drag your finger/mouse) is
### Very long texts
LVGL can efficiently handle very long (e.g. > 40k characters) labels by saving some extra data (~12 bytes) to speed up drawing. To enable this feature, set `LV_LABEL_LONG_TXT_HINT 1` in `lv_conf.h`.
+### Custom scrolling animations
+Some aspects of the scrolling animations in long modes `LV_LABEL_LONG_SCROLL` and `LV_LABEL_LONG_SCROLL_CIRCULAR` can be customized by setting the animation property of a style, using `lv_style_set_anim()`.
+Currently, only the start and repeat delay of the circular scrolling animation can be customized. If you need to customize another aspect of the scrolling animation, feel free to open an [issue on Github](https://github.com/lvgl/lvgl/issues) to request the feature.
+
### Symbols
The labels can display symbols alongside letters (or on their own). Read the [Font](/overview/font) section to learn more about the symbols.
diff --git a/examples/widgets/label/index.rst b/examples/widgets/label/index.rst
index 4060149a6..3296bfa24 100644
--- a/examples/widgets/label/index.rst
+++ b/examples/widgets/label/index.rst
@@ -23,3 +23,9 @@ Draw label with gradient color
.. lv_example:: widgets/label/lv_example_label_4
:language: c
+Customize circular scrolling animation
+""""""""""""""""""""""""""""""""""""
+
+.. lv_example:: widgets/label/lv_example_label_5
+ :language: c
+
diff --git a/examples/widgets/label/lv_example_label_5.c b/examples/widgets/label/lv_example_label_5.c
new file mode 100644
index 000000000..c190df695
--- /dev/null
+++ b/examples/widgets/label/lv_example_label_5.c
@@ -0,0 +1,30 @@
+#include "../../lv_examples.h"
+#if LV_USE_LABEL && LV_BUILD_EXAMPLES
+
+/**
+ * Show customizing the circular scrolling animation of a label with `LV_LABEL_LONG_SCROLL_CIRCULAR`
+ * long mode.
+ */
+void lv_example_label_5(void)
+{
+ static lv_anim_t animation_template;
+ static lv_style_t label_style;
+
+ lv_anim_init(&animation_template);
+ lv_anim_set_delay(&animation_template, 1000); /*Wait 1 second to start the first scroll*/
+ lv_anim_set_repeat_delay(&animation_template,
+ 3000); /*Repeat the scroll 3 seconds after the label scrolls back to the initial position*/
+
+ /*Initialize the label style with the animation template*/
+ lv_style_init(&label_style);
+ lv_style_set_anim(&label_style, &animation_template);
+
+ lv_obj_t * label1 = lv_label_create(lv_scr_act());
+ lv_label_set_long_mode(label1, LV_LABEL_LONG_SCROLL_CIRCULAR); /*Circular scroll*/
+ lv_obj_set_width(label1, 150);
+ lv_label_set_text(label1, "It is a circularly scrolling text. ");
+ lv_obj_align(label1, LV_ALIGN_CENTER, 0, 40);
+ lv_obj_add_style(label1, &label_style, LV_STATE_DEFAULT); /*Add the style to the label*/
+}
+
+#endif
diff --git a/examples/widgets/label/lv_example_label_5.py b/examples/widgets/label/lv_example_label_5.py
new file mode 100644
index 000000000..817d53e32
--- /dev/null
+++ b/examples/widgets/label/lv_example_label_5.py
@@ -0,0 +1,10 @@
+#
+# Show customizing the circular scrolling animation of a label with `LV_LABEL_LONG_SCROLL_CIRCULAR` long mode.
+#
+
+label1 = lv.label(lv.scr_act())
+label1.set_long_mode(lv.label.LONG.SCROLL_CIRCULAR) # Circular scroll
+label1.set_width(150)
+label1.set_text("It is a circularly scrolling text. ")
+label1.align(lv.ALIGN.CENTER, 0, 40)
+
diff --git a/examples/widgets/lv_example_widgets.h b/examples/widgets/lv_example_widgets.h
index 17b6ac20e..1d1ae16b1 100644
--- a/examples/widgets/lv_example_widgets.h
+++ b/examples/widgets/lv_example_widgets.h
@@ -82,6 +82,7 @@ void lv_example_label_1(void);
void lv_example_label_2(void);
void lv_example_label_3(void);
void lv_example_label_4(void);
+void lv_example_label_5(void);
void lv_example_led_1(void);
diff --git a/scripts/style_api_gen.py b/scripts/style_api_gen.py
index 699fbe31b..ca904833f 100755
--- a/scripts/style_api_gen.py
+++ b/scripts/style_api_gen.py
@@ -344,6 +344,10 @@ props = [
'style_type': 'num', 'var_type': 'lv_opa_t' , 'default':'`LV_OPA_TRANSP`', 'inherited': 0, 'layout': 0, 'ext_draw': 0,
'dsc': "The intensity of mixing of color filter."},
+ {'name': 'ANIM',
+ 'style_type': 'ptr', 'var_type': 'const lv_anim_t *', 'default':'`NULL`', 'inherited': 0, 'layout': 0, 'ext_draw': 0,
+ 'dsc': "The animation template for the object's animation. Should be a pointer to `lv_anim_t`. The animation parameters are widget specific, e.g. animation time could be the E.g. blink time of the cursor on the text area or scroll time of a roller. See the widgets' documentation to learn more."},
+
{'name': 'ANIM_TIME',
'style_type': 'num', 'var_type': 'uint32_t' , 'default':0, 'inherited': 0, 'layout': 0, 'ext_draw': 0,
'dsc': "The animation time in milliseconds. Its meaning is widget specific. E.g. blink time of the cursor on the text area or scroll time of a roller. See the widgets' documentation to learn more."},
diff --git a/src/core/lv_obj_style_gen.c b/src/core/lv_obj_style_gen.c
index 8eb7ebe6d..defaba7eb 100644
--- a/src/core/lv_obj_style_gen.c
+++ b/src/core/lv_obj_style_gen.c
@@ -681,6 +681,14 @@ void lv_obj_set_style_color_filter_opa(struct _lv_obj_t * obj, lv_opa_t value, l
lv_obj_set_local_style_prop(obj, LV_STYLE_COLOR_FILTER_OPA, v, selector);
}
+void lv_obj_set_style_anim(struct _lv_obj_t * obj, const lv_anim_t * value, lv_style_selector_t selector)
+{
+ lv_style_value_t v = {
+ .ptr = value
+ };
+ lv_obj_set_local_style_prop(obj, LV_STYLE_ANIM, v, selector);
+}
+
void lv_obj_set_style_anim_time(struct _lv_obj_t * obj, uint32_t value, lv_style_selector_t selector)
{
lv_style_value_t v = {
diff --git a/src/core/lv_obj_style_gen.h b/src/core/lv_obj_style_gen.h
index e4383d5ce..6ac1f8e41 100644
--- a/src/core/lv_obj_style_gen.h
+++ b/src/core/lv_obj_style_gen.h
@@ -509,6 +509,12 @@ static inline lv_opa_t lv_obj_get_style_color_filter_opa(const struct _lv_obj_t
return (lv_opa_t)v.num;
}
+static inline const lv_anim_t * lv_obj_get_style_anim(const struct _lv_obj_t * obj, uint32_t part)
+{
+ lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_ANIM);
+ return (const lv_anim_t *)v.ptr;
+}
+
static inline uint32_t lv_obj_get_style_anim_time(const struct _lv_obj_t * obj, uint32_t part)
{
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_ANIM_TIME);
@@ -631,6 +637,7 @@ void lv_obj_set_style_opa(struct _lv_obj_t * obj, lv_opa_t value, lv_style_selec
void lv_obj_set_style_color_filter_dsc(struct _lv_obj_t * obj, const lv_color_filter_dsc_t * value,
lv_style_selector_t selector);
void lv_obj_set_style_color_filter_opa(struct _lv_obj_t * obj, lv_opa_t value, lv_style_selector_t selector);
+void lv_obj_set_style_anim(struct _lv_obj_t * obj, const lv_anim_t * value, lv_style_selector_t selector);
void lv_obj_set_style_anim_time(struct _lv_obj_t * obj, uint32_t value, lv_style_selector_t selector);
void lv_obj_set_style_anim_speed(struct _lv_obj_t * obj, uint32_t value, lv_style_selector_t selector);
void lv_obj_set_style_transition(struct _lv_obj_t * obj, const lv_style_transition_dsc_t * value,
diff --git a/src/misc/lv_style.h b/src/misc/lv_style.h
index 6ec97cb57..c639cd6d9 100644
--- a/src/misc/lv_style.h
+++ b/src/misc/lv_style.h
@@ -261,12 +261,13 @@ typedef enum {
LV_STYLE_OPA = 98 | LV_STYLE_PROP_INHERIT,
LV_STYLE_COLOR_FILTER_DSC = 99,
LV_STYLE_COLOR_FILTER_OPA = 100,
- LV_STYLE_ANIM_TIME = 101,
- LV_STYLE_ANIM_SPEED = 102,
- LV_STYLE_TRANSITION = 103,
- LV_STYLE_BLEND_MODE = 104,
- LV_STYLE_LAYOUT = 105 | LV_STYLE_PROP_LAYOUT_REFR,
- LV_STYLE_BASE_DIR = 106 | LV_STYLE_PROP_INHERIT | LV_STYLE_PROP_LAYOUT_REFR,
+ LV_STYLE_ANIM = 101,
+ LV_STYLE_ANIM_TIME = 102,
+ LV_STYLE_ANIM_SPEED = 103,
+ LV_STYLE_TRANSITION = 104,
+ LV_STYLE_BLEND_MODE = 105,
+ LV_STYLE_LAYOUT = 106 | LV_STYLE_PROP_LAYOUT_REFR,
+ LV_STYLE_BASE_DIR = 107 | LV_STYLE_PROP_INHERIT | LV_STYLE_PROP_LAYOUT_REFR,
_LV_STYLE_LAST_BUILT_IN_PROP = 111,
diff --git a/src/misc/lv_style_gen.c b/src/misc/lv_style_gen.c
index b806a996b..63ca64112 100644
--- a/src/misc/lv_style_gen.c
+++ b/src/misc/lv_style_gen.c
@@ -680,6 +680,14 @@ void lv_style_set_color_filter_opa(lv_style_t * style, lv_opa_t value)
lv_style_set_prop(style, LV_STYLE_COLOR_FILTER_OPA, v);
}
+void lv_style_set_anim(lv_style_t * style, const lv_anim_t * value)
+{
+ lv_style_value_t v = {
+ .ptr = value
+ };
+ lv_style_set_prop(style, LV_STYLE_ANIM, v);
+}
+
void lv_style_set_anim_time(lv_style_t * style, uint32_t value)
{
lv_style_value_t v = {
diff --git a/src/misc/lv_style_gen.h b/src/misc/lv_style_gen.h
index 04e1f1a52..52833fd50 100644
--- a/src/misc/lv_style_gen.h
+++ b/src/misc/lv_style_gen.h
@@ -83,6 +83,7 @@ void lv_style_set_clip_corner(lv_style_t * style, bool value);
void lv_style_set_opa(lv_style_t * style, lv_opa_t value);
void lv_style_set_color_filter_dsc(lv_style_t * style, const lv_color_filter_dsc_t * value);
void lv_style_set_color_filter_opa(lv_style_t * style, lv_opa_t value);
+void lv_style_set_anim(lv_style_t * style, const lv_anim_t * value);
void lv_style_set_anim_time(lv_style_t * style, uint32_t value);
void lv_style_set_anim_speed(lv_style_t * style, uint32_t value);
void lv_style_set_transition(lv_style_t * style, const lv_style_transition_dsc_t * value);
@@ -515,6 +516,11 @@ void lv_style_set_base_dir(lv_style_t * style, lv_base_dir_t value);
.prop = LV_STYLE_COLOR_FILTER_OPA, .value = { .num = (int32_t)val } \
}
+#define LV_STYLE_CONST_ANIM(val) \
+ { \
+ .prop = LV_STYLE_ANIM, .value = { .ptr = val } \
+ }
+
#define LV_STYLE_CONST_ANIM_TIME(val) \
{ \
.prop = LV_STYLE_ANIM_TIME, .value = { .num = (int32_t)val } \
diff --git a/src/widgets/lv_label.c b/src/widgets/lv_label.c
index 0b8a1657a..6294e5203 100644
--- a/src/widgets/lv_label.c
+++ b/src/widgets/lv_label.c
@@ -1021,6 +1021,7 @@ static void lv_label_refr_text(lv_obj_t * obj)
}
/*In roll inf. mode keep the size but start offset animations*/
else if(label->long_mode == LV_LABEL_LONG_SCROLL_CIRCULAR) {
+ const lv_anim_t * anim_template = lv_obj_get_style_anim(obj, LV_PART_MAIN);
uint16_t anim_speed = lv_obj_get_style_anim_speed(obj, LV_PART_MAIN);
if(anim_speed == 0) anim_speed = LV_LABEL_DEF_SCROLL_SPEED;
lv_anim_t a;
@@ -1055,8 +1056,14 @@ static void lv_label_refr_text(lv_obj_t * obj)
lv_anim_t * anim_cur = lv_anim_get(obj, set_ofs_x_anim);
int32_t act_time = anim_cur ? anim_cur->act_time : 0;
- if(act_time < a.time) {
- a.act_time = act_time; /*To keep the old position*/
+
+ /*If a template animation exists, consider it's start delay and repeat delay*/
+ if(anim_template) {
+ a.act_time = anim_template->act_time;
+ a.repeat_delay = anim_template->repeat_delay;
+ }
+ else if(act_time < a.time) {
+ a.act_time = act_time; /*To keep the old position when the label text is updated mid-scrolling*/
a.early_apply = 0;
}
@@ -1076,8 +1083,14 @@ static void lv_label_refr_text(lv_obj_t * obj)
lv_anim_t * anim_cur = lv_anim_get(obj, set_ofs_y_anim);
int32_t act_time = anim_cur ? anim_cur->act_time : 0;
- if(act_time < a.time) {
- a.act_time = act_time; /*To keep the old position*/
+
+ /*If a template animation exists, consider it's start delay and repeat delay*/
+ if(anim_template) {
+ a.act_time = anim_template->act_time;
+ a.repeat_delay = anim_template->repeat_delay;
+ }
+ else if(act_time < a.time) {
+ a.act_time = act_time; /*To keep the old position when the label text is updated mid-scrolling*/
a.early_apply = 0;
}