feat(xml): add animation support (#8599)
@@ -19,11 +19,11 @@
|
||||
#endif
|
||||
|
||||
#if !LV_VERSION_CHECK(9, 3, 0)
|
||||
#error "At least LVGL v9.3 is required to use the stride attribute of the fonts"
|
||||
#error "At least LVGL v9.3 is required to use the stride attribute of the fonts"
|
||||
#endif
|
||||
|
||||
#ifndef LV_FONT_BENCHMARK_MONTSERRAT_12_ALIGNED
|
||||
#define LV_FONT_BENCHMARK_MONTSERRAT_12_ALIGNED 1
|
||||
#define LV_FONT_BENCHMARK_MONTSERRAT_12_ALIGNED 1
|
||||
#endif
|
||||
|
||||
#if LV_FONT_BENCHMARK_MONTSERRAT_12_ALIGNED
|
||||
@@ -3192,8 +3192,7 @@ static const uint16_t unicode_list_1[] = {
|
||||
};
|
||||
|
||||
/*Collect the unicode lists and glyph_id offsets*/
|
||||
static const lv_font_fmt_txt_cmap_t cmaps[] =
|
||||
{
|
||||
static const lv_font_fmt_txt_cmap_t cmaps[] = {
|
||||
{
|
||||
.range_start = 32, .range_length = 95, .glyph_id_start = 1,
|
||||
.unicode_list = NULL, .glyph_id_ofs_list = NULL, .list_length = 0, .type = LV_FONT_FMT_TXT_CMAP_FORMAT0_TINY
|
||||
@@ -3210,8 +3209,7 @@ static const lv_font_fmt_txt_cmap_t cmaps[] =
|
||||
|
||||
|
||||
/*Map glyph_ids to kern left classes*/
|
||||
static const uint8_t kern_left_class_mapping[] =
|
||||
{
|
||||
static const uint8_t kern_left_class_mapping[] = {
|
||||
0, 0, 1, 2, 0, 3, 4, 5,
|
||||
2, 6, 7, 8, 9, 10, 9, 10,
|
||||
11, 12, 0, 13, 14, 15, 16, 17,
|
||||
@@ -3234,8 +3232,7 @@ static const uint8_t kern_left_class_mapping[] =
|
||||
};
|
||||
|
||||
/*Map glyph_ids to kern right classes*/
|
||||
static const uint8_t kern_right_class_mapping[] =
|
||||
{
|
||||
static const uint8_t kern_right_class_mapping[] = {
|
||||
0, 0, 1, 2, 0, 3, 4, 5,
|
||||
2, 6, 7, 8, 9, 10, 9, 10,
|
||||
11, 12, 13, 14, 15, 16, 17, 12,
|
||||
@@ -3258,8 +3255,7 @@ static const uint8_t kern_right_class_mapping[] =
|
||||
};
|
||||
|
||||
/*Kern values between classes*/
|
||||
static const int8_t kern_class_values[] =
|
||||
{
|
||||
static const int8_t kern_class_values[] = {
|
||||
0, 1, 0, 0, 0, 0, 0, 0,
|
||||
0, 1, 0, 0, 2, 0, 0, 0,
|
||||
0, 1, 0, 0, 0, 0, 0, 0,
|
||||
@@ -3638,8 +3634,7 @@ static const int8_t kern_class_values[] =
|
||||
|
||||
|
||||
/*Collect the kern class' data in one place*/
|
||||
static const lv_font_fmt_txt_kern_classes_t kern_classes =
|
||||
{
|
||||
static const lv_font_fmt_txt_kern_classes_t kern_classes = {
|
||||
.class_pair_values = kern_class_values,
|
||||
.left_class_mapping = kern_left_class_mapping,
|
||||
.right_class_mapping = kern_right_class_mapping,
|
||||
@@ -3652,8 +3647,8 @@ static const lv_font_fmt_txt_kern_classes_t kern_classes =
|
||||
*--------------------*/
|
||||
|
||||
#if LVGL_VERSION_MAJOR == 8
|
||||
/*Store all the custom data of the font*/
|
||||
static lv_font_fmt_txt_glyph_cache_t cache;
|
||||
/*Store all the custom data of the font*/
|
||||
static lv_font_fmt_txt_glyph_cache_t cache;
|
||||
#endif
|
||||
|
||||
#if LVGL_VERSION_MAJOR >= 8
|
||||
@@ -3699,7 +3694,9 @@ lv_font_t lv_font_benchmark_montserrat_12_aligned = {
|
||||
.underline_position = -1,
|
||||
.underline_thickness = 1,
|
||||
#endif
|
||||
#if LV_VERSION_CHECK(9, 3, 0)
|
||||
.static_bitmap = 1,
|
||||
#endif
|
||||
.dsc = &font_dsc, /*The custom font data. Will be accessed by `get_glyph_bitmap/dsc` */
|
||||
#if LV_VERSION_CHECK(8, 2, 0) || LVGL_VERSION_MAJOR >= 9
|
||||
.fallback = NULL,
|
||||
|
||||
@@ -362,6 +362,13 @@ Call :cpp:expr:`lv_anim_timeline_delete(timeline)` function to delete the Animat
|
||||
**Note**: If you need to delete a Widget during Animation, be sure to delete the
|
||||
Animation Timeline before deleting the Widget. Otherwise, the program may crash or behave abnormally.
|
||||
|
||||
If a base object is set with :cpp:expr:`lv_anim_timeline_set_base_object(timeline, obj)`,
|
||||
``var`` in the added animations is assumed to be a widget name (or path) string.
|
||||
The actual widgets are retrieved by :cpp:expr:`lv_obj_get_child_by_name` before
|
||||
calling the ``exec_cb`` of the animation. That is, the ``exec_cb`` gets a pointer to
|
||||
the widget, and not the name/path.
|
||||
|
||||
|
||||
.. image:: /_static/images/anim-timeline.png
|
||||
|
||||
.. _animations_example:
|
||||
|
||||
@@ -1,7 +1,111 @@
|
||||
.. _xml_animations:
|
||||
.. _xml_animations:
|
||||
|
||||
==========
|
||||
Animations
|
||||
==========
|
||||
|
||||
TODO
|
||||
Overview
|
||||
--------
|
||||
|
||||
XML animations are built on top of :ref:`Timeline animations <animations_timeline>`.
|
||||
|
||||
Timelines are composed of simple animations. For example: *"change the ``bg_opa``
|
||||
of ``my_button_2`` from 0 to 255 in 500 ms."*
|
||||
|
||||
Each component can define its own timeline animations, which can then be played by the
|
||||
component itself or by any parent components.
|
||||
|
||||
Defining Timelines
|
||||
------------------
|
||||
|
||||
Timelines can be defined inside ``<screen>``\ s and ``<component>``\ s.
|
||||
For ``<widget>``\ s, timelines are supported only in LVGL's UI Editor,
|
||||
where C code can also be exported from them.
|
||||
|
||||
Example:
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
<animations>
|
||||
|
||||
<!-- Show the component and its children -->
|
||||
<timeline name="load">
|
||||
<animation prop="translate_x" target="self" start="-30" end="0" duration="500"/>
|
||||
<animation prop="opa" target="icon" start="0" end="255" duration="500"/>
|
||||
<animation prop="opa" target="text" start="0" end="255" duration="500" delay="200"/>
|
||||
</timeline>
|
||||
|
||||
<!-- Shake horizontally -->
|
||||
<timeline name="shake">
|
||||
<animation prop="translate_x" target="self" start="0" end="-30" duration="150"/>
|
||||
<animation prop="translate_x" target="self" start="-30" end="30" duration="300" delay="150"/>
|
||||
<animation prop="translate_x" target="self" start="30" end="0" duration="150" delay="450"/>
|
||||
</timeline>
|
||||
</animations>
|
||||
|
||||
<view>
|
||||
<lv_button width="200">
|
||||
<my_icon name="icon" src="image1"/>
|
||||
<lv_label name="text" text="Click me"/>
|
||||
</lv_button>
|
||||
</view>
|
||||
|
||||
In summary: inside ``<animations>``, you can define ``<timeline>``\ s, each with a unique name
|
||||
that you can reference later.
|
||||
|
||||
Inside a ``<timeline>``, you add ``<animation>``\ s to describe each step.
|
||||
Supported properties of ``<animation>`` are:
|
||||
|
||||
- ``prop``: Style property to animate. All integer style properties are supported (colors are not).
|
||||
- ``selector``: Style selector, e.g. ``knob|pressed``. Default: ``main|default``.
|
||||
- ``target``: Name of the UI element to animate. ``self`` refers to the root element of the component (the ``<view>``).
|
||||
- ``start``: Start value (integer only).
|
||||
- ``end``: End value (integer only).
|
||||
- ``duration``: Duration of the animation in milliseconds.
|
||||
- ``delay``: Delay before starting in milliseconds.
|
||||
- ``early_apply``: If ``true``, the start value is applied immediately, even during the delay.
|
||||
|
||||
Playing Timelines
|
||||
-----------------
|
||||
|
||||
Timelines can be triggered by events (e.g. click) using ``<play_timeline_event>``
|
||||
as a child of any widget.
|
||||
|
||||
Example:
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
<view>
|
||||
<lv_label name="title" text="Hello world!"/>
|
||||
<custom_button name="button" y="20">
|
||||
<play_timeline_event trigger="clicked" target="button" timeline="bounce"/>
|
||||
<lv_label text="Click me"/>
|
||||
</custom_button>
|
||||
</view>
|
||||
|
||||
You set a ``target`` UI element and select one of its ``timeline``s to play.
|
||||
If ``target="self"``, the timeline is looked up in the current component/widget/screen
|
||||
(i.e. in the current XML file).
|
||||
|
||||
You can also set ``delay`` and ``reverse="true"`` when playing a timeline.
|
||||
|
||||
Under the Hood
|
||||
--------------
|
||||
|
||||
Understanding how timelines work internally helps use them effectively.
|
||||
|
||||
When an XML file is registered, the contents of the ``<animations>`` section are parsed,
|
||||
and the animation data is stored as a blueprint.
|
||||
|
||||
When an instance of a component or screen is created, ``lv_anim_timeline``\ s are
|
||||
created and initialized from the saved blueprint. Each instance gets its own copy.
|
||||
|
||||
When a ``<play_timeline_event>`` is added to a UI element, the target and timeline
|
||||
names are saved as strings. (It can't use pointers as the event can reference UI elements
|
||||
that will be created only later in the ``<view>``.)
|
||||
|
||||
Finally, when the trigger event happens, LVGL finds the target widget by the saved name,
|
||||
retrieves the specified timeline, and starts it.
|
||||
|
||||
Since each instance has its own timeline, you can have multiple components (e.g. 10 ``<list_item>``\ s)
|
||||
and play their ``load`` timelines independently with different delays.
|
||||
|
||||
@@ -261,6 +261,7 @@ typedef struct _lv_global_t {
|
||||
|
||||
#if LV_USE_XML
|
||||
const char * xml_path_prefix;
|
||||
uint32_t lv_event_xml_store_timeline;
|
||||
#endif
|
||||
|
||||
#if LV_USE_DRAW_EVE
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "../misc/lv_math.h"
|
||||
#include "../misc/lv_log.h"
|
||||
#include "../misc/lv_types.h"
|
||||
#include "../misc/lv_anim_timeline.h"
|
||||
#include "../tick/lv_tick.h"
|
||||
#include "../stdlib/lv_string.h"
|
||||
#include "lv_obj_draw_private.h"
|
||||
@@ -49,6 +50,12 @@ typedef struct {
|
||||
} target;
|
||||
} screen_load_anim_dsc_t;
|
||||
|
||||
typedef struct {
|
||||
lv_anim_timeline_t * at;
|
||||
uint32_t delay;
|
||||
bool reverse;
|
||||
} timeline_play_dsc_t;
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
@@ -65,6 +72,7 @@ static void lv_obj_children_remove_state(lv_obj_t * obj, lv_state_t state);
|
||||
static void null_on_delete_cb(lv_event_t * e);
|
||||
static void screen_load_on_trigger_event_cb(lv_event_t * e);
|
||||
static void screen_create_on_trigger_event_cb(lv_event_t * e);
|
||||
static void play_timeline_on_trigger_event_cb(lv_event_t * e);
|
||||
static void free_user_data_on_delete_event_cb(lv_event_t * e);
|
||||
static void delete_on_screen_unloaded_event_cb(lv_event_t * e);
|
||||
|
||||
@@ -518,6 +526,20 @@ void lv_obj_add_screen_create_event(lv_obj_t * obj, lv_event_code_t trigger, lv_
|
||||
lv_obj_add_event_cb(obj, free_user_data_on_delete_event_cb, LV_EVENT_DELETE, dsc);
|
||||
}
|
||||
|
||||
void lv_obj_add_play_timeline_event(lv_obj_t * obj, lv_event_code_t trigger, lv_anim_timeline_t * at, uint32_t delay,
|
||||
bool reverse)
|
||||
{
|
||||
timeline_play_dsc_t * dsc = lv_malloc(sizeof(timeline_play_dsc_t));
|
||||
LV_ASSERT_MALLOC(dsc);
|
||||
lv_memzero(dsc, sizeof(timeline_play_dsc_t));
|
||||
dsc->at = at;
|
||||
dsc->delay = delay;
|
||||
dsc->reverse = reverse;
|
||||
|
||||
lv_obj_add_event_cb(obj, play_timeline_on_trigger_event_cb, trigger, dsc);
|
||||
lv_obj_add_event_cb(obj, free_user_data_on_delete_event_cb, LV_EVENT_DELETE, dsc);
|
||||
}
|
||||
|
||||
void lv_obj_set_user_data(lv_obj_t * obj, void * user_data)
|
||||
{
|
||||
obj->user_data = user_data;
|
||||
@@ -1117,6 +1139,23 @@ static void screen_create_on_trigger_event_cb(lv_event_t * e)
|
||||
lv_obj_add_event_cb(screen, delete_on_screen_unloaded_event_cb, LV_EVENT_SCREEN_UNLOADED, NULL);
|
||||
}
|
||||
|
||||
static void play_timeline_on_trigger_event_cb(lv_event_t * e)
|
||||
{
|
||||
timeline_play_dsc_t * dsc = lv_event_get_user_data(e);
|
||||
LV_ASSERT_NULL(dsc);
|
||||
|
||||
if(dsc->reverse) {
|
||||
lv_anim_timeline_set_progress(dsc->at, LV_ANIM_TIMELINE_PROGRESS_MAX);
|
||||
lv_anim_timeline_set_reverse(dsc->at, true);
|
||||
}
|
||||
else {
|
||||
lv_anim_timeline_set_progress(dsc->at, 0);
|
||||
lv_anim_timeline_set_reverse(dsc->at, false);
|
||||
}
|
||||
lv_anim_timeline_set_delay(dsc->at, dsc->delay);
|
||||
lv_anim_timeline_start(dsc->at);
|
||||
}
|
||||
|
||||
static void free_user_data_on_delete_event_cb(lv_event_t * e)
|
||||
{
|
||||
lv_free(lv_event_get_user_data(e));
|
||||
|
||||
@@ -368,6 +368,18 @@ void lv_obj_add_screen_load_event(lv_obj_t * obj, lv_event_code_t trigger, lv_ob
|
||||
void lv_obj_add_screen_create_event(lv_obj_t * obj, lv_event_code_t trigger, lv_screen_create_cb_t screen_create_cb,
|
||||
lv_screen_load_anim_t anim_type, uint32_t duration, uint32_t delay);
|
||||
|
||||
|
||||
/**
|
||||
* Play a timeline animation on a trigger
|
||||
* @param obj pointer to widget which should trigger playing the animation
|
||||
* @param trigger an event code, e.g. `LV_EVENT_CLICKED`
|
||||
* @param at pointer to an animation timeline
|
||||
* @param delay wait time before starting the animation
|
||||
* @param reverse true: play in reverse
|
||||
*/
|
||||
void lv_obj_add_play_timeline_event(lv_obj_t * obj, lv_event_code_t trigger, lv_anim_timeline_t * at, uint32_t delay,
|
||||
bool reverse);
|
||||
|
||||
#if LV_USE_OBJ_ID
|
||||
/**
|
||||
* Set an id for an object.
|
||||
|
||||
@@ -8,9 +8,12 @@
|
||||
*********************/
|
||||
#include "lv_anim_private.h"
|
||||
#include "lv_assert.h"
|
||||
#include "lv_anim_timeline.h"
|
||||
#include "lv_anim_timeline_private.h"
|
||||
#include "../stdlib/lv_mem.h"
|
||||
#include "../stdlib/lv_string.h"
|
||||
#if LV_USE_OBJ_NAME
|
||||
#include "../core/lv_obj_tree.h"
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
@@ -19,23 +22,6 @@
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
/*Data of anim_timeline_dsc*/
|
||||
typedef struct {
|
||||
lv_anim_t anim;
|
||||
uint32_t start_time;
|
||||
uint8_t is_started : 1;
|
||||
uint8_t is_completed : 1;
|
||||
} lv_anim_timeline_dsc_t;
|
||||
|
||||
/*Data of anim_timeline*/
|
||||
struct _lv_anim_timeline_t {
|
||||
lv_anim_timeline_dsc_t * anim_dsc; /**< Dynamically allocated anim dsc array*/
|
||||
uint32_t anim_dsc_cnt; /**< The length of anim dsc array*/
|
||||
uint32_t act_time; /**< Current time of the animation*/
|
||||
bool reverse; /**< Reverse playback*/
|
||||
uint32_t repeat_count; /**< Repeat count*/
|
||||
uint32_t repeat_delay; /**< Wait before repeat*/
|
||||
};
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
@@ -43,6 +29,7 @@ struct _lv_anim_timeline_t {
|
||||
static void anim_timeline_exec_cb(void * var, int32_t v);
|
||||
static void anim_timeline_set_act_time(lv_anim_timeline_t * at, uint32_t act_time);
|
||||
static int32_t anim_timeline_path_cb(const lv_anim_t * a);
|
||||
static void exec_anim(lv_anim_timeline_t * at, lv_anim_t * a, int32_t v);
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
@@ -92,7 +79,7 @@ uint32_t lv_anim_timeline_start(lv_anim_timeline_t * at)
|
||||
|
||||
uint32_t playtime = lv_anim_timeline_get_playtime(at);
|
||||
uint32_t repeat = at->repeat_count;
|
||||
uint32_t delay = at->repeat_delay;
|
||||
uint32_t repeat_delay = at->repeat_delay;
|
||||
uint32_t start = at->act_time;
|
||||
uint32_t end = at->reverse ? 0 : playtime;
|
||||
uint32_t duration = end > start ? end - start : start - end;
|
||||
@@ -104,15 +91,21 @@ uint32_t lv_anim_timeline_start(lv_anim_timeline_t * at)
|
||||
}
|
||||
}
|
||||
|
||||
/*Apply the delay only if playing from any ends*/
|
||||
uint32_t delay = 0;
|
||||
if(!at->reverse && at->act_time == 0) delay = at->delay;
|
||||
else if(at->reverse && at->act_time == playtime) delay = at->delay;
|
||||
|
||||
lv_anim_t a;
|
||||
lv_anim_init(&a);
|
||||
lv_anim_set_var(&a, at);
|
||||
lv_anim_set_exec_cb(&a, anim_timeline_exec_cb);
|
||||
lv_anim_set_values(&a, start, end);
|
||||
lv_anim_set_duration(&a, duration);
|
||||
lv_anim_set_delay(&a, delay);
|
||||
lv_anim_set_path_cb(&a, anim_timeline_path_cb);
|
||||
lv_anim_set_repeat_count(&a, repeat);
|
||||
lv_anim_set_repeat_delay(&a, delay);
|
||||
lv_anim_set_repeat_delay(&a, repeat_delay);
|
||||
lv_anim_start(&a);
|
||||
return playtime;
|
||||
}
|
||||
@@ -130,6 +123,12 @@ void lv_anim_timeline_set_reverse(lv_anim_timeline_t * at, bool reverse)
|
||||
at->reverse = reverse;
|
||||
}
|
||||
|
||||
void lv_anim_timeline_set_delay(lv_anim_timeline_t * at, uint32_t delay)
|
||||
{
|
||||
LV_ASSERT_NULL(at);
|
||||
at->delay = delay;
|
||||
}
|
||||
|
||||
void lv_anim_timeline_set_repeat_count(lv_anim_timeline_t * at, uint32_t cnt)
|
||||
{
|
||||
LV_ASSERT_NULL(at);
|
||||
@@ -151,6 +150,22 @@ void lv_anim_timeline_set_progress(lv_anim_timeline_t * at, uint16_t progress)
|
||||
anim_timeline_set_act_time(at, act_time);
|
||||
}
|
||||
|
||||
void lv_anim_timeline_set_user_data(lv_anim_timeline_t * at, void * user_data)
|
||||
{
|
||||
LV_ASSERT_NULL(at);
|
||||
at->user_data = user_data;
|
||||
}
|
||||
|
||||
#if LV_USE_OBJ_NAME
|
||||
|
||||
void lv_anim_timeline_set_base_obj(lv_anim_timeline_t * at, lv_obj_t * base_obj)
|
||||
{
|
||||
LV_ASSERT_NULL(at);
|
||||
at->base_obj = base_obj;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
uint32_t lv_anim_timeline_get_playtime(lv_anim_timeline_t * at)
|
||||
{
|
||||
LV_ASSERT_NULL(at);
|
||||
@@ -175,6 +190,13 @@ bool lv_anim_timeline_get_reverse(lv_anim_timeline_t * at)
|
||||
return at->reverse;
|
||||
}
|
||||
|
||||
|
||||
uint32_t lv_anim_timeline_get_delay(lv_anim_timeline_t * at)
|
||||
{
|
||||
LV_ASSERT_NULL(at);
|
||||
return at->delay;
|
||||
}
|
||||
|
||||
uint16_t lv_anim_timeline_get_progress(lv_anim_timeline_t * at)
|
||||
{
|
||||
LV_ASSERT_NULL(at);
|
||||
@@ -194,6 +216,22 @@ uint32_t lv_anim_timeline_get_repeat_delay(lv_anim_timeline_t * at)
|
||||
return at->repeat_delay;
|
||||
}
|
||||
|
||||
void * lv_anim_timeline_get_user_data(lv_anim_timeline_t * at)
|
||||
{
|
||||
LV_ASSERT_NULL(at);
|
||||
return at->user_data;
|
||||
}
|
||||
|
||||
|
||||
#if LV_USE_OBJ_NAME
|
||||
|
||||
lv_obj_t * lv_anim_timeline_get_base_obj(lv_anim_timeline_t * at)
|
||||
{
|
||||
LV_ASSERT_NULL(at);
|
||||
return at->base_obj;
|
||||
}
|
||||
|
||||
#endif
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
@@ -221,8 +259,7 @@ static void anim_timeline_set_act_time(lv_anim_timeline_t * at, uint32_t act_tim
|
||||
}
|
||||
|
||||
value = a->start_value;
|
||||
if(a->exec_cb) a->exec_cb(a->var, value);
|
||||
if(a->custom_exec_cb) a->custom_exec_cb(a, value);
|
||||
exec_anim(at, a, value);
|
||||
|
||||
if(anim_timeline_is_started) {
|
||||
if(at->reverse) {
|
||||
@@ -242,8 +279,7 @@ static void anim_timeline_set_act_time(lv_anim_timeline_t * at, uint32_t act_tim
|
||||
|
||||
a->act_time = act_time - start_time;
|
||||
value = a->path_cb(a);
|
||||
if(a->exec_cb) a->exec_cb(a->var, value);
|
||||
if(a->custom_exec_cb) a->custom_exec_cb(a, value);
|
||||
exec_anim(at, a, value);
|
||||
|
||||
if(anim_timeline_is_started) {
|
||||
if(at->reverse) {
|
||||
@@ -278,8 +314,7 @@ static void anim_timeline_set_act_time(lv_anim_timeline_t * at, uint32_t act_tim
|
||||
}
|
||||
|
||||
value = a->end_value;
|
||||
if(a->exec_cb) a->exec_cb(a->var, value);
|
||||
if(a->custom_exec_cb) a->custom_exec_cb(a, value);
|
||||
exec_anim(at, a, value);
|
||||
|
||||
if(anim_timeline_is_started) {
|
||||
if(at->reverse) {
|
||||
@@ -305,3 +340,39 @@ static void anim_timeline_exec_cb(void * var, int32_t v)
|
||||
lv_anim_timeline_t * at = var;
|
||||
anim_timeline_set_act_time(at, v);
|
||||
}
|
||||
|
||||
static void exec_anim(lv_anim_timeline_t * at, lv_anim_t * a, int32_t v)
|
||||
{
|
||||
|
||||
/*a->var stores children names if at->base_obj is set. */
|
||||
#if LV_USE_OBJ_NAME
|
||||
lv_obj_t * obj_resolved;
|
||||
if(at->base_obj) {
|
||||
if(lv_streq(a->var, "self")) obj_resolved = at->base_obj;
|
||||
else if(lv_streq(a->var, "")) obj_resolved = at->base_obj;
|
||||
else obj_resolved = lv_obj_get_child_by_name(at->base_obj, a->var);
|
||||
if(obj_resolved == NULL) {
|
||||
LV_LOG_WARN("Widget was not found with name `%s` as child of %p", (const char *)a->var, (void *)at->base_obj);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else {
|
||||
obj_resolved = a->var;
|
||||
}
|
||||
#else
|
||||
LV_UNUSED(at);
|
||||
lv_obj_t * obj_resolved = a->var;
|
||||
#endif
|
||||
|
||||
|
||||
if(a->exec_cb) {
|
||||
a->exec_cb(obj_resolved, v);
|
||||
}
|
||||
if(a->custom_exec_cb) {
|
||||
/*Temporarily replace the var with the resolved object*/
|
||||
void * var_ori = a->var;
|
||||
a->var = obj_resolved;
|
||||
a->custom_exec_cb(a, v);
|
||||
a->var = var_ori;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,14 @@ extern "C" {
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
typedef struct _lv_anim_timeline_t lv_anim_timeline_t;
|
||||
/*Data of anim_timeline_dsc*/
|
||||
typedef struct _lv_anim_timeline_dsc_t {
|
||||
lv_anim_t anim;
|
||||
uint32_t start_time;
|
||||
uint8_t is_started : 1;
|
||||
uint8_t is_completed : 1;
|
||||
} lv_anim_timeline_dsc_t;
|
||||
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
@@ -54,7 +61,7 @@ void lv_anim_timeline_add(lv_anim_timeline_t * at, uint32_t start_time, const lv
|
||||
/**
|
||||
* Start the animation timeline.
|
||||
* @param at pointer to the animation timeline.
|
||||
* @return total time spent in animation timeline.
|
||||
* @return total time spent in animation timeline.
|
||||
*/
|
||||
uint32_t lv_anim_timeline_start(lv_anim_timeline_t * at);
|
||||
|
||||
@@ -71,6 +78,14 @@ void lv_anim_timeline_pause(lv_anim_timeline_t * at);
|
||||
*/
|
||||
void lv_anim_timeline_set_reverse(lv_anim_timeline_t * at, bool reverse);
|
||||
|
||||
/**
|
||||
* Set the time to wait before starting the the animation.
|
||||
* Applies only when playing from the very start, or reverse from the very end.
|
||||
* @param at pointer to an animation timeline
|
||||
* @param delay the delay time in milliseconds
|
||||
*/
|
||||
void lv_anim_timeline_set_delay(lv_anim_timeline_t * at, uint32_t delay);
|
||||
|
||||
/**
|
||||
* Make the animation timeline repeat itself.
|
||||
* @param at pointer to the animation timeline.
|
||||
@@ -92,24 +107,49 @@ void lv_anim_timeline_set_repeat_delay(lv_anim_timeline_t * at, uint32_t delay);
|
||||
*/
|
||||
void lv_anim_timeline_set_progress(lv_anim_timeline_t * at, uint16_t progress);
|
||||
|
||||
/**
|
||||
* Set the user_data of a an animation timeline
|
||||
* @param at pointer to the animation timeline.
|
||||
* @param user_data pointer to any data. Only the pointer will be saved.
|
||||
*/
|
||||
void lv_anim_timeline_set_user_data(lv_anim_timeline_t * at, void * user_data);
|
||||
|
||||
#if LV_USE_OBJ_NAME
|
||||
/**
|
||||
* Set base object.
|
||||
* If set, it's assumed that the `var` of animations is a widget name (path).
|
||||
* The widget pointer will be retrieved by finding them by name on this widget.
|
||||
* @param at pointer to the animation timeline.
|
||||
* @param base_obj pointer to a widget
|
||||
*/
|
||||
void lv_anim_timeline_set_base_obj(lv_anim_timeline_t * at, lv_obj_t * base_obj);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Get the time used to play the animation timeline.
|
||||
* @param at pointer to the animation timeline.
|
||||
* @return total time spent in animation timeline.
|
||||
* @param at pointer to the animation timeline.
|
||||
* @return total time spent in animation timeline.
|
||||
*/
|
||||
uint32_t lv_anim_timeline_get_playtime(lv_anim_timeline_t * at);
|
||||
|
||||
/**
|
||||
* Get whether the animation timeline is played in reverse.
|
||||
* @param at pointer to the animation timeline.
|
||||
* @return return true if it is reverse playback.
|
||||
* @param at pointer to the animation timeline.
|
||||
* @return return true if it is reverse playback.
|
||||
*/
|
||||
bool lv_anim_timeline_get_reverse(lv_anim_timeline_t * at);
|
||||
|
||||
/**
|
||||
* Get the wait time when playing from the very start, or reverse from the very end.
|
||||
* @param at pointer to an animation timeline
|
||||
* @return the remaining time in milliseconds
|
||||
*/
|
||||
uint32_t lv_anim_timeline_get_delay(lv_anim_timeline_t * at);
|
||||
|
||||
/**
|
||||
* Get the progress of the animation timeline.
|
||||
* @param at pointer to the animation timeline.
|
||||
* @return return value 0~65535 to map 0~100% animation progress.
|
||||
* @return return value 0~65535 to map 0~100% animation progress.
|
||||
*/
|
||||
uint16_t lv_anim_timeline_get_progress(lv_anim_timeline_t * at);
|
||||
|
||||
@@ -125,6 +165,25 @@ uint32_t lv_anim_timeline_get_repeat_count(lv_anim_timeline_t * at);
|
||||
*/
|
||||
uint32_t lv_anim_timeline_get_repeat_delay(lv_anim_timeline_t * at);
|
||||
|
||||
/**
|
||||
* Get the user_data of a an animation timeline
|
||||
* @param at pointer to the animation timeline.
|
||||
*/
|
||||
void * lv_anim_timeline_get_user_data(lv_anim_timeline_t * at);
|
||||
|
||||
|
||||
#if LV_USE_OBJ_NAME
|
||||
/**
|
||||
* Get base object.
|
||||
* If set, it's assumed that the `var` of animations is a widget name (path).
|
||||
* The widget pointer will be retrieved by finding them by name on this widget.
|
||||
* @param at pointer to the animation timeline.
|
||||
* @return pointer to the base widget
|
||||
*/
|
||||
lv_obj_t * lv_anim_timeline_get_base_obj(lv_anim_timeline_t * at);
|
||||
#endif
|
||||
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
/**
|
||||
* @file lv_anim_timeline_private.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_ANIM_TIMELINE_PRIVATE_H
|
||||
#define LV_ANIM_TIMELINE_PRIVATE_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_anim_timeline.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
struct _lv_anim_timeline_dsc_t;
|
||||
|
||||
/*Data of anim_timeline*/
|
||||
struct _lv_anim_timeline_t {
|
||||
/** Dynamically allocated anim dsc array*/
|
||||
struct _lv_anim_timeline_dsc_t * anim_dsc;
|
||||
|
||||
/** The length of anim dsc array*/
|
||||
uint32_t anim_dsc_cnt;
|
||||
|
||||
/** Current time of the animation*/
|
||||
uint32_t act_time;
|
||||
|
||||
/** Reverse playback*/
|
||||
bool reverse;
|
||||
|
||||
/** Delay before starting the animation from any ends*/
|
||||
uint32_t delay;
|
||||
|
||||
/** Repeat count*/
|
||||
uint32_t repeat_count;
|
||||
|
||||
/** Wait before repeat*/
|
||||
uint32_t repeat_delay;
|
||||
|
||||
/** If set, it's assumed that the `var` of animations is a widget name (path).
|
||||
* The widget pointer will be retrieved by finding them by name on this widget.*/
|
||||
lv_obj_t * base_obj;
|
||||
|
||||
/** For any custom data*/
|
||||
void * user_data;
|
||||
};
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_ANIM_TIMELINE_PRIVATE_H*/
|
||||
@@ -489,7 +489,7 @@ const char * lv_fs_get_last(const char * path)
|
||||
|
||||
size_t i;
|
||||
for(i = len; i > 0; i--) {
|
||||
if(path[i] == '/' || path[i] == '\\') break;
|
||||
if(path[i] == '/' || path[i] == '\\' || path[i] == ':') break;
|
||||
}
|
||||
|
||||
/*No '/' or '\' in the path so return with path itself*/
|
||||
|
||||
@@ -130,6 +130,8 @@ typedef struct _lv_theme_t lv_theme_t;
|
||||
|
||||
typedef struct _lv_anim_t lv_anim_t;
|
||||
|
||||
typedef struct _lv_anim_timeline_t lv_anim_timeline_t;
|
||||
|
||||
typedef struct _lv_font_t lv_font_t;
|
||||
typedef struct _lv_font_class_t lv_font_class_t;
|
||||
typedef struct _lv_font_info_t lv_font_info_t;
|
||||
|
||||
@@ -43,11 +43,13 @@
|
||||
#include "../../libs/expat/expat.h"
|
||||
#include "../../draw/lv_draw_image.h"
|
||||
#include "../../core/lv_global.h"
|
||||
#include "../../misc/lv_anim_timeline_private.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
#define xml_path_prefix LV_GLOBAL_DEFAULT()->xml_path_prefix
|
||||
#define lv_event_xml_store_timeline LV_GLOBAL_DEFAULT()->lv_event_xml_store_timeline
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
@@ -58,6 +60,8 @@
|
||||
**********************/
|
||||
static void view_start_element_handler(void * user_data, const char * name, const char ** attrs);
|
||||
static void view_end_element_handler(void * user_data, const char * name);
|
||||
static void get_timeline_from_event_cb(lv_event_t * e);
|
||||
static void free_timelines_event_cb(lv_event_t * e);
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
@@ -75,6 +79,9 @@ void lv_xml_init(void)
|
||||
{
|
||||
xml_path_prefix = lv_strdup("");
|
||||
|
||||
/*It will be sued to store animation time lines in user_data*/
|
||||
lv_event_xml_store_timeline = lv_event_register_id();
|
||||
|
||||
lv_xml_component_init();
|
||||
|
||||
lv_xml_register_font(NULL, "lv_font_default", lv_font_get_default());
|
||||
@@ -129,6 +136,8 @@ void lv_xml_init(void)
|
||||
lv_obj_xml_screen_load_event_apply);
|
||||
lv_xml_widget_register("lv_obj-screen_create_event", lv_obj_xml_screen_create_event_create,
|
||||
lv_obj_xml_screen_create_event_apply);
|
||||
lv_xml_widget_register("lv_obj-play_timeline_event", lv_obj_xml_play_timeline_event_create,
|
||||
lv_obj_xml_play_timeline_event_apply);
|
||||
|
||||
lv_xml_widget_register("lv_obj-bind_style", lv_obj_xml_bind_style_create, lv_obj_xml_bind_style_apply);
|
||||
lv_xml_widget_register("lv_obj-bind_flag_if_eq", lv_obj_xml_bind_flag_create, lv_obj_xml_bind_flag_apply);
|
||||
@@ -202,6 +211,35 @@ void * lv_xml_create_in_scope(lv_obj_t * parent, lv_xml_component_scope_t * pare
|
||||
}
|
||||
#endif
|
||||
|
||||
/*Create the timelines as well*/
|
||||
if(!lv_ll_is_empty(&scope->timeline_ll)) {
|
||||
lv_xml_timeline_t * at_xml;
|
||||
lv_anim_timeline_t ** timeline_array;
|
||||
timeline_array = lv_malloc((lv_ll_get_len(&scope->timeline_ll) + 1) * sizeof(lv_anim_timeline_t *));
|
||||
uint32_t i = 0;
|
||||
LV_LL_READ(&scope->timeline_ll, at_xml) {
|
||||
lv_anim_timeline_t * at = lv_anim_timeline_create();
|
||||
at->user_data = lv_strdup(at_xml->name);
|
||||
|
||||
lv_anim_t * a_stored;
|
||||
LV_LL_READ(&at_xml->anims_ll, a_stored) {
|
||||
int32_t delay = -a_stored->act_time;
|
||||
lv_anim_timeline_add(at, delay, a_stored);
|
||||
}
|
||||
|
||||
at->base_obj = state.view;
|
||||
timeline_array[i] = at;
|
||||
i++;
|
||||
}
|
||||
|
||||
|
||||
timeline_array[i] = NULL; /*Closing to avoid storing the length*/
|
||||
|
||||
|
||||
lv_obj_add_event_cb(state.view, get_timeline_from_event_cb, lv_event_xml_store_timeline, timeline_array);
|
||||
lv_obj_add_event_cb(state.view, free_timelines_event_cb, LV_EVENT_DELETE, timeline_array);
|
||||
}
|
||||
|
||||
lv_ll_clear(&state.parent_ll);
|
||||
XML_ParserFree(parser);
|
||||
|
||||
@@ -298,7 +336,7 @@ lv_result_t lv_xml_register_font(lv_xml_component_scope_t * scope, const char *
|
||||
lv_xml_font_t * f;
|
||||
LV_LL_READ(&scope->font_ll, f) {
|
||||
if(lv_streq(f->name, name)) {
|
||||
LV_LOG_INFO("Font %s is already registered. Don't register it again.", name);
|
||||
LV_LOG_INFO("Font `%s` is already registered. Don't register it again.", name);
|
||||
return LV_RESULT_OK;
|
||||
}
|
||||
}
|
||||
@@ -342,11 +380,10 @@ lv_result_t lv_xml_register_subject(lv_xml_component_scope_t * scope, const char
|
||||
return LV_RESULT_INVALID;
|
||||
}
|
||||
|
||||
|
||||
lv_xml_subject_t * s;
|
||||
LV_LL_READ(&scope->subjects_ll, s) {
|
||||
if(lv_streq(s->name, name)) {
|
||||
LV_LOG_INFO("Subject %s is already registered. Don't register it again.", name);
|
||||
LV_LOG_INFO("Subject `%s` is already registered. Don't register it again.", name);
|
||||
return LV_RESULT_OK;
|
||||
}
|
||||
}
|
||||
@@ -382,6 +419,54 @@ lv_subject_t * lv_xml_get_subject(lv_xml_component_scope_t * scope, const char *
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
lv_result_t lv_xml_register_timeline(lv_xml_component_scope_t * scope, const char * name)
|
||||
{
|
||||
if(scope == NULL) scope = lv_xml_component_get_scope("globals");
|
||||
if(scope == NULL) {
|
||||
LV_LOG_WARN("No component found to register subject `%s`", name);
|
||||
return LV_RESULT_INVALID;
|
||||
}
|
||||
|
||||
lv_xml_timeline_t * at;
|
||||
LV_LL_READ(&scope->timeline_ll, at) {
|
||||
if(lv_streq(at->name, name)) {
|
||||
LV_LOG_INFO("Animation timeline `%s` is already registered. Don't register it again.", name);
|
||||
return LV_RESULT_OK;
|
||||
}
|
||||
}
|
||||
|
||||
at = lv_ll_ins_head(&scope->timeline_ll);
|
||||
at->name = lv_strdup(name);
|
||||
lv_ll_init(&at->anims_ll, sizeof(lv_anim_t));
|
||||
|
||||
return LV_RESULT_OK;
|
||||
}
|
||||
|
||||
void * lv_xml_get_timeline(lv_xml_component_scope_t * scope, const char * name)
|
||||
{
|
||||
lv_xml_timeline_t * at;
|
||||
if(scope) {
|
||||
LV_LL_READ(&scope->timeline_ll, at) {
|
||||
if(lv_streq(at->name, name)) return at;
|
||||
}
|
||||
}
|
||||
|
||||
/*If not found in the component check the global space*/
|
||||
if((scope == NULL || scope->name == NULL) || !lv_streq(scope->name, "globals")) {
|
||||
scope = lv_xml_component_get_scope("globals");
|
||||
if(scope) {
|
||||
LV_LL_READ(&scope->timeline_ll, at) {
|
||||
if(lv_streq(at->name, name)) return at;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LV_LOG_WARN("No timeline was found with name \"%s\".", name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
lv_result_t lv_xml_register_const(lv_xml_component_scope_t * scope, const char * name, const char * value)
|
||||
{
|
||||
if(scope == NULL) scope = lv_xml_component_get_scope("globals");
|
||||
@@ -393,7 +478,7 @@ lv_result_t lv_xml_register_const(lv_xml_component_scope_t * scope, const char *
|
||||
lv_xml_const_t * cnst;
|
||||
LV_LL_READ(&scope->const_ll, cnst) {
|
||||
if(lv_streq(cnst->name, name)) {
|
||||
LV_LOG_INFO("Const %s is already registered. Don't register it again.", name);
|
||||
LV_LOG_INFO("Const `%s` is already registered. Don't register it again.", name);
|
||||
return LV_RESULT_OK;
|
||||
}
|
||||
}
|
||||
@@ -446,7 +531,7 @@ lv_result_t lv_xml_register_image(lv_xml_component_scope_t * scope, const char *
|
||||
lv_xml_image_t * img;
|
||||
LV_LL_READ(&scope->image_ll, img) {
|
||||
if(lv_streq(img->name, name)) {
|
||||
LV_LOG_INFO("Image %s is already registered. Don't register it again.", name);
|
||||
LV_LOG_INFO("Image `%s` is already registered. Don't register it again.", name);
|
||||
return LV_RESULT_OK;
|
||||
}
|
||||
}
|
||||
@@ -503,7 +588,7 @@ lv_result_t lv_xml_register_event_cb(lv_xml_component_scope_t * scope, const cha
|
||||
lv_xml_event_cb_t * e;
|
||||
LV_LL_READ(&scope->event_ll, e) {
|
||||
if(lv_streq(e->name, name)) {
|
||||
LV_LOG_INFO("Event_cb %s is already registered. Don't register it again.", name);
|
||||
LV_LOG_INFO("Event_cb `%s` is already registered. Don't register it again.", name);
|
||||
return LV_RESULT_OK;
|
||||
}
|
||||
}
|
||||
@@ -636,8 +721,8 @@ static void view_start_element_handler(void * user_data, const char * name, cons
|
||||
{
|
||||
lv_xml_parser_state_t * state = (lv_xml_parser_state_t *)user_data;
|
||||
state->tag_name = name;
|
||||
bool is_view = false;
|
||||
|
||||
bool is_view = false;
|
||||
if(lv_streq(name, "view")) {
|
||||
const char * extends = lv_xml_get_value_of(attrs, "extends");
|
||||
name = extends ? extends : "lv_obj";
|
||||
@@ -647,7 +732,7 @@ static void view_start_element_handler(void * user_data, const char * name, cons
|
||||
lv_obj_t ** current_parent_p = lv_ll_get_tail(&state->parent_ll);
|
||||
if(current_parent_p == NULL) {
|
||||
if(state->parent == NULL) {
|
||||
LV_LOG_ERROR("There is no parent object available for %s. This also should never happen.", name);
|
||||
LV_LOG_ERROR("There is no parent object available for %s. This should never happen.", name);
|
||||
return;
|
||||
}
|
||||
else {
|
||||
@@ -721,5 +806,21 @@ static void view_end_element_handler(void * user_data, const char * name)
|
||||
}
|
||||
}
|
||||
|
||||
static void get_timeline_from_event_cb(lv_event_t * e)
|
||||
{
|
||||
void ** out = lv_event_get_param(e);
|
||||
*out = lv_event_get_user_data(e);
|
||||
}
|
||||
|
||||
static void free_timelines_event_cb(lv_event_t * e)
|
||||
{
|
||||
lv_anim_timeline_t ** at_array = lv_event_get_user_data(e);
|
||||
uint32_t i;
|
||||
for(i = 0; at_array[i]; i++) {
|
||||
lv_free(lv_anim_timeline_get_user_data(at_array[i]));
|
||||
lv_anim_timeline_delete(at_array[i]);
|
||||
}
|
||||
lv_free(at_array);
|
||||
}
|
||||
|
||||
#endif /* LV_USE_XML */
|
||||
|
||||
@@ -91,6 +91,10 @@ lv_result_t lv_xml_register_event_cb(lv_xml_component_scope_t * scope, const cha
|
||||
|
||||
lv_event_cb_t lv_xml_get_event_cb(lv_xml_component_scope_t * scope, const char * name);
|
||||
|
||||
lv_result_t lv_xml_register_timeline(lv_xml_component_scope_t * scope, const char * name);
|
||||
|
||||
void * lv_xml_get_timeline(lv_xml_component_scope_t * scope, const char * name);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
@@ -326,6 +326,184 @@ lv_screen_load_anim_t lv_xml_screen_load_anim_text_to_enum_value(const char * tx
|
||||
return LV_SCREEN_LOAD_ANIM_NONE;
|
||||
}
|
||||
|
||||
lv_style_prop_t lv_xml_style_prop_to_enum(const char * txt)
|
||||
{
|
||||
if(lv_streq(txt, "width")) return LV_STYLE_WIDTH;
|
||||
if(lv_streq(txt, "min_width")) return LV_STYLE_MIN_WIDTH;
|
||||
if(lv_streq(txt, "max_width")) return LV_STYLE_MAX_WIDTH;
|
||||
else if(lv_streq(txt, "height")) return LV_STYLE_HEIGHT;
|
||||
else if(lv_streq(txt, "min_height")) return LV_STYLE_MIN_HEIGHT;
|
||||
else if(lv_streq(txt, "max_height")) return LV_STYLE_MAX_HEIGHT;
|
||||
else if(lv_streq(txt, "length")) return LV_STYLE_LENGTH;
|
||||
else if(lv_streq(txt, "radius")) return LV_STYLE_RADIUS;
|
||||
|
||||
else if(lv_streq(txt, "pad_left")) return LV_STYLE_PAD_LEFT;
|
||||
else if(lv_streq(txt, "pad_right")) return LV_STYLE_PAD_RIGHT;
|
||||
else if(lv_streq(txt, "pad_top")) return LV_STYLE_PAD_TOP;
|
||||
else if(lv_streq(txt, "pad_bottom")) return LV_STYLE_PAD_BOTTOM;
|
||||
else if(lv_streq(txt, "pad_row")) return LV_STYLE_PAD_ROW;
|
||||
else if(lv_streq(txt, "pad_column")) return LV_STYLE_PAD_COLUMN;
|
||||
else if(lv_streq(txt, "pad_radial")) return LV_STYLE_PAD_RADIAL;
|
||||
|
||||
else if(lv_streq(txt, "margin_left")) return LV_STYLE_MARGIN_LEFT;
|
||||
else if(lv_streq(txt, "margin_right")) return LV_STYLE_MARGIN_RIGHT;
|
||||
else if(lv_streq(txt, "margin_top")) return LV_STYLE_MARGIN_TOP;
|
||||
else if(lv_streq(txt, "margin_bottom")) return LV_STYLE_MARGIN_BOTTOM;
|
||||
|
||||
else if(lv_streq(txt, "base_dir")) return LV_STYLE_BASE_DIR;
|
||||
else if(lv_streq(txt, "clip_corner")) return LV_STYLE_CLIP_CORNER;
|
||||
|
||||
else if(lv_streq(txt, "bg_opa")) return LV_STYLE_BG_OPA;
|
||||
else if(lv_streq(txt, "bg_color")) return LV_STYLE_BG_COLOR;
|
||||
else if(lv_streq(txt, "bg_grad_dir")) return LV_STYLE_BG_GRAD_DIR;
|
||||
else if(lv_streq(txt, "bg_grad_color")) return LV_STYLE_BG_GRAD_COLOR;
|
||||
else if(lv_streq(txt, "bg_main_stop")) return LV_STYLE_BG_MAIN_STOP;
|
||||
else if(lv_streq(txt, "bg_grad_stop")) return LV_STYLE_BG_GRAD_STOP;
|
||||
else if(lv_streq(txt, "bg_grad")) return LV_STYLE_BG_GRAD;
|
||||
|
||||
else if(lv_streq(txt, "bg_image_src")) return LV_STYLE_BG_IMAGE_SRC;
|
||||
else if(lv_streq(txt, "bg_image_tiled")) return LV_STYLE_BG_IMAGE_TILED;
|
||||
else if(lv_streq(txt, "bg_image_recolor")) return LV_STYLE_BG_IMAGE_RECOLOR;
|
||||
else if(lv_streq(txt, "bg_image_recolor_opa")) return LV_STYLE_BG_IMAGE_RECOLOR_OPA;
|
||||
|
||||
else if(lv_streq(txt, "border_color")) return LV_STYLE_BORDER_COLOR;
|
||||
else if(lv_streq(txt, "border_width")) return LV_STYLE_BORDER_WIDTH;
|
||||
else if(lv_streq(txt, "border_opa")) return LV_STYLE_BORDER_OPA;
|
||||
else if(lv_streq(txt, "border_side")) return LV_STYLE_BORDER_SIDE;
|
||||
else if(lv_streq(txt, "border_post")) return LV_STYLE_BORDER_POST;
|
||||
|
||||
else if(lv_streq(txt, "outline_color")) return LV_STYLE_OUTLINE_COLOR;
|
||||
else if(lv_streq(txt, "outline_width")) return LV_STYLE_OUTLINE_WIDTH;
|
||||
else if(lv_streq(txt, "outline_opa")) return LV_STYLE_OUTLINE_OPA;
|
||||
else if(lv_streq(txt, "outline_pad")) return LV_STYLE_OUTLINE_PAD;
|
||||
|
||||
else if(lv_streq(txt, "shadow_width")) return LV_STYLE_SHADOW_WIDTH;
|
||||
else if(lv_streq(txt, "shadow_color")) return LV_STYLE_SHADOW_COLOR;
|
||||
else if(lv_streq(txt, "shadow_offset_x")) return LV_STYLE_SHADOW_OFFSET_X;
|
||||
else if(lv_streq(txt, "shadow_offset_y")) return LV_STYLE_SHADOW_OFFSET_Y;
|
||||
else if(lv_streq(txt, "shadow_spread")) return LV_STYLE_SHADOW_SPREAD;
|
||||
else if(lv_streq(txt, "shadow_opa")) return LV_STYLE_SHADOW_OPA;
|
||||
|
||||
else if(lv_streq(txt, "text_color")) return LV_STYLE_TEXT_COLOR;
|
||||
else if(lv_streq(txt, "text_font")) return LV_STYLE_TEXT_FONT;
|
||||
else if(lv_streq(txt, "text_opa")) return LV_STYLE_TEXT_OPA;
|
||||
else if(lv_streq(txt, "text_align")) return LV_STYLE_TEXT_ALIGN;
|
||||
else if(lv_streq(txt, "text_letter_space")) return LV_STYLE_TEXT_LETTER_SPACE;
|
||||
else if(lv_streq(txt, "text_line_space")) return LV_STYLE_TEXT_LINE_SPACE;
|
||||
else if(lv_streq(txt, "text_decor")) return LV_STYLE_TEXT_DECOR;
|
||||
|
||||
else if(lv_streq(txt, "image_opa")) return LV_STYLE_IMAGE_OPA;
|
||||
else if(lv_streq(txt, "image_recolor")) return LV_STYLE_IMAGE_RECOLOR;
|
||||
else if(lv_streq(txt, "image_recolor_opa")) return LV_STYLE_IMAGE_RECOLOR_OPA;
|
||||
|
||||
else if(lv_streq(txt, "line_color")) return LV_STYLE_LINE_COLOR;
|
||||
else if(lv_streq(txt, "line_opa")) return LV_STYLE_LINE_OPA;
|
||||
else if(lv_streq(txt, "line_width")) return LV_STYLE_LINE_WIDTH;
|
||||
else if(lv_streq(txt, "line_dash_width")) return LV_STYLE_LINE_DASH_WIDTH;
|
||||
else if(lv_streq(txt, "line_dash_gap")) return LV_STYLE_LINE_DASH_GAP;
|
||||
else if(lv_streq(txt, "line_rounded")) return LV_STYLE_LINE_ROUNDED;
|
||||
|
||||
else if(lv_streq(txt, "arc_color")) return LV_STYLE_ARC_COLOR;
|
||||
else if(lv_streq(txt, "arc_opa")) return LV_STYLE_ARC_OPA;
|
||||
else if(lv_streq(txt, "arc_width")) return LV_STYLE_ARC_WIDTH;
|
||||
else if(lv_streq(txt, "arc_rounded")) return LV_STYLE_ARC_ROUNDED;
|
||||
else if(lv_streq(txt, "arc_image_src")) return LV_STYLE_ARC_IMAGE_SRC;
|
||||
|
||||
else if(lv_streq(txt, "opa")) return LV_STYLE_OPA;
|
||||
else if(lv_streq(txt, "opa_layered")) return LV_STYLE_OPA_LAYERED;
|
||||
else if(lv_streq(txt, "color_filter_opa")) return LV_STYLE_COLOR_FILTER_OPA;
|
||||
else if(lv_streq(txt, "anim_duration")) return LV_STYLE_ANIM_DURATION;
|
||||
else if(lv_streq(txt, "blend_mode")) return LV_STYLE_BLEND_MODE;
|
||||
else if(lv_streq(txt, "transform_width")) return LV_STYLE_TRANSFORM_WIDTH;
|
||||
else if(lv_streq(txt, "transform_height")) return LV_STYLE_TRANSFORM_HEIGHT;
|
||||
else if(lv_streq(txt, "translate_x")) return LV_STYLE_TRANSLATE_X;
|
||||
else if(lv_streq(txt, "translate_y")) return LV_STYLE_TRANSLATE_Y;
|
||||
else if(lv_streq(txt, "translate_radial")) return LV_STYLE_TRANSLATE_RADIAL;
|
||||
else if(lv_streq(txt, "transform_scale_x")) return LV_STYLE_TRANSFORM_SCALE_X;
|
||||
else if(lv_streq(txt, "transform_scale_y")) return LV_STYLE_TRANSFORM_SCALE_Y;
|
||||
else if(lv_streq(txt, "transform_rotation")) return LV_STYLE_TRANSFORM_ROTATION;
|
||||
else if(lv_streq(txt, "transform_pivot_x")) return LV_STYLE_TRANSFORM_PIVOT_X;
|
||||
else if(lv_streq(txt, "transform_pivot_y")) return LV_STYLE_TRANSFORM_PIVOT_Y;
|
||||
else if(lv_streq(txt, "transform_skew_x")) return LV_STYLE_TRANSFORM_SKEW_X;
|
||||
else if(lv_streq(txt, "transform_skew_y")) return LV_STYLE_TRANSFORM_SKEW_Y;
|
||||
else if(lv_streq(txt, "bitmap_mask_src")) return LV_STYLE_BITMAP_MASK_SRC;
|
||||
else if(lv_streq(txt, "rotary_sensitivity")) return LV_STYLE_ROTARY_SENSITIVITY;
|
||||
else if(lv_streq(txt, "recolor")) return LV_STYLE_RECOLOR;
|
||||
else if(lv_streq(txt, "recolor_opa")) return LV_STYLE_RECOLOR_OPA;
|
||||
|
||||
else if(lv_streq(txt, "layout")) return LV_STYLE_LAYOUT;
|
||||
|
||||
else if(lv_streq(txt, "flex_flow")) return LV_STYLE_FLEX_FLOW;
|
||||
else if(lv_streq(txt, "flex_grow")) return LV_STYLE_FLEX_GROW;
|
||||
else if(lv_streq(txt, "flex_main_place")) return LV_STYLE_FLEX_MAIN_PLACE;
|
||||
else if(lv_streq(txt, "flex_cross_place")) return LV_STYLE_FLEX_CROSS_PLACE;
|
||||
else if(lv_streq(txt, "flex_track_place")) return LV_STYLE_FLEX_TRACK_PLACE;
|
||||
|
||||
else if(lv_streq(txt, "grid_column_align")) return LV_STYLE_GRID_COLUMN_ALIGN;
|
||||
else if(lv_streq(txt, "grid_row_align")) return LV_STYLE_GRID_ROW_ALIGN;
|
||||
else if(lv_streq(txt, "grid_cell_column_pos")) return LV_STYLE_GRID_CELL_COLUMN_POS;
|
||||
else if(lv_streq(txt, "grid_cell_column_span")) return LV_STYLE_GRID_CELL_COLUMN_SPAN;
|
||||
else if(lv_streq(txt, "grid_cell_x_align")) return LV_STYLE_GRID_CELL_X_ALIGN;
|
||||
else if(lv_streq(txt, "grid_cell_row_pos")) return LV_STYLE_GRID_CELL_ROW_POS;
|
||||
else if(lv_streq(txt, "grid_cell_row_span")) return LV_STYLE_GRID_CELL_ROW_SPAN;
|
||||
else if(lv_streq(txt, "grid_cell_y_align")) return LV_STYLE_GRID_CELL_Y_ALIGN;
|
||||
|
||||
return LV_STYLE_PROP_INV;
|
||||
}
|
||||
|
||||
lv_state_t lv_xml_style_state_to_enum(const char * txt)
|
||||
{
|
||||
if(lv_streq("default", txt)) return LV_STATE_DEFAULT;
|
||||
else if(lv_streq("pressed", txt)) return LV_STATE_PRESSED;
|
||||
else if(lv_streq("checked", txt)) return LV_STATE_CHECKED;
|
||||
else if(lv_streq("scrolled", txt)) return LV_STATE_SCROLLED;
|
||||
else if(lv_streq("focused", txt)) return LV_STATE_FOCUSED;
|
||||
else if(lv_streq("focus_key", txt)) return LV_STATE_FOCUS_KEY;
|
||||
else if(lv_streq("edited", txt)) return LV_STATE_EDITED;
|
||||
else if(lv_streq("hovered", txt)) return LV_STATE_HOVERED;
|
||||
else if(lv_streq("disabled", txt)) return LV_STATE_DISABLED;
|
||||
else if(lv_streq("user_1", txt)) return LV_STATE_USER_1;
|
||||
else if(lv_streq("user_2", txt)) return LV_STATE_USER_2;
|
||||
else if(lv_streq("user_3", txt)) return LV_STATE_USER_3;
|
||||
else if(lv_streq("user_4", txt)) return LV_STATE_USER_4;
|
||||
|
||||
return 0; /*Return 0 in lack of a better option. */
|
||||
}
|
||||
|
||||
lv_part_t lv_xml_style_part_to_enum(const char * txt)
|
||||
{
|
||||
if(lv_streq("main", txt)) return LV_PART_MAIN;
|
||||
else if(lv_streq("scrollbar", txt)) return LV_PART_SCROLLBAR;
|
||||
else if(lv_streq("indicator", txt)) return LV_PART_INDICATOR;
|
||||
else if(lv_streq("knob", txt)) return LV_PART_KNOB;
|
||||
else if(lv_streq("selected", txt)) return LV_PART_SELECTED;
|
||||
else if(lv_streq("items", txt)) return LV_PART_ITEMS;
|
||||
else if(lv_streq("cursor", txt)) return LV_PART_CURSOR;
|
||||
|
||||
return 0; /*Return 0 in lack of a better option. */
|
||||
}
|
||||
|
||||
lv_style_selector_t lv_xml_style_selector_text_to_enum(const char * str)
|
||||
{
|
||||
if(str == NULL) return 0;
|
||||
lv_style_selector_t selector = 0;
|
||||
char buf[256];
|
||||
lv_strncpy(buf, str, sizeof(buf));
|
||||
|
||||
char * bufp = buf;
|
||||
const char * next = lv_xml_split_str(&bufp, '|');
|
||||
|
||||
while(next) {
|
||||
/* Handle different states and parts */
|
||||
selector |= lv_xml_style_state_to_enum(next);
|
||||
selector |= lv_xml_style_part_to_enum(next);
|
||||
|
||||
/* Move to the next token */
|
||||
next = lv_xml_split_str(&bufp, '|');
|
||||
}
|
||||
|
||||
return selector;
|
||||
}
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
@@ -146,6 +146,37 @@ lv_event_code_t lv_xml_trigger_text_to_enum_value(const char * txt);
|
||||
*/
|
||||
lv_screen_load_anim_t lv_xml_screen_load_anim_text_to_enum_value(const char * txt);
|
||||
|
||||
/**
|
||||
* Convert a style property string to enum
|
||||
* @param txt e.g. "bg_color"
|
||||
* @return the related enum, e.g. `LV_STYLE_BG_COLOR` or
|
||||
* `LV_STYLE_PROP_INV` if not found.
|
||||
*/
|
||||
lv_style_prop_t lv_xml_style_prop_to_enum(const char * txt);
|
||||
|
||||
|
||||
/**
|
||||
* Convert a style state to enum
|
||||
* @param txt e.g. "pressed"
|
||||
* @return the enum `LV_STATE_PRESSED`
|
||||
*/
|
||||
lv_state_t lv_xml_style_state_to_enum(const char * txt);
|
||||
|
||||
/**
|
||||
* Convert a style part to enum
|
||||
* @param txt e.g. "knob"
|
||||
* @return the enum `LV_PART_KNOB`
|
||||
*/
|
||||
lv_part_t lv_xml_style_part_to_enum(const char * txt);
|
||||
|
||||
|
||||
/**
|
||||
* Convert ORed style parts and states to an ORed selector
|
||||
* @param txt e.g. "knob|pressed"
|
||||
* @return the enum `LV_PART_KNOB|LV_STATE_PRESSED`
|
||||
*/
|
||||
lv_style_selector_t lv_xml_style_selector_text_to_enum(const char * str);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
@@ -30,6 +30,10 @@
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
typedef enum {
|
||||
STYLE_PROP_TYPE_INT,
|
||||
STYLE_PROP_TYPE_UNKNOWN
|
||||
} style_prop_anim_type_t;
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
@@ -41,6 +45,9 @@ static void process_font_element(lv_xml_parser_state_t * state, const char * typ
|
||||
static void process_image_element(lv_xml_parser_state_t * state, const char * type, const char ** attrs);
|
||||
static void process_prop_element(lv_xml_parser_state_t * state, const char ** attrs);
|
||||
static char * extract_view_content(const char * xml_definition);
|
||||
static style_prop_anim_type_t style_prop_anim_get_type(lv_style_prop_t prop);
|
||||
static int32_t anim_value_to_int(lv_style_prop_t prop_type, const char * value_str);
|
||||
static void int_anim_exec_cb(lv_anim_t * a, int32_t v);
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
@@ -77,6 +84,7 @@ void lv_xml_component_scope_init(lv_xml_component_scope_t * scope)
|
||||
lv_ll_init(&scope->event_ll, sizeof(lv_xml_event_cb_t));
|
||||
lv_ll_init(&scope->image_ll, sizeof(lv_xml_image_t));
|
||||
lv_ll_init(&scope->font_ll, sizeof(lv_xml_font_t));
|
||||
lv_ll_init(&scope->timeline_ll, sizeof(lv_xml_timeline_t));
|
||||
}
|
||||
|
||||
|
||||
@@ -146,7 +154,7 @@ lv_result_t lv_xml_component_register_from_data(const char * name, const char *
|
||||
XML_SetElementHandler(parser, start_metadata_handler, end_metadata_handler);
|
||||
|
||||
if(XML_Parse(parser, xml_def, lv_strlen(xml_def), XML_TRUE) == XML_STATUS_ERROR) {
|
||||
LV_LOG_ERROR("XML parsing error: %s on line %lu",
|
||||
LV_LOG_ERROR("XML parsing error; %s on line %lu",
|
||||
XML_ErrorString(XML_GetErrorCode(parser)),
|
||||
(unsigned long)XML_GetCurrentLineNumber(parser));
|
||||
XML_ParserFree(parser);
|
||||
@@ -305,6 +313,17 @@ lv_result_t lv_xml_component_unregister(const char * name)
|
||||
}
|
||||
lv_ll_clear(&scope->subjects_ll);
|
||||
|
||||
lv_xml_timeline_t * timeline;
|
||||
LV_LL_READ(&scope->timeline_ll, timeline) {
|
||||
lv_anim_t * a;
|
||||
LV_LL_READ(&timeline->anims_ll, a) {
|
||||
lv_free(a->var); /*It was the name of the target object*/
|
||||
}
|
||||
lv_ll_clear(&timeline->anims_ll);
|
||||
lv_free((char *)timeline->name);
|
||||
}
|
||||
lv_ll_clear(&scope->timeline_ll);
|
||||
|
||||
lv_free(scope);
|
||||
|
||||
return LV_RESULT_OK;
|
||||
@@ -477,6 +496,122 @@ static void process_subject_element(lv_xml_parser_state_t * state, const char *
|
||||
lv_xml_register_subject(&state->scope, name, subject);
|
||||
}
|
||||
|
||||
static void process_timeline_element(lv_xml_parser_state_t * state, const char ** attrs)
|
||||
{
|
||||
const char * name = lv_xml_get_value_of(attrs, "name");
|
||||
|
||||
if(name == NULL) {
|
||||
LV_LOG_WARN("'name' is missing from a timeline");
|
||||
return;
|
||||
}
|
||||
|
||||
/*If already registered skip all. Don't set state->context
|
||||
*so animations won't be added later either*/
|
||||
lv_xml_timeline_t * at;
|
||||
LV_LL_READ(&state->scope.timeline_ll, at) {
|
||||
if(lv_streq(at->name, name)) {
|
||||
LV_LOG_INFO("Timeline %s is already registered. Don't register it again.", name);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
lv_xml_register_timeline(&state->scope, name);
|
||||
|
||||
/*Save the created timeline so that animations can be added to it later*/
|
||||
state->context = lv_xml_get_timeline(&state->scope, name);
|
||||
}
|
||||
|
||||
static void process_animation_element(lv_xml_parser_state_t * state, const char ** attrs)
|
||||
{
|
||||
if(state->context == NULL) {
|
||||
LV_LOG_INFO("No parent timeline is set, skipping");
|
||||
return;
|
||||
}
|
||||
|
||||
const char * target_str = lv_xml_get_value_of(attrs, "target");
|
||||
const char * prop_str = lv_xml_get_value_of(attrs, "prop");
|
||||
const char * start_str = lv_xml_get_value_of(attrs, "start");
|
||||
const char * end_str = lv_xml_get_value_of(attrs, "end");
|
||||
const char * duration_str = lv_xml_get_value_of(attrs, "duration");
|
||||
const char * delay_str = lv_xml_get_value_of(attrs, "delay");
|
||||
const char * early_apply_str = lv_xml_get_value_of(attrs, "early_apply");
|
||||
const char * selector_str = lv_xml_get_value_of(attrs, "selector");
|
||||
|
||||
if(target_str == NULL) {
|
||||
LV_LOG_WARN("'target' is missing from a animation");
|
||||
return;
|
||||
}
|
||||
|
||||
if(prop_str == NULL) {
|
||||
LV_LOG_WARN("'prop' is missing from a animation");
|
||||
return;
|
||||
}
|
||||
|
||||
lv_style_prop_t prop = lv_xml_style_prop_to_enum(prop_str);
|
||||
if(prop == LV_STYLE_PROP_INV) {
|
||||
LV_LOG_WARN("Unknown style property; '%s'", prop_str);
|
||||
return;
|
||||
}
|
||||
|
||||
style_prop_anim_type_t prop_type = style_prop_anim_get_type(prop);
|
||||
if(prop_type == STYLE_PROP_TYPE_UNKNOWN) {
|
||||
LV_LOG_WARN("Style property '%s' is not animateable", prop_str);
|
||||
return;
|
||||
}
|
||||
|
||||
if(start_str == NULL) {
|
||||
LV_LOG_WARN("'start' is missing from a animation");
|
||||
return;
|
||||
}
|
||||
|
||||
if(end_str == NULL) {
|
||||
LV_LOG_WARN("'end' is missing from a animation");
|
||||
return;
|
||||
}
|
||||
|
||||
if(duration_str == NULL) duration_str = "1000";
|
||||
if(delay_str == NULL) delay_str = "0";
|
||||
if(early_apply_str == NULL) early_apply_str = "false";
|
||||
if(selector_str == NULL) selector_str = "";
|
||||
|
||||
lv_style_selector_t selector = lv_xml_style_selector_text_to_enum(selector_str);
|
||||
|
||||
int32_t start = anim_value_to_int(prop_type, start_str);
|
||||
int32_t end = anim_value_to_int(prop_type, end_str);
|
||||
|
||||
lv_xml_timeline_t * at = state->context;
|
||||
if(at == NULL) {
|
||||
LV_LOG_WARN("There was no parent timeline for the animation");
|
||||
return;
|
||||
}
|
||||
|
||||
if(target_str[0] == '#') target_str = lv_xml_get_const(&state->scope, &target_str[1]);
|
||||
if(prop_str[0] == '#') prop_str = lv_xml_get_const(&state->scope, &prop_str[1]);
|
||||
if(start_str[0] == '#') start_str = lv_xml_get_const(&state->scope, &start_str[1]);
|
||||
if(end_str[0] == '#') end_str = lv_xml_get_const(&state->scope, &end_str[1]);
|
||||
if(duration_str[0] == '#') duration_str = lv_xml_get_const(&state->scope, &duration_str[1]);
|
||||
if(delay_str[0] == '#') delay_str = lv_xml_get_const(&state->scope, &delay_str[1]);
|
||||
if(early_apply_str[0] == '#') early_apply_str = lv_xml_get_const(&state->scope, &early_apply_str[1]);
|
||||
|
||||
if(!target_str || !prop_str || !start_str || !end_str || !duration_str || !delay_str || !early_apply_str) {
|
||||
LV_LOG_WARN("Couldn't resolve one or more constants. Skipping the animation.");
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t selector_and_prop = ((prop & 0xff) << 24) | selector;
|
||||
|
||||
lv_anim_t * a = lv_ll_ins_tail(&at->anims_ll);
|
||||
|
||||
lv_anim_init(a);
|
||||
lv_anim_set_var(a, lv_strdup(target_str));
|
||||
lv_anim_set_values(a, start, end);
|
||||
lv_anim_set_custom_exec_cb(a, int_anim_exec_cb);
|
||||
lv_anim_set_duration(a, lv_xml_atoi(duration_str));
|
||||
lv_anim_set_delay(a, lv_xml_atoi(delay_str));
|
||||
lv_anim_set_early_apply(a, lv_xml_to_bool(early_apply_str));
|
||||
lv_anim_set_user_data(a, (void *)((uintptr_t)selector_and_prop));
|
||||
}
|
||||
|
||||
static void process_grad_element(lv_xml_parser_state_t * state, const char * tag_name, const char ** attrs)
|
||||
{
|
||||
lv_xml_grad_t * grad = lv_ll_ins_tail(&state->scope.gradient_ll);
|
||||
@@ -605,7 +740,7 @@ static void process_grad_element(lv_xml_parser_state_t * state, const char * tag
|
||||
dsc->dir = LV_GRAD_DIR_VER;
|
||||
}
|
||||
else {
|
||||
LV_LOG_WARN("Unknown gradient type: %s", tag_name);
|
||||
LV_LOG_WARN("Unknown gradient type; %s", tag_name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -705,7 +840,12 @@ static void start_metadata_handler(void * user_data, const char * name, const ch
|
||||
if(old_section != state->section) return; /*Ignore the section opening, e.g. <subjects>*/
|
||||
process_subject_element(state, name, attrs);
|
||||
break;
|
||||
|
||||
case LV_XML_PARSER_SECTION_TIMELINE:
|
||||
process_timeline_element(state, attrs);
|
||||
break;
|
||||
case LV_XML_PARSER_SECTION_ANIMATION:
|
||||
process_animation_element(state, attrs);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -749,4 +889,95 @@ static char * extract_view_content(const char * xml_definition)
|
||||
return view_content;
|
||||
}
|
||||
|
||||
|
||||
static style_prop_anim_type_t style_prop_anim_get_type(lv_style_prop_t prop)
|
||||
{
|
||||
switch(prop) {
|
||||
case LV_STYLE_WIDTH:
|
||||
case LV_STYLE_MIN_WIDTH:
|
||||
case LV_STYLE_MAX_WIDTH:
|
||||
case LV_STYLE_HEIGHT:
|
||||
case LV_STYLE_MIN_HEIGHT:
|
||||
case LV_STYLE_MAX_HEIGHT:
|
||||
case LV_STYLE_LENGTH:
|
||||
case LV_STYLE_RADIUS:
|
||||
case LV_STYLE_PAD_LEFT:
|
||||
case LV_STYLE_PAD_RIGHT:
|
||||
case LV_STYLE_PAD_TOP:
|
||||
case LV_STYLE_PAD_BOTTOM:
|
||||
case LV_STYLE_PAD_ROW:
|
||||
case LV_STYLE_PAD_COLUMN:
|
||||
case LV_STYLE_PAD_RADIAL:
|
||||
case LV_STYLE_MARGIN_LEFT:
|
||||
case LV_STYLE_MARGIN_RIGHT:
|
||||
case LV_STYLE_MARGIN_TOP:
|
||||
case LV_STYLE_MARGIN_BOTTOM:
|
||||
case LV_STYLE_BG_OPA:
|
||||
case LV_STYLE_BG_MAIN_STOP:
|
||||
case LV_STYLE_BG_GRAD_STOP:
|
||||
case LV_STYLE_BG_IMAGE_RECOLOR_OPA:
|
||||
case LV_STYLE_BORDER_WIDTH:
|
||||
case LV_STYLE_BORDER_OPA:
|
||||
case LV_STYLE_OUTLINE_WIDTH:
|
||||
case LV_STYLE_OUTLINE_OPA:
|
||||
case LV_STYLE_OUTLINE_PAD:
|
||||
case LV_STYLE_SHADOW_WIDTH:
|
||||
case LV_STYLE_SHADOW_OFFSET_X:
|
||||
case LV_STYLE_SHADOW_OFFSET_Y:
|
||||
case LV_STYLE_SHADOW_SPREAD:
|
||||
case LV_STYLE_SHADOW_OPA:
|
||||
case LV_STYLE_TEXT_OPA:
|
||||
case LV_STYLE_TEXT_LETTER_SPACE:
|
||||
case LV_STYLE_TEXT_LINE_SPACE:
|
||||
case LV_STYLE_IMAGE_OPA:
|
||||
case LV_STYLE_IMAGE_RECOLOR_OPA:
|
||||
case LV_STYLE_LINE_OPA:
|
||||
case LV_STYLE_LINE_WIDTH:
|
||||
case LV_STYLE_LINE_DASH_WIDTH:
|
||||
case LV_STYLE_LINE_DASH_GAP:
|
||||
case LV_STYLE_ARC_OPA:
|
||||
case LV_STYLE_ARC_WIDTH:
|
||||
case LV_STYLE_OPA:
|
||||
case LV_STYLE_OPA_LAYERED:
|
||||
case LV_STYLE_COLOR_FILTER_OPA:
|
||||
case LV_STYLE_TRANSFORM_WIDTH:
|
||||
case LV_STYLE_TRANSFORM_HEIGHT:
|
||||
case LV_STYLE_TRANSLATE_X:
|
||||
case LV_STYLE_TRANSLATE_Y:
|
||||
case LV_STYLE_TRANSLATE_RADIAL:
|
||||
case LV_STYLE_TRANSFORM_SCALE_X:
|
||||
case LV_STYLE_TRANSFORM_SCALE_Y:
|
||||
case LV_STYLE_TRANSFORM_ROTATION:
|
||||
case LV_STYLE_TRANSFORM_PIVOT_X:
|
||||
case LV_STYLE_TRANSFORM_PIVOT_Y:
|
||||
case LV_STYLE_RECOLOR_OPA:
|
||||
return STYLE_PROP_TYPE_INT;
|
||||
|
||||
default:
|
||||
return STYLE_PROP_TYPE_UNKNOWN;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
static int32_t anim_value_to_int(lv_style_prop_t prop_type, const char * value_str)
|
||||
{
|
||||
if(prop_type == STYLE_PROP_TYPE_INT) {
|
||||
return lv_xml_atoi(value_str);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void int_anim_exec_cb(lv_anim_t * a, int32_t v)
|
||||
{
|
||||
uint32_t data = (lv_uintptr_t)lv_anim_get_user_data(a);
|
||||
lv_style_prop_t prop = data >> 24;
|
||||
lv_style_selector_t selector = data & 0x00ffffff;
|
||||
|
||||
lv_style_value_t style_value;
|
||||
style_value.num = v;
|
||||
lv_obj_set_local_style_prop(a->var, prop, style_value, selector);
|
||||
}
|
||||
|
||||
|
||||
#endif /* LV_USE_XML */
|
||||
|
||||
@@ -34,6 +34,7 @@ struct _lv_xml_component_scope_t {
|
||||
lv_ll_t param_ll;
|
||||
lv_ll_t gradient_ll;
|
||||
lv_ll_t subjects_ll;
|
||||
lv_ll_t timeline_ll;
|
||||
lv_ll_t font_ll;
|
||||
lv_ll_t image_ll;
|
||||
lv_ll_t event_ll;
|
||||
@@ -54,6 +55,11 @@ typedef struct {
|
||||
lv_subject_t * subject;
|
||||
} lv_xml_subject_t;
|
||||
|
||||
typedef struct {
|
||||
const char * name;
|
||||
lv_ll_t anims_ll;
|
||||
} lv_xml_timeline_t;
|
||||
|
||||
typedef struct {
|
||||
const char * name;
|
||||
const char * def;
|
||||
|
||||
@@ -81,6 +81,14 @@ void lv_xml_parser_start_section(lv_xml_parser_state_t * state, const char * nam
|
||||
state->section = LV_XML_PARSER_SECTION_SUBJECTS;
|
||||
return;
|
||||
}
|
||||
else if(lv_streq(name, "animation")) {
|
||||
state->section = LV_XML_PARSER_SECTION_ANIMATION;
|
||||
return;
|
||||
}
|
||||
else if(lv_streq(name, "timeline")) {
|
||||
state->section = LV_XML_PARSER_SECTION_TIMELINE;
|
||||
return;
|
||||
}
|
||||
else if(lv_streq(name, "view")) {
|
||||
state->section = LV_XML_PARSER_SECTION_VIEW;
|
||||
return;
|
||||
|
||||
@@ -38,6 +38,8 @@ typedef enum {
|
||||
LV_XML_PARSER_SECTION_FONTS,
|
||||
LV_XML_PARSER_SECTION_IMAGES,
|
||||
LV_XML_PARSER_SECTION_SUBJECTS,
|
||||
LV_XML_PARSER_SECTION_ANIMATION,
|
||||
LV_XML_PARSER_SECTION_TIMELINE,
|
||||
LV_XML_PARSER_SECTION_VIEW
|
||||
} lv_xml_parser_section_t;
|
||||
|
||||
@@ -48,6 +50,7 @@ struct _lv_xml_parser_state_t {
|
||||
lv_obj_t * parent;
|
||||
lv_obj_t * item;
|
||||
lv_obj_t * view; /*Pointer to the created view during component creation*/
|
||||
void * context; /*Custom data that can be stored during parsing*/
|
||||
const char ** parent_attrs;
|
||||
lv_xml_component_scope_t * parent_scope;
|
||||
lv_xml_parser_section_t section;
|
||||
|
||||
@@ -30,7 +30,6 @@
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
static lv_style_prop_t style_prop_text_to_enum(const char * txt);
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
@@ -49,38 +48,6 @@ static lv_style_prop_t style_prop_text_to_enum(const char * txt);
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
lv_state_t lv_xml_style_state_to_enum(const char * txt)
|
||||
{
|
||||
if(lv_streq("default", txt)) return LV_STATE_DEFAULT;
|
||||
else if(lv_streq("pressed", txt)) return LV_STATE_PRESSED;
|
||||
else if(lv_streq("checked", txt)) return LV_STATE_CHECKED;
|
||||
else if(lv_streq("scrolled", txt)) return LV_STATE_SCROLLED;
|
||||
else if(lv_streq("focused", txt)) return LV_STATE_FOCUSED;
|
||||
else if(lv_streq("focus_key", txt)) return LV_STATE_FOCUS_KEY;
|
||||
else if(lv_streq("edited", txt)) return LV_STATE_EDITED;
|
||||
else if(lv_streq("hovered", txt)) return LV_STATE_HOVERED;
|
||||
else if(lv_streq("disabled", txt)) return LV_STATE_DISABLED;
|
||||
else if(lv_streq("user_1", txt)) return LV_STATE_USER_1;
|
||||
else if(lv_streq("user_2", txt)) return LV_STATE_USER_2;
|
||||
else if(lv_streq("user_3", txt)) return LV_STATE_USER_3;
|
||||
else if(lv_streq("user_4", txt)) return LV_STATE_USER_4;
|
||||
|
||||
return 0; /*Return 0 in lack of a better option. */
|
||||
}
|
||||
|
||||
lv_part_t lv_xml_style_part_to_enum(const char * txt)
|
||||
{
|
||||
if(lv_streq("main", txt)) return LV_PART_MAIN;
|
||||
else if(lv_streq("scrollbar", txt)) return LV_PART_SCROLLBAR;
|
||||
else if(lv_streq("indicator", txt)) return LV_PART_INDICATOR;
|
||||
else if(lv_streq("knob", txt)) return LV_PART_KNOB;
|
||||
else if(lv_streq("selected", txt)) return LV_PART_SELECTED;
|
||||
else if(lv_streq("items", txt)) return LV_PART_ITEMS;
|
||||
else if(lv_streq("cursor", txt)) return LV_PART_CURSOR;
|
||||
|
||||
return 0; /*Return 0 in lack of a better option. */
|
||||
}
|
||||
|
||||
lv_result_t lv_xml_style_register(lv_xml_component_scope_t * scope, const char ** attrs)
|
||||
{
|
||||
const char * style_name = lv_xml_get_value_of(attrs, "name");
|
||||
@@ -152,7 +119,7 @@ lv_result_t lv_xml_style_register(lv_xml_component_scope_t * scope, const char *
|
||||
}
|
||||
|
||||
if(lv_streq(value, "remove")) {
|
||||
lv_style_prop_t prop = style_prop_text_to_enum(name);
|
||||
lv_style_prop_t prop = lv_xml_style_prop_to_enum(name);
|
||||
if(prop != LV_STYLE_PROP_INV) lv_style_remove_prop(style, prop);
|
||||
else if(lv_streq(name, "pad_all")) {
|
||||
lv_style_remove_prop(style, LV_STYLE_PAD_TOP);
|
||||
@@ -291,6 +258,7 @@ lv_result_t lv_xml_style_register(lv_xml_component_scope_t * scope, const char *
|
||||
else SET_STYLE_IF(transform_pivot_x, lv_xml_atoi(value));
|
||||
else SET_STYLE_IF(transform_pivot_y, lv_xml_atoi(value));
|
||||
else SET_STYLE_IF(transform_skew_x, lv_xml_atoi(value));
|
||||
else SET_STYLE_IF(transform_skew_y, lv_xml_atoi(value));
|
||||
else SET_STYLE_IF(bitmap_mask_src, lv_xml_get_image(scope, value));
|
||||
else SET_STYLE_IF(rotary_sensitivity, lv_xml_atoi(value));
|
||||
else SET_STYLE_IF(recolor, lv_xml_to_color(value));
|
||||
@@ -393,134 +361,8 @@ lv_grad_dsc_t * lv_xml_component_get_grad(lv_xml_component_scope_t * scope, cons
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
static lv_style_prop_t style_prop_text_to_enum(const char * txt)
|
||||
{
|
||||
if(lv_streq(txt, "width")) return LV_STYLE_WIDTH;
|
||||
if(lv_streq(txt, "min_width")) return LV_STYLE_MIN_WIDTH;
|
||||
if(lv_streq(txt, "max_width")) return LV_STYLE_MAX_WIDTH;
|
||||
else if(lv_streq(txt, "height")) return LV_STYLE_HEIGHT;
|
||||
else if(lv_streq(txt, "min_height")) return LV_STYLE_MIN_HEIGHT;
|
||||
else if(lv_streq(txt, "max_height")) return LV_STYLE_MAX_HEIGHT;
|
||||
else if(lv_streq(txt, "length")) return LV_STYLE_LENGTH;
|
||||
else if(lv_streq(txt, "radius")) return LV_STYLE_RADIUS;
|
||||
|
||||
else if(lv_streq(txt, "pad_left")) return LV_STYLE_PAD_LEFT;
|
||||
else if(lv_streq(txt, "pad_right")) return LV_STYLE_PAD_RIGHT;
|
||||
else if(lv_streq(txt, "pad_top")) return LV_STYLE_PAD_TOP;
|
||||
else if(lv_streq(txt, "pad_bottom")) return LV_STYLE_PAD_BOTTOM;
|
||||
else if(lv_streq(txt, "pad_row")) return LV_STYLE_PAD_ROW;
|
||||
else if(lv_streq(txt, "pad_column")) return LV_STYLE_PAD_COLUMN;
|
||||
else if(lv_streq(txt, "pad_radial")) return LV_STYLE_PAD_RADIAL;
|
||||
|
||||
else if(lv_streq(txt, "margin_left")) return LV_STYLE_MARGIN_LEFT;
|
||||
else if(lv_streq(txt, "margin_right")) return LV_STYLE_MARGIN_RIGHT;
|
||||
else if(lv_streq(txt, "margin_top")) return LV_STYLE_MARGIN_TOP;
|
||||
else if(lv_streq(txt, "margin_bottom")) return LV_STYLE_MARGIN_BOTTOM;
|
||||
|
||||
else if(lv_streq(txt, "base_dir")) return LV_STYLE_BASE_DIR;
|
||||
else if(lv_streq(txt, "clip_corner")) return LV_STYLE_CLIP_CORNER;
|
||||
|
||||
else if(lv_streq(txt, "bg_opa")) return LV_STYLE_BG_OPA;
|
||||
else if(lv_streq(txt, "bg_color")) return LV_STYLE_BG_COLOR;
|
||||
else if(lv_streq(txt, "bg_grad_dir")) return LV_STYLE_BG_GRAD_DIR;
|
||||
else if(lv_streq(txt, "bg_grad_color")) return LV_STYLE_BG_GRAD_COLOR;
|
||||
else if(lv_streq(txt, "bg_main_stop")) return LV_STYLE_BG_MAIN_STOP;
|
||||
else if(lv_streq(txt, "bg_grad_stop")) return LV_STYLE_BG_GRAD_STOP;
|
||||
else if(lv_streq(txt, "bg_grad")) return LV_STYLE_BG_GRAD;
|
||||
|
||||
else if(lv_streq(txt, "bg_image_src")) return LV_STYLE_BG_IMAGE_SRC;
|
||||
else if(lv_streq(txt, "bg_image_tiled")) return LV_STYLE_BG_IMAGE_TILED;
|
||||
else if(lv_streq(txt, "bg_image_recolor")) return LV_STYLE_BG_IMAGE_RECOLOR;
|
||||
else if(lv_streq(txt, "bg_image_recolor_opa")) return LV_STYLE_BG_IMAGE_RECOLOR_OPA;
|
||||
|
||||
else if(lv_streq(txt, "border_color")) return LV_STYLE_BORDER_COLOR;
|
||||
else if(lv_streq(txt, "border_width")) return LV_STYLE_BORDER_WIDTH;
|
||||
else if(lv_streq(txt, "border_opa")) return LV_STYLE_BORDER_OPA;
|
||||
else if(lv_streq(txt, "border_side")) return LV_STYLE_BORDER_SIDE;
|
||||
else if(lv_streq(txt, "border_post")) return LV_STYLE_BORDER_POST;
|
||||
|
||||
else if(lv_streq(txt, "outline_color")) return LV_STYLE_OUTLINE_COLOR;
|
||||
else if(lv_streq(txt, "outline_width")) return LV_STYLE_OUTLINE_WIDTH;
|
||||
else if(lv_streq(txt, "outline_opa")) return LV_STYLE_OUTLINE_OPA;
|
||||
else if(lv_streq(txt, "outline_pad")) return LV_STYLE_OUTLINE_PAD;
|
||||
|
||||
else if(lv_streq(txt, "shadow_width")) return LV_STYLE_SHADOW_WIDTH;
|
||||
else if(lv_streq(txt, "shadow_color")) return LV_STYLE_SHADOW_COLOR;
|
||||
else if(lv_streq(txt, "shadow_offset_x")) return LV_STYLE_SHADOW_OFFSET_X;
|
||||
else if(lv_streq(txt, "shadow_offset_y")) return LV_STYLE_SHADOW_OFFSET_Y;
|
||||
else if(lv_streq(txt, "shadow_spread")) return LV_STYLE_SHADOW_SPREAD;
|
||||
else if(lv_streq(txt, "shadow_opa")) return LV_STYLE_SHADOW_OPA;
|
||||
|
||||
else if(lv_streq(txt, "text_color")) return LV_STYLE_TEXT_COLOR;
|
||||
else if(lv_streq(txt, "text_font")) return LV_STYLE_TEXT_FONT;
|
||||
else if(lv_streq(txt, "text_opa")) return LV_STYLE_TEXT_OPA;
|
||||
else if(lv_streq(txt, "text_align")) return LV_STYLE_TEXT_ALIGN;
|
||||
else if(lv_streq(txt, "text_letter_space")) return LV_STYLE_TEXT_LETTER_SPACE;
|
||||
else if(lv_streq(txt, "text_line_space")) return LV_STYLE_TEXT_LINE_SPACE;
|
||||
else if(lv_streq(txt, "text_decor")) return LV_STYLE_TEXT_DECOR;
|
||||
|
||||
else if(lv_streq(txt, "image_opa")) return LV_STYLE_IMAGE_OPA;
|
||||
else if(lv_streq(txt, "image_recolor")) return LV_STYLE_IMAGE_RECOLOR;
|
||||
else if(lv_streq(txt, "image_recolor_opa")) return LV_STYLE_IMAGE_RECOLOR_OPA;
|
||||
|
||||
else if(lv_streq(txt, "line_color")) return LV_STYLE_LINE_COLOR;
|
||||
else if(lv_streq(txt, "line_opa")) return LV_STYLE_LINE_OPA;
|
||||
else if(lv_streq(txt, "line_width")) return LV_STYLE_LINE_WIDTH;
|
||||
else if(lv_streq(txt, "line_dash_width")) return LV_STYLE_LINE_DASH_WIDTH;
|
||||
else if(lv_streq(txt, "line_dash_gap")) return LV_STYLE_LINE_DASH_GAP;
|
||||
else if(lv_streq(txt, "line_rounded")) return LV_STYLE_LINE_ROUNDED;
|
||||
|
||||
else if(lv_streq(txt, "arc_color")) return LV_STYLE_ARC_COLOR;
|
||||
else if(lv_streq(txt, "arc_opa")) return LV_STYLE_ARC_OPA;
|
||||
else if(lv_streq(txt, "arc_width")) return LV_STYLE_ARC_WIDTH;
|
||||
else if(lv_streq(txt, "arc_rounded")) return LV_STYLE_ARC_ROUNDED;
|
||||
else if(lv_streq(txt, "arc_image_src")) return LV_STYLE_ARC_IMAGE_SRC;
|
||||
|
||||
else if(lv_streq(txt, "opa")) return LV_STYLE_OPA;
|
||||
else if(lv_streq(txt, "opa_layered")) return LV_STYLE_OPA_LAYERED;
|
||||
else if(lv_streq(txt, "color_filter_opa")) return LV_STYLE_COLOR_FILTER_OPA;
|
||||
else if(lv_streq(txt, "anim_duration")) return LV_STYLE_ANIM_DURATION;
|
||||
else if(lv_streq(txt, "blend_mode")) return LV_STYLE_BLEND_MODE;
|
||||
else if(lv_streq(txt, "transform_width")) return LV_STYLE_TRANSFORM_WIDTH;
|
||||
else if(lv_streq(txt, "transform_height")) return LV_STYLE_TRANSFORM_HEIGHT;
|
||||
else if(lv_streq(txt, "translate_x")) return LV_STYLE_TRANSLATE_X;
|
||||
else if(lv_streq(txt, "translate_y")) return LV_STYLE_TRANSLATE_Y;
|
||||
else if(lv_streq(txt, "translate_radial")) return LV_STYLE_TRANSLATE_RADIAL;
|
||||
else if(lv_streq(txt, "transform_scale_x")) return LV_STYLE_TRANSFORM_SCALE_X;
|
||||
else if(lv_streq(txt, "transform_scale_y")) return LV_STYLE_TRANSFORM_SCALE_Y;
|
||||
else if(lv_streq(txt, "transform_rotation")) return LV_STYLE_TRANSFORM_ROTATION;
|
||||
else if(lv_streq(txt, "transform_pivot_x")) return LV_STYLE_TRANSFORM_PIVOT_X;
|
||||
else if(lv_streq(txt, "transform_pivot_y")) return LV_STYLE_TRANSFORM_PIVOT_Y;
|
||||
else if(lv_streq(txt, "transform_skew_x")) return LV_STYLE_TRANSFORM_SKEW_X;
|
||||
else if(lv_streq(txt, "bitmap_mask_src")) return LV_STYLE_BITMAP_MASK_SRC;
|
||||
else if(lv_streq(txt, "rotary_sensitivity")) return LV_STYLE_ROTARY_SENSITIVITY;
|
||||
else if(lv_streq(txt, "recolor")) return LV_STYLE_RECOLOR;
|
||||
else if(lv_streq(txt, "recolor_opa")) return LV_STYLE_RECOLOR_OPA;
|
||||
|
||||
else if(lv_streq(txt, "layout")) return LV_STYLE_LAYOUT;
|
||||
|
||||
else if(lv_streq(txt, "flex_flow")) return LV_STYLE_FLEX_FLOW;
|
||||
else if(lv_streq(txt, "flex_grow")) return LV_STYLE_FLEX_GROW;
|
||||
else if(lv_streq(txt, "flex_main_place")) return LV_STYLE_FLEX_MAIN_PLACE;
|
||||
else if(lv_streq(txt, "flex_cross_place")) return LV_STYLE_FLEX_CROSS_PLACE;
|
||||
else if(lv_streq(txt, "flex_track_place")) return LV_STYLE_FLEX_TRACK_PLACE;
|
||||
|
||||
else if(lv_streq(txt, "grid_column_align")) return LV_STYLE_GRID_COLUMN_ALIGN;
|
||||
else if(lv_streq(txt, "grid_row_align")) return LV_STYLE_GRID_ROW_ALIGN;
|
||||
else if(lv_streq(txt, "grid_cell_column_pos")) return LV_STYLE_GRID_CELL_COLUMN_POS;
|
||||
else if(lv_streq(txt, "grid_cell_column_span")) return LV_STYLE_GRID_CELL_COLUMN_SPAN;
|
||||
else if(lv_streq(txt, "grid_cell_x_align")) return LV_STYLE_GRID_CELL_X_ALIGN;
|
||||
else if(lv_streq(txt, "grid_cell_row_pos")) return LV_STYLE_GRID_CELL_ROW_POS;
|
||||
else if(lv_streq(txt, "grid_cell_row_span")) return LV_STYLE_GRID_CELL_ROW_SPAN;
|
||||
else if(lv_streq(txt, "grid_cell_y_align")) return LV_STYLE_GRID_CELL_Y_ALIGN;
|
||||
|
||||
return LV_STYLE_PROP_INV;
|
||||
|
||||
}
|
||||
|
||||
#endif /* LV_USE_XML */
|
||||
|
||||
@@ -40,20 +40,6 @@ typedef struct _lv_xml_style_t {
|
||||
*/
|
||||
lv_result_t lv_xml_style_register(lv_xml_component_scope_t * scope, const char ** attrs);
|
||||
|
||||
/**
|
||||
* Convert a style state to enum
|
||||
* @param txt e.g. "pressed"
|
||||
* @return the enum `LV_STATE_PRESSED`
|
||||
*/
|
||||
lv_state_t lv_xml_style_state_to_enum(const char * txt);
|
||||
|
||||
/**
|
||||
* Convert a style part to enum
|
||||
* @param txt e.g. "knob"
|
||||
* @return the enum `LV_PART_KNOB`
|
||||
*/
|
||||
lv_part_t lv_xml_style_part_to_enum(const char * txt);
|
||||
|
||||
/**
|
||||
* Decompose a string like `"style1:pressed:checked:knob"` to style name and selector
|
||||
* @param txt the input string
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
#define lv_event_xml_store_timeline LV_GLOBAL_DEFAULT()->lv_event_xml_store_timeline
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
@@ -29,17 +30,26 @@ typedef struct {
|
||||
const char * screen_name;
|
||||
} screen_load_anim_dsc_t;
|
||||
|
||||
typedef struct {
|
||||
const char * timeline_name;
|
||||
const char * target_name;
|
||||
uint32_t delay;
|
||||
bool reverse;
|
||||
lv_obj_t * base_obj; /**< Get the objs by name from here (the view) */
|
||||
} play_anim_dsc_t;
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
static lv_obj_flag_t flag_to_enum(const char * txt);
|
||||
static void apply_styles(lv_xml_parser_state_t * state, lv_obj_t * obj, const char * name, const char * value);
|
||||
static lv_style_selector_t get_selector(const char * str);
|
||||
static void free_user_data_event_cb(lv_event_t * e);
|
||||
static void screen_create_on_trigger_event_cb(lv_event_t * e);
|
||||
static void screen_load_on_trigger_event_cb(lv_event_t * e);
|
||||
static void delete_on_screen_unloaded_event_cb(lv_event_t * e);
|
||||
static void free_screen_create_user_data_on_delete_event_cb(lv_event_t * e);
|
||||
static void play_anim_on_trigger_event_cb(lv_event_t * e);
|
||||
static void free_play_anim_user_data_on_delete_event_cb(lv_event_t * e);
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
@@ -181,7 +191,7 @@ void lv_obj_xml_style_apply(lv_xml_parser_state_t * state, const char ** attrs)
|
||||
}
|
||||
|
||||
const char * selector_str = lv_xml_get_value_of(attrs, "selector");
|
||||
lv_style_selector_t selector = get_selector(selector_str);
|
||||
lv_style_selector_t selector = lv_xml_style_selector_text_to_enum(selector_str);
|
||||
|
||||
void * item = lv_xml_state_get_parent(state);
|
||||
lv_obj_add_style(item, &xml_style->style, selector);
|
||||
@@ -210,7 +220,7 @@ void lv_obj_xml_remove_style_apply(lv_xml_parser_state_t * state, const char **
|
||||
style = &xml_style->style;
|
||||
}
|
||||
|
||||
lv_style_selector_t selector = get_selector(selector_str);
|
||||
lv_style_selector_t selector = lv_xml_style_selector_text_to_enum(selector_str);
|
||||
|
||||
void * item = lv_xml_state_get_item(state);
|
||||
lv_obj_remove_style(item, style, selector);
|
||||
@@ -437,7 +447,7 @@ void lv_obj_xml_bind_style_apply(lv_xml_parser_state_t * state, const char ** at
|
||||
int32_t ref_value = lv_xml_atoi(ref_value_str);
|
||||
|
||||
const char * selector_str = lv_xml_get_value_of(attrs, "selector");
|
||||
lv_style_selector_t selector = get_selector(selector_str);
|
||||
lv_style_selector_t selector = lv_xml_style_selector_text_to_enum(selector_str);
|
||||
|
||||
void * item = lv_xml_state_get_parent(state);
|
||||
lv_obj_bind_style(item, &xml_style->style, selector, subject, ref_value);
|
||||
@@ -647,6 +657,62 @@ void lv_obj_xml_screen_create_event_apply(lv_xml_parser_state_t * state, const c
|
||||
lv_obj_add_event_cb(item, free_screen_create_user_data_on_delete_event_cb, LV_EVENT_DELETE, dsc);
|
||||
}
|
||||
|
||||
void * lv_obj_xml_play_timeline_event_create(lv_xml_parser_state_t * state, const char ** attrs)
|
||||
{
|
||||
LV_UNUSED(attrs);
|
||||
void * item = lv_xml_state_get_parent(state);
|
||||
return item;
|
||||
}
|
||||
|
||||
void lv_obj_xml_play_timeline_event_apply(lv_xml_parser_state_t * state, const char ** attrs)
|
||||
{
|
||||
|
||||
if(state->view == NULL) {
|
||||
/*Shouldn't happen*/
|
||||
LV_LOG_WARN("view is not set, can't add the event");
|
||||
return;
|
||||
}
|
||||
|
||||
const char * target_str = lv_xml_get_value_of(attrs, "target");
|
||||
const char * delay_str = lv_xml_get_value_of(attrs, "delay");
|
||||
const char * trigger_str = lv_xml_get_value_of(attrs, "trigger");
|
||||
const char * timeline_str = lv_xml_get_value_of(attrs, "timeline");
|
||||
const char * reverse_str = lv_xml_get_value_of(attrs, "reverse");
|
||||
|
||||
if(target_str == NULL) {
|
||||
LV_LOG_WARN("`target` is missing in <lv_obj-play_animation_event>");
|
||||
return;
|
||||
}
|
||||
|
||||
if(timeline_str == NULL) {
|
||||
LV_LOG_WARN("`timeline` is missing in <lv_obj-play_animation_event>");
|
||||
return;
|
||||
}
|
||||
|
||||
if(delay_str == NULL) delay_str = "0";
|
||||
if(trigger_str == NULL) trigger_str = "clicked";
|
||||
if(reverse_str == NULL) reverse_str = "false";
|
||||
|
||||
lv_event_code_t trigger = lv_xml_trigger_text_to_enum_value(trigger_str);
|
||||
if(trigger == LV_EVENT_LAST) {
|
||||
LV_LOG_WARN("Couldn't apply <screen_load_event> because `%s` trigger is invalid.", trigger_str);
|
||||
return;
|
||||
}
|
||||
|
||||
play_anim_dsc_t * dsc = lv_malloc(sizeof(play_anim_dsc_t));
|
||||
LV_ASSERT_MALLOC(dsc);
|
||||
lv_memzero(dsc, sizeof(play_anim_dsc_t));
|
||||
dsc->target_name = lv_strdup(target_str);
|
||||
dsc->timeline_name = lv_strdup(timeline_str);
|
||||
dsc->delay = lv_xml_atoi(delay_str);
|
||||
dsc->reverse = lv_xml_to_bool(reverse_str);
|
||||
dsc->base_obj = state->view;
|
||||
|
||||
void * item = lv_xml_state_get_item(state);
|
||||
lv_obj_add_event_cb(item, play_anim_on_trigger_event_cb, trigger, dsc);
|
||||
lv_obj_add_event_cb(item, free_play_anim_user_data_on_delete_event_cb, LV_EVENT_DELETE, dsc);
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
@@ -804,6 +870,7 @@ static void apply_styles(lv_xml_parser_state_t * state, lv_obj_t * obj, const ch
|
||||
else SET_STYLE_IF(transform_pivot_x, lv_xml_atoi(value));
|
||||
else SET_STYLE_IF(transform_pivot_y, lv_xml_atoi(value));
|
||||
else SET_STYLE_IF(transform_skew_x, lv_xml_atoi(value));
|
||||
else SET_STYLE_IF(transform_skew_y, lv_xml_atoi(value));
|
||||
else SET_STYLE_IF(bitmap_mask_src, lv_xml_get_image(&state->scope, value));
|
||||
else SET_STYLE_IF(rotary_sensitivity, lv_xml_atoi(value));
|
||||
else SET_STYLE_IF(recolor, lv_xml_to_color(value));
|
||||
@@ -827,27 +894,6 @@ static void apply_styles(lv_xml_parser_state_t * state, lv_obj_t * obj, const ch
|
||||
else SET_STYLE_IF(grid_cell_y_align, lv_xml_grid_align_to_enum(value));
|
||||
}
|
||||
|
||||
static lv_style_selector_t get_selector(const char * str)
|
||||
{
|
||||
if(str == NULL) return 0;
|
||||
lv_style_selector_t selector = 0;
|
||||
char buf[256];
|
||||
lv_strncpy(buf, str, sizeof(buf));
|
||||
|
||||
char * bufp = buf;
|
||||
const char * next = lv_xml_split_str(&bufp, '|');
|
||||
|
||||
while(next) {
|
||||
/* Handle different states and parts */
|
||||
selector |= lv_xml_style_state_to_enum(next);
|
||||
selector |= lv_xml_style_part_to_enum(next);
|
||||
|
||||
/* Move to the next token */
|
||||
next = lv_xml_split_str(&bufp, '|');
|
||||
}
|
||||
|
||||
return selector;
|
||||
}
|
||||
|
||||
static void free_user_data_event_cb(lv_event_t * e)
|
||||
{
|
||||
@@ -895,4 +941,67 @@ static void free_screen_create_user_data_on_delete_event_cb(lv_event_t * e)
|
||||
lv_free(dsc);
|
||||
}
|
||||
|
||||
static void play_anim_on_trigger_event_cb(lv_event_t * e)
|
||||
{
|
||||
play_anim_dsc_t * dsc = lv_event_get_user_data(e);
|
||||
LV_ASSERT_NULL(dsc);
|
||||
|
||||
lv_obj_t * target;
|
||||
|
||||
if(lv_streq(dsc->target_name, "self")) {
|
||||
target = dsc->base_obj;
|
||||
}
|
||||
else {
|
||||
target = lv_obj_get_child_by_name(dsc->base_obj, dsc->target_name);
|
||||
}
|
||||
|
||||
if(target == NULL) {
|
||||
LV_LOG_WARN("No target widget is found with `%s` name", dsc->target_name);
|
||||
return;
|
||||
}
|
||||
|
||||
lv_anim_timeline_t * timeline = NULL;
|
||||
lv_anim_timeline_t ** timeline_array = NULL;
|
||||
lv_obj_send_event(target, lv_event_xml_store_timeline, &timeline_array);
|
||||
if(timeline_array == NULL) {
|
||||
LV_LOG_WARN("No time lines are stored in `%s`", dsc->target_name);
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t i;
|
||||
for(i = 0; timeline_array[i]; i++) {
|
||||
const char * name = lv_anim_timeline_get_user_data(timeline_array[i]);
|
||||
if(lv_streq(name, dsc->timeline_name)) {
|
||||
timeline = timeline_array[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(timeline == NULL) {
|
||||
LV_LOG_WARN("No timeline is found for `%s` with `%s` name", dsc->target_name, dsc->timeline_name);
|
||||
return;
|
||||
}
|
||||
|
||||
if(dsc->reverse) {
|
||||
lv_anim_timeline_set_reverse(timeline, true);
|
||||
lv_anim_timeline_set_progress(timeline, LV_ANIM_TIMELINE_PROGRESS_MAX);
|
||||
}
|
||||
else {
|
||||
lv_anim_timeline_set_reverse(timeline, false);
|
||||
lv_anim_timeline_set_progress(timeline, 0);
|
||||
}
|
||||
|
||||
lv_anim_timeline_set_delay(timeline, dsc->delay);
|
||||
lv_anim_timeline_start(timeline);
|
||||
|
||||
}
|
||||
|
||||
static void free_play_anim_user_data_on_delete_event_cb(lv_event_t * e)
|
||||
{
|
||||
play_anim_dsc_t * dsc = lv_event_get_user_data(e);
|
||||
lv_free((void *)dsc->target_name);
|
||||
lv_free((void *)dsc->timeline_name);
|
||||
lv_free(dsc);
|
||||
}
|
||||
|
||||
#endif /* LV_USE_XML */
|
||||
|
||||
@@ -60,6 +60,9 @@ void lv_obj_xml_screen_load_event_apply(lv_xml_parser_state_t * state, const cha
|
||||
void * lv_obj_xml_screen_create_event_create(lv_xml_parser_state_t * state, const char ** attrs);
|
||||
void lv_obj_xml_screen_create_event_apply(lv_xml_parser_state_t * state, const char ** attrs);
|
||||
|
||||
void * lv_obj_xml_play_timeline_event_create(lv_xml_parser_state_t * state, const char ** attrs);
|
||||
void lv_obj_xml_play_timeline_event_apply(lv_xml_parser_state_t * state, const char ** attrs);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
|
After Width: | Height: | Size: 2.6 KiB |
|
After Width: | Height: | Size: 2.7 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 2.7 KiB |
|
After Width: | Height: | Size: 2.6 KiB |
|
After Width: | Height: | Size: 2.6 KiB |
|
After Width: | Height: | Size: 2.6 KiB |
|
After Width: | Height: | Size: 2.7 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 2.6 KiB |
|
After Width: | Height: | Size: 3.1 KiB |
|
After Width: | Height: | Size: 3.3 KiB |
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 3.4 KiB |
|
After Width: | Height: | Size: 3.1 KiB |
|
After Width: | Height: | Size: 3.1 KiB |
|
After Width: | Height: | Size: 3.2 KiB |
|
After Width: | Height: | Size: 3.3 KiB |
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 3.2 KiB |
@@ -0,0 +1,34 @@
|
||||
<component>
|
||||
|
||||
<consts>
|
||||
<int name="delay1" value="200"/>
|
||||
<int name="delay2" value="400"/>
|
||||
<int name="duration" value="300"/>
|
||||
</consts>
|
||||
|
||||
<animations>
|
||||
<timeline name="load">
|
||||
<animation prop="translate_x" target="title" start="-30" end="0" duration="500"/>
|
||||
<animation prop="opa" target="title" start="0" end="255" duration="500"/>
|
||||
|
||||
<animation prop="translate_y" target="my_button_anim_1" start="-20" end="0" duration="#duration" delay="#delay2" early_apply="true"/>
|
||||
<animation prop="opa" target="my_button_anim_1" start="0" end="255" duration="#duration" delay="#delay2" early_apply="true"/>
|
||||
|
||||
<!-- Animate from the bottom if checked -->
|
||||
<animation prop="translate_y" selector="checked" target="my_button_anim_1" start="20" end="0" duration="#duration" delay="#delay2" early_apply="true"/>
|
||||
</timeline>
|
||||
</animations>
|
||||
|
||||
<view height="200">
|
||||
<lv_label text="List title" name="title"/>
|
||||
|
||||
<my_button_anim y="20" text="Button 1">
|
||||
<play_timeline_event trigger="clicked" target="self" timeline="load"/>
|
||||
</my_button_anim>
|
||||
|
||||
<my_button_anim y="60" text="Button 2" checkable="true">
|
||||
<play_timeline_event trigger="pressed" target="my_button_anim_1" timeline="grow"/>
|
||||
<play_timeline_event trigger="released" target="my_button_anim_1" timeline="shrink" delay="1000"/>
|
||||
</my_button_anim>
|
||||
</view>
|
||||
</component>
|
||||
@@ -0,0 +1,24 @@
|
||||
<component>
|
||||
|
||||
<animations>
|
||||
<timeline name="grow">
|
||||
<animation prop="pad_left" target="self" start="10" end="30" duration="500"/>
|
||||
<animation prop="pad_right" target="self" start="10" end="30" duration="500"/>
|
||||
<animation prop="text_letter_space" target="lv_label_0" start="0" end="5" duration="500"/>
|
||||
</timeline>
|
||||
|
||||
<timeline name="shrink">
|
||||
<animation prop="pad_left" target="self" start="30" end="10" duration="500" delay="300"/>
|
||||
<animation prop="pad_right" target="self" start="30" end="10" duration="500" delay="300"/>
|
||||
<animation prop="text_letter_space" target="lv_label_0" start="5" end="0" duration="500" delay="300"/>
|
||||
</timeline>
|
||||
</animations>
|
||||
|
||||
<api>
|
||||
<prop name="text" type="string" default="Click me" help="the text to display on the button"/>
|
||||
</api>
|
||||
|
||||
<view extends="lv_button" style_pad_hor="10">
|
||||
<lv_label text="$text"/>
|
||||
</view>
|
||||
</component>
|
||||
@@ -0,0 +1,69 @@
|
||||
#if LV_BUILD_TEST
|
||||
#include "../lvgl.h"
|
||||
|
||||
#include "unity/unity.h"
|
||||
|
||||
void setUp(void)
|
||||
{
|
||||
/* Function run before every test */
|
||||
}
|
||||
|
||||
void tearDown(void)
|
||||
{
|
||||
/* Function run after every test */
|
||||
lv_obj_clean(lv_screen_active());
|
||||
}
|
||||
|
||||
void test_xml_complex(void)
|
||||
{
|
||||
lv_xml_component_register_from_file("A:src/test_assets/xml/my_button_anim.xml");
|
||||
lv_xml_component_register_from_file("A:src/test_assets/xml/list_item_anim.xml");
|
||||
|
||||
lv_obj_t * obj = lv_xml_create(lv_screen_active(), "list_item_anim", NULL);
|
||||
|
||||
TEST_ASSERT_EQUAL_SCREENSHOT("xml/timeline_1.png");
|
||||
|
||||
lv_test_mouse_move_to_obj(lv_obj_get_child_by_name(obj, "my_button_anim_0"));
|
||||
/*Click Button 1 to trigger a load animation*/
|
||||
lv_test_mouse_click_at(45, 45);
|
||||
|
||||
lv_test_wait(200);
|
||||
TEST_ASSERT_EQUAL_SCREENSHOT("xml/timeline_2.png");
|
||||
lv_test_wait(200);
|
||||
TEST_ASSERT_EQUAL_SCREENSHOT("xml/timeline_3.png");
|
||||
lv_test_wait(500);
|
||||
TEST_ASSERT_EQUAL_SCREENSHOT("xml/timeline_1.png"); /*Loaded, initial state*/
|
||||
|
||||
/*Click Button 2 to trigger a grow/shrink animation*/
|
||||
lv_test_mouse_click_at(45, 90);
|
||||
lv_test_wait(200);
|
||||
TEST_ASSERT_EQUAL_SCREENSHOT("xml/timeline_4.png");
|
||||
lv_test_wait(300);
|
||||
TEST_ASSERT_EQUAL_SCREENSHOT("xml/timeline_5.png");
|
||||
|
||||
/*1000 delay on the play_timeline_event trigger="released" in list_item_anim.xml
|
||||
*and 300 delay in the shrink animation in my_button_anim.xml.
|
||||
*But the clock started to tick on release, so 500 ms already elapsed
|
||||
*-50ms as lv_test_mouse_click_at has 50ms delay after release.
|
||||
*Use the same image as we are just waiting for the delay*/
|
||||
lv_test_wait(1000 + 300 - 500 - 50);
|
||||
TEST_ASSERT_EQUAL_SCREENSHOT("xml/timeline_5.png");
|
||||
lv_test_wait(300);
|
||||
TEST_ASSERT_EQUAL_SCREENSHOT("xml/timeline_6.png");
|
||||
lv_test_wait(200);
|
||||
|
||||
/*Animated back to normal size, but checked*/
|
||||
TEST_ASSERT_EQUAL_SCREENSHOT("xml/timeline_7.png");
|
||||
|
||||
/*Click Button 1 to trigger a load animation,
|
||||
*but Button 2 is now checked and loaded from the bottom*/
|
||||
lv_test_mouse_click_at(45, 45);
|
||||
lv_test_wait(200);
|
||||
TEST_ASSERT_EQUAL_SCREENSHOT("xml/timeline_8.png");
|
||||
lv_test_wait(200);
|
||||
TEST_ASSERT_EQUAL_SCREENSHOT("xml/timeline_9.png");
|
||||
lv_test_wait(500);
|
||||
TEST_ASSERT_EQUAL_SCREENSHOT("xml/timeline_10.png");
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -80,6 +80,14 @@ Example
|
||||
<arg name="delay" type="int" default="0"/>
|
||||
</element>
|
||||
|
||||
<element name="play_timeline_event" access="add" type="void">
|
||||
<arg name="trigger" type="lv_event" default="clicked"/>
|
||||
<arg name="target" type="lv_obj"/>
|
||||
<arg name="timeline" type="timeline"/>
|
||||
<arg name="delay" type="int" default="0"/>
|
||||
<arg name="reverse" type="bool" default="false"/>
|
||||
</element>
|
||||
|
||||
<element name="subject_set_int_event" access="add" type="void">
|
||||
<arg name="subject" type="subject"/>
|
||||
<arg name="trigger" type="lv_event" default="clicked"/>
|
||||
|
||||