mirror of
https://github.com/lvgl/lvgl.git
synced 2025-01-14 06:42:58 +08:00
feat(obj): add unified obj property set/get API (#4579)
Signed-off-by: Xu Xingliang <xuxingliang@xiaomi.com>
This commit is contained in:
parent
ce6f56a742
commit
726620d0fc
@ -14,3 +14,4 @@ Others
|
||||
imgfont
|
||||
ime_pinyin
|
||||
obj_id
|
||||
obj_property
|
||||
|
74
docs/others/obj_property.rst
Normal file
74
docs/others/obj_property.rst
Normal file
@ -0,0 +1,74 @@
|
||||
===============
|
||||
Widget Property
|
||||
===============
|
||||
|
||||
Widgets have many properties that can decide what they look like and how they behave.
|
||||
For example, the size, position, color, font, etc. are properties of a widget.
|
||||
Specially, widget local style is also a property of a widget.
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
Two APIs are provided to get/set widget properties. It can be enabled by setting
|
||||
``LV_USE_OBJ_PROPERTY`` to 1 in `lv_conf.h`.
|
||||
|
||||
.. code:: c
|
||||
|
||||
typedef struct {
|
||||
lv_prop_id_t id;
|
||||
union {
|
||||
int32_t num; /**< Number integer number (opacity, enums, booleans or "normal" numbers)*/
|
||||
const void * ptr; /**< Constant pointers (font, cone text, etc)*/
|
||||
lv_color_t color; /**< Colors*/
|
||||
lv_style_value_t _style; /**< A place holder for style value which is same as property value.*/
|
||||
};
|
||||
} lv_property_t;
|
||||
|
||||
lv_result_t lv_obj_set_property(struct _lv_obj_t * obj, const lv_property_t * value);
|
||||
lv_property_t lv_obj_get_property(struct _lv_obj_t * obj, lv_prop_id_t id);
|
||||
|
||||
|
||||
Property ID
|
||||
~~~~~~~~~~~
|
||||
|
||||
``lv_prop_id_t`` identifies which property to get/set. ``lv_property_t`` is an enum value
|
||||
defined in `lv_obj_property.h` that are grouped by widget class. You can add your own
|
||||
widget property ID following same rule and using helper macro ``LV_PROPERTY_ID``.
|
||||
Do make sure the ID is unique across all widgets.
|
||||
|
||||
|
||||
Property ID is a 32-bit value. The higher 4bits indicates the property value type.
|
||||
The lower 28bits is the property ID.
|
||||
|
||||
Note that ``lv_style_prop_t`` is also valid property ID.
|
||||
|
||||
Property Value
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
Property value is a union of all possible property types including integer, pointer and color.
|
||||
``_style`` is kept their just to indicate it's compatible with ``style`` value type.
|
||||
|
||||
|
||||
A Step Further
|
||||
--------------
|
||||
The unified widget property set/get API is useful when developing wrapper layer for other
|
||||
modules like micropython, lua, or for an external animation engine.
|
||||
|
||||
For pointer type of property value, which typically points to a specific struct, it still needs
|
||||
additional code to convert values from dict, table etc to a C struct before setting to widget.
|
||||
|
||||
Another possible use case is to ease of creating UI from lots of code. For example, you can gather
|
||||
all properties to an array now and set properties with a for loop.
|
||||
|
||||
.. code:: c
|
||||
|
||||
lv_property_t props[] = {
|
||||
{ .id = LV_PROPERTY_IMAGE_SRC, .ptr = &img_demo_widgets_avatar, },
|
||||
{ .id = LV_PROPERTY_IMAGE_PIVOT, .ptr = &pivot_50, },
|
||||
{ .id = LV_PROPERTY_IMAGE_SCALE, .num = 128, },
|
||||
{ .id = LV_PROPERTY_OBJ_FLAG_CLICKABLE, .num = 1, },
|
||||
{ .id = LV_STYLE_IMAGE_OPA, .num = 128, },
|
||||
{ .id = LV_STYLE_BG_COLOR, .color = (lv_color_t){.red = 0x11, .green = 0x22, .blue = 0x33}, },
|
||||
}
|
||||
|
||||
LV_OBJ_PROPERTY_ARRAY_SET(obj, props);
|
@ -277,6 +277,9 @@
|
||||
/* Use lvgl builtin method for obj ID */
|
||||
#define LV_USE_OBJ_ID_BUILTIN 0
|
||||
|
||||
/*Use obj property set/get API*/
|
||||
#define LV_USE_OBJ_PROPERTY 0
|
||||
|
||||
/*=====================
|
||||
* COMPILER SETTINGS
|
||||
*====================*/
|
||||
|
@ -45,10 +45,28 @@ static void draw_scrollbar(lv_obj_t * obj, lv_layer_t * layer);
|
||||
static lv_result_t scrollbar_init_draw_dsc(lv_obj_t * obj, lv_draw_rect_dsc_t * dsc);
|
||||
static bool obj_valid_child(const lv_obj_t * parent, const lv_obj_t * obj_to_find);
|
||||
static void update_obj_state(lv_obj_t * obj, lv_state_t new_state);
|
||||
#if LV_USE_OBJ_PROPERTY
|
||||
static lv_result_t lv_obj_set_any(lv_obj_t *, lv_prop_id_t, const lv_property_t *);
|
||||
static lv_result_t lv_obj_get_any(const lv_obj_t *, lv_prop_id_t, lv_property_t *);
|
||||
#endif
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
#if LV_USE_OBJ_PROPERTY
|
||||
static const lv_property_ops_t properties[] = {
|
||||
{
|
||||
.id = LV_PROPERTY_OBJ_PARENT,
|
||||
.setter = lv_obj_set_parent,
|
||||
.getter = lv_obj_get_parent,
|
||||
},
|
||||
{
|
||||
.id = LV_PROPERTY_ID_ANY,
|
||||
.setter = lv_obj_set_any,
|
||||
.getter = lv_obj_get_any,
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
const lv_obj_class_t lv_obj_class = {
|
||||
.constructor_cb = lv_obj_constructor,
|
||||
@ -61,6 +79,12 @@ const lv_obj_class_t lv_obj_class = {
|
||||
.instance_size = (sizeof(lv_obj_t)),
|
||||
.base_class = NULL,
|
||||
.name = "obj",
|
||||
#if LV_USE_OBJ_PROPERTY
|
||||
.prop_index_start = LV_PROPERTY_OBJ_START,
|
||||
.prop_index_end = LV_PROPERTY_OBJ_END,
|
||||
.properties = properties,
|
||||
.properties_count = sizeof(properties) / sizeof(properties[0]),
|
||||
#endif
|
||||
};
|
||||
|
||||
/**********************
|
||||
@ -183,7 +207,6 @@ void lv_obj_remove_state(lv_obj_t * obj, lv_state_t state)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void lv_obj_set_state(lv_obj_t * obj, lv_state_t state, bool v)
|
||||
{
|
||||
if(v) lv_obj_add_state(obj, state);
|
||||
@ -784,3 +807,34 @@ static bool obj_valid_child(const lv_obj_t * parent, const lv_obj_t * obj_to_fin
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#if LV_USE_OBJ_PROPERTY
|
||||
static lv_result_t lv_obj_set_any(lv_obj_t * obj, lv_prop_id_t id, const lv_property_t * prop)
|
||||
{
|
||||
LV_ASSERT_OBJ(obj, MY_CLASS);
|
||||
|
||||
if(id >= LV_PROPERTY_OBJ_FLAG_START && id <= LV_PROPERTY_OBJ_FLAG_END) {
|
||||
lv_obj_flag_t flag = 1L << (id - LV_PROPERTY_OBJ_FLAG_START);
|
||||
if(prop->num) lv_obj_add_flag(obj, flag);
|
||||
else lv_obj_remove_flag(obj, flag);
|
||||
return LV_RESULT_OK;
|
||||
}
|
||||
else {
|
||||
return LV_RESULT_INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
static lv_result_t lv_obj_get_any(const lv_obj_t * obj, lv_prop_id_t id, lv_property_t * prop)
|
||||
{
|
||||
LV_ASSERT_OBJ(obj, MY_CLASS);
|
||||
if(id >= LV_PROPERTY_OBJ_FLAG_START && id <= LV_PROPERTY_OBJ_FLAG_END) {
|
||||
lv_obj_flag_t flag = 1L << (id - LV_PROPERTY_OBJ_FLAG_START);
|
||||
prop->id = id;
|
||||
prop->num = obj->flags & flag;
|
||||
return LV_RESULT_OK;
|
||||
}
|
||||
else {
|
||||
return LV_RESULT_INVALID;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -22,6 +22,7 @@ extern "C" {
|
||||
#include "../misc/lv_area.h"
|
||||
#include "../misc/lv_color.h"
|
||||
#include "../misc/lv_assert.h"
|
||||
#include "lv_obj_property.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
@ -92,6 +93,9 @@ typedef uint32_t lv_part_t;
|
||||
/**
|
||||
* On/Off features controlling the object's behavior.
|
||||
* OR-ed values are possible
|
||||
*
|
||||
* Note: update obj flags corresponding properties below
|
||||
* whenever add/remove flags or change bit definition of flags.
|
||||
*/
|
||||
typedef enum {
|
||||
LV_OBJ_FLAG_HIDDEN = (1L << 0), /**< Make the object hidden. (Like it wasn't there at all)*/
|
||||
@ -137,6 +141,48 @@ typedef _lv_obj_flag_t lv_obj_flag_t;
|
||||
typedef uint32_t lv_obj_flag_t;
|
||||
#endif /*DOXYGEN*/
|
||||
|
||||
#if LV_USE_OBJ_PROPERTY
|
||||
enum {
|
||||
/*OBJ flag properties */
|
||||
LV_PROPERTY_ID(OBJ, FLAG_START, LV_PROPERTY_TYPE_INT, 0),
|
||||
LV_PROPERTY_ID(OBJ, FLAG_HIDDEN, LV_PROPERTY_TYPE_INT, 0),
|
||||
LV_PROPERTY_ID(OBJ, FLAG_CLICKABLE, LV_PROPERTY_TYPE_INT, 1),
|
||||
LV_PROPERTY_ID(OBJ, FLAG_CLICK_FOCUSABLE, LV_PROPERTY_TYPE_INT, 2),
|
||||
LV_PROPERTY_ID(OBJ, FLAG_CHECKABLE, LV_PROPERTY_TYPE_INT, 3),
|
||||
LV_PROPERTY_ID(OBJ, FLAG_SCROLLABLE, LV_PROPERTY_TYPE_INT, 4),
|
||||
LV_PROPERTY_ID(OBJ, FLAG_SCROLL_ELASTIC, LV_PROPERTY_TYPE_INT, 5),
|
||||
LV_PROPERTY_ID(OBJ, FLAG_SCROLL_MOMENTUM, LV_PROPERTY_TYPE_INT, 6),
|
||||
LV_PROPERTY_ID(OBJ, FLAG_SCROLL_ONE, LV_PROPERTY_TYPE_INT, 7),
|
||||
LV_PROPERTY_ID(OBJ, FLAG_SCROLL_CHAIN_HOR, LV_PROPERTY_TYPE_INT, 8),
|
||||
LV_PROPERTY_ID(OBJ, FLAG_SCROLL_CHAIN_VER, LV_PROPERTY_TYPE_INT, 9),
|
||||
LV_PROPERTY_ID(OBJ, FLAG_SCROLL_ON_FOCUS, LV_PROPERTY_TYPE_INT, 10),
|
||||
LV_PROPERTY_ID(OBJ, FLAG_SCROLL_WITH_ARROW, LV_PROPERTY_TYPE_INT, 11),
|
||||
LV_PROPERTY_ID(OBJ, FLAG_SNAPPABLE, LV_PROPERTY_TYPE_INT, 12),
|
||||
LV_PROPERTY_ID(OBJ, FLAG_PRESS_LOCK, LV_PROPERTY_TYPE_INT, 13),
|
||||
LV_PROPERTY_ID(OBJ, FLAG_EVENT_BUBBLE, LV_PROPERTY_TYPE_INT, 14),
|
||||
LV_PROPERTY_ID(OBJ, FLAG_GESTURE_BUBBLE, LV_PROPERTY_TYPE_INT, 15),
|
||||
LV_PROPERTY_ID(OBJ, FLAG_ADV_HITTEST, LV_PROPERTY_TYPE_INT, 16),
|
||||
LV_PROPERTY_ID(OBJ, FLAG_IGNORE_LAYOUT, LV_PROPERTY_TYPE_INT, 17),
|
||||
LV_PROPERTY_ID(OBJ, FLAG_FLOATING, LV_PROPERTY_TYPE_INT, 18),
|
||||
LV_PROPERTY_ID(OBJ, FLAG_SEND_DRAW_TASK_EVENTS, LV_PROPERTY_TYPE_INT, 19),
|
||||
LV_PROPERTY_ID(OBJ, FLAG_OVERFLOW_VISIBLE, LV_PROPERTY_TYPE_INT, 20),
|
||||
LV_PROPERTY_ID(OBJ, FLAG_FLEX_IN_NEW_TRACK, LV_PROPERTY_TYPE_INT, 21),
|
||||
LV_PROPERTY_ID(OBJ, FLAG_LAYOUT_1, LV_PROPERTY_TYPE_INT, 23),
|
||||
LV_PROPERTY_ID(OBJ, FLAG_LAYOUT_2, LV_PROPERTY_TYPE_INT, 24),
|
||||
LV_PROPERTY_ID(OBJ, FLAG_WIDGET_1, LV_PROPERTY_TYPE_INT, 25),
|
||||
LV_PROPERTY_ID(OBJ, FLAG_WIDGET_2, LV_PROPERTY_TYPE_INT, 26),
|
||||
LV_PROPERTY_ID(OBJ, FLAG_USER_1, LV_PROPERTY_TYPE_INT, 27),
|
||||
LV_PROPERTY_ID(OBJ, FLAG_USER_2, LV_PROPERTY_TYPE_INT, 28),
|
||||
LV_PROPERTY_ID(OBJ, FLAG_USER_3, LV_PROPERTY_TYPE_INT, 29),
|
||||
LV_PROPERTY_ID(OBJ, FLAG_USER_4, LV_PROPERTY_TYPE_INT, 30),
|
||||
LV_PROPERTY_ID(OBJ, FLAG_END, LV_PROPERTY_TYPE_INT, 30),
|
||||
|
||||
/*OBJ normal properties*/
|
||||
LV_PROPERTY_ID(OBJ, PARENT, LV_PROPERTY_TYPE_POINTER, 31),
|
||||
|
||||
LV_PROPERTY_OBJ_END,
|
||||
};
|
||||
#endif
|
||||
|
||||
#include "lv_obj_tree.h"
|
||||
#include "lv_obj_pos.h"
|
||||
|
@ -15,6 +15,7 @@ extern "C" {
|
||||
*********************/
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "lv_obj_property.h"
|
||||
#include "../misc/lv_area.h"
|
||||
|
||||
/*********************
|
||||
@ -61,6 +62,14 @@ typedef struct _lv_obj_class_t {
|
||||
/*class_p is the class in which event is being processed.*/
|
||||
void (*event_cb)(const struct _lv_obj_class_t * class_p,
|
||||
struct _lv_event_t * e); /**< Widget type specific event function*/
|
||||
|
||||
#if LV_USE_OBJ_PROPERTY
|
||||
uint32_t prop_index_start;
|
||||
uint32_t prop_index_end;
|
||||
const lv_property_ops_t * properties;
|
||||
uint32_t properties_count;
|
||||
#endif
|
||||
|
||||
void * user_data;
|
||||
const char * name;
|
||||
lv_coord_t width_def;
|
||||
|
179
src/core/lv_obj_property.c
Normal file
179
src/core/lv_obj_property.c
Normal file
@ -0,0 +1,179 @@
|
||||
/**
|
||||
* @file lv_obj_id.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "../core/lv_obj.h"
|
||||
#include "../stdlib/lv_string.h"
|
||||
#include "lv_obj_property.h"
|
||||
|
||||
#if LV_USE_OBJ_PROPERTY
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
typedef void (*lv_property_set_int_t)(struct _lv_obj_t *, int32_t);
|
||||
typedef void (*lv_property_set_pointer_t)(struct _lv_obj_t *, const void *);
|
||||
typedef void (*lv_property_set_color_t)(struct _lv_obj_t *, lv_color_t);
|
||||
typedef lv_result_t (*lv_property_setter_t)(struct _lv_obj_t *, lv_prop_id_t, const lv_property_t *);
|
||||
|
||||
typedef int32_t (*lv_property_get_int_t)(const struct _lv_obj_t *);
|
||||
typedef void * (*lv_property_get_pointer_t)(const struct _lv_obj_t *);
|
||||
typedef lv_color_t (*lv_property_get_color_t)(const struct _lv_obj_t *);
|
||||
typedef lv_result_t (*lv_property_getter_t)(const struct _lv_obj_t *, lv_prop_id_t, lv_property_t *);
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
static lv_result_t obj_property(lv_obj_t * obj, lv_prop_id_t id, lv_property_t * value, bool set);
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
lv_result_t lv_obj_set_property(lv_obj_t * obj, const lv_property_t * value)
|
||||
{
|
||||
LV_ASSERT(obj && value);
|
||||
|
||||
if(value->id == LV_PROPERTY_ID_INVALID) {
|
||||
LV_LOG_WARN("invalid property id set to %p\n", obj);
|
||||
return LV_RESULT_INVALID;
|
||||
}
|
||||
|
||||
if(value->id < LV_PROPERTY_ID_START) {
|
||||
lv_obj_set_local_style_prop(obj, value->id, value->_style, 0);
|
||||
return LV_RESULT_OK;
|
||||
}
|
||||
|
||||
return obj_property(obj, value->id, (lv_property_t *)value, true);
|
||||
}
|
||||
|
||||
lv_result_t lv_obj_set_properties(struct _lv_obj_t * obj, const lv_property_t * value, uint32_t count)
|
||||
{
|
||||
for(uint32_t i = 0; i < count; i++) {
|
||||
lv_result_t result = lv_obj_set_property(obj, &value[i]);
|
||||
if(result != LV_RESULT_OK) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return LV_RESULT_OK;
|
||||
}
|
||||
|
||||
lv_property_t lv_obj_get_property(lv_obj_t * obj, lv_prop_id_t id)
|
||||
{
|
||||
lv_result_t result;
|
||||
lv_property_t value;
|
||||
|
||||
if(id == LV_PROPERTY_ID_INVALID) {
|
||||
LV_LOG_WARN("invalid property id to get from %p\n", obj);
|
||||
value.id = 0;
|
||||
value.num = 0;
|
||||
return value;
|
||||
}
|
||||
|
||||
if(id < LV_PROPERTY_ID_START) {
|
||||
lv_obj_get_local_style_prop(obj, id, &value._style, 0);
|
||||
value.id = id;
|
||||
return value;
|
||||
}
|
||||
|
||||
result = obj_property(obj, id, &value, false);
|
||||
if(result != LV_RESULT_OK)
|
||||
value.id = 0;
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
static lv_result_t obj_property(lv_obj_t * obj, lv_prop_id_t id, lv_property_t * value, bool set)
|
||||
{
|
||||
const lv_property_ops_t * properties;
|
||||
const lv_property_ops_t * prop;
|
||||
|
||||
const lv_obj_class_t * clz;
|
||||
uint32_t index = LV_PROPERTY_ID_INDEX(id);
|
||||
|
||||
for(clz = obj->class_p ; clz; clz = clz->base_class) {
|
||||
properties = clz->properties;
|
||||
if(properties == NULL) {
|
||||
/* try base class*/
|
||||
continue;
|
||||
}
|
||||
|
||||
if(id != LV_PROPERTY_ID_ANY && (index < clz->prop_index_start || index > clz->prop_index_end)) {
|
||||
/* try base class*/
|
||||
continue;
|
||||
}
|
||||
|
||||
/*Check if there's setter available for this class*/
|
||||
for(uint32_t i = 0; i < clz->properties_count; i++) {
|
||||
prop = &properties[i];
|
||||
|
||||
/*pass id and value directly to widget's property method*/
|
||||
if(prop->id == LV_PROPERTY_ID_ANY) {
|
||||
value->id = prop->id;
|
||||
if(set) return ((lv_property_setter_t)prop->setter)(obj, id, value);
|
||||
else return ((lv_property_getter_t)prop->getter)(obj, id, value);
|
||||
}
|
||||
|
||||
/*Not this id, check next*/
|
||||
if(prop->id != id)
|
||||
continue;
|
||||
|
||||
/*id matched but we got null pointer to functions*/
|
||||
if(set ? prop->setter == NULL : prop->getter == NULL) {
|
||||
LV_LOG_WARN("null %s provided, id: %d\n", set ? "setter" : "getter", id);
|
||||
return LV_RESULT_INVALID;
|
||||
}
|
||||
|
||||
/*Update value id if it's a read*/
|
||||
if(!set) value->id = prop->id;
|
||||
|
||||
switch(LV_PROPERTY_ID_TYPE(prop->id)) {
|
||||
case LV_PROPERTY_TYPE_INT:
|
||||
if(set)((lv_property_set_int_t)(prop->setter))(obj, value->num);
|
||||
else value->num = ((lv_property_get_int_t)(prop->getter))(obj);
|
||||
break;
|
||||
case LV_PROPERTY_TYPE_POINTER:
|
||||
case LV_PROPERTY_TYPE_IMGSRC:
|
||||
if(set)((lv_property_set_pointer_t)(prop->setter))(obj, value->ptr);
|
||||
else value->ptr = ((lv_property_get_pointer_t)(prop->getter))(obj);
|
||||
break;
|
||||
case LV_PROPERTY_TYPE_COLOR:
|
||||
if(set)((lv_property_set_color_t)prop->setter)(obj, value->color);
|
||||
else value->color = ((lv_property_get_color_t)(prop->getter))(obj);
|
||||
break;
|
||||
default:
|
||||
LV_LOG_WARN("unknown property id: 0x%08x\n", prop->id);
|
||||
return LV_RESULT_INVALID;
|
||||
break;
|
||||
}
|
||||
|
||||
return LV_RESULT_OK;
|
||||
}
|
||||
|
||||
/*If no setter found, try base class then*/
|
||||
}
|
||||
|
||||
LV_LOG_WARN("unknown property id: 0x%08x\n", id);
|
||||
return LV_RESULT_INVALID;
|
||||
}
|
||||
|
||||
#endif /*LV_USE_OBJ_PROPERTY*/
|
128
src/core/lv_obj_property.h
Normal file
128
src/core/lv_obj_property.h
Normal file
@ -0,0 +1,128 @@
|
||||
/**
|
||||
* @file lv_obj_property.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_OBJ_PROPERTY_H
|
||||
#define LV_OBJ_PROPERTY_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "../misc/lv_types.h"
|
||||
#include "../misc/lv_style.h"
|
||||
|
||||
#if LV_USE_OBJ_PROPERTY
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/*All possible property value types*/
|
||||
#define LV_PROPERTY_TYPE_INVALID 0 /*Use default 0 as invalid to detect program outliers*/
|
||||
#define LV_PROPERTY_TYPE_INT 1 /*int32_t type*/
|
||||
#define LV_PROPERTY_TYPE_COLOR 2 /*ARGB8888 type*/
|
||||
#define LV_PROPERTY_TYPE_POINTER 3 /*void * pointer*/
|
||||
#define LV_PROPERTY_TYPE_IMGSRC 4 /*Special pointer for image*/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
struct _lv_obj_t;
|
||||
|
||||
#define LV_PROPERTY_ID(clz, name, type, index) LV_PROPERTY_## clz ##_##name = (LV_PROPERTY_## clz ##_START + (index)) | ((type) << 28)
|
||||
|
||||
#define LV_PROPERTY_ID_TYPE(id) ((id) >> 28)
|
||||
#define LV_PROPERTY_ID_INDEX(id) ((id) & 0xfffffff)
|
||||
|
||||
/*Set properties from an array of lv_property_t*/
|
||||
#define LV_OBJ_PROPERTY_ARRAY_SET(obj, array) lv_obj_set_properties(obj, array, sizeof(array)/sizeof(array[0]))
|
||||
|
||||
/**
|
||||
* Group of predefined widget ID start value.
|
||||
*/
|
||||
enum {
|
||||
LV_PROPERTY_ID_INVALID = 0,
|
||||
|
||||
/*ID 0 to 0xff are style ID, check lv_style_prop_t*/
|
||||
LV_PROPERTY_ID_START = 0x100, /*ID little than 0xff is style ID*/
|
||||
|
||||
/* lv_obj.c */
|
||||
LV_PROPERTY_OBJ_START = 1000,
|
||||
|
||||
/* lv_image.c */
|
||||
LV_PROPERTY_IMAGE_START = 1100,
|
||||
|
||||
/*Special ID*/
|
||||
LV_PROPERTY_ID_BUILTIN_LAST, /*Use it to extend ID and make sure it's unique and compile time determinant*/
|
||||
|
||||
LV_PROPERTY_ID_ANY = 0x7ffffffe, /*Special ID used by lvgl to intercept all setter/getter call.*/
|
||||
};
|
||||
|
||||
typedef uint32_t lv_prop_id_t;
|
||||
|
||||
typedef struct {
|
||||
lv_prop_id_t id;
|
||||
union {
|
||||
int32_t num; /**< Number integer number (opacity, enums, booleans or "normal" numbers)*/
|
||||
const void * ptr; /**< Constant pointers (font, cone text, etc)*/
|
||||
lv_color_t color; /**< Colors*/
|
||||
lv_style_value_t _style; /**< A place holder for style value which is same as property value.*/
|
||||
};
|
||||
} lv_property_t;
|
||||
|
||||
typedef struct {
|
||||
lv_prop_id_t id;
|
||||
|
||||
void * setter;
|
||||
void * getter;
|
||||
} lv_property_ops_t;
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/*=====================
|
||||
* Setter functions
|
||||
*====================*/
|
||||
|
||||
/**
|
||||
* Set widget property value.
|
||||
* @param obj pointer to an object
|
||||
* @param id ID of which property
|
||||
* @param value The property value to set
|
||||
* @return return LV_RESULT_OK if success
|
||||
*/
|
||||
lv_result_t lv_obj_set_property(struct _lv_obj_t * obj, const lv_property_t * value);
|
||||
|
||||
lv_result_t lv_obj_set_properties(struct _lv_obj_t * obj, const lv_property_t * value, uint32_t count);
|
||||
|
||||
/*=====================
|
||||
* Getter functions
|
||||
*====================*/
|
||||
|
||||
/**
|
||||
* Read property value from object
|
||||
* @param obj pointer to an object
|
||||
* @param id ID of which property
|
||||
* @param value pointer to a buffer to store the value
|
||||
* @return ? to be discussed, LV_RESULT_OK or LV_RESULT_INVALID
|
||||
*/
|
||||
lv_property_t lv_obj_get_property(struct _lv_obj_t * obj, lv_prop_id_t id);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#endif /*LV_USE_OBJ_PROPERTY*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_OBJ_PROPERTY_H*/
|
@ -767,6 +767,15 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*Use obj property set/get API*/
|
||||
#ifndef LV_USE_OBJ_PROPERTY
|
||||
#ifdef CONFIG_LV_USE_OBJ_PROPERTY
|
||||
#define LV_USE_OBJ_PROPERTY CONFIG_LV_USE_OBJ_PROPERTY
|
||||
#else
|
||||
#define LV_USE_OBJ_PROPERTY 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*=====================
|
||||
* COMPILER SETTINGS
|
||||
*====================*/
|
||||
|
@ -28,6 +28,51 @@ static void lv_image_destructor(const lv_obj_class_t * class_p, lv_obj_t * obj);
|
||||
static void lv_image_event(const lv_obj_class_t * class_p, lv_event_t * e);
|
||||
static void draw_image(lv_event_t * e);
|
||||
|
||||
#if LV_USE_OBJ_PROPERTY
|
||||
static const lv_property_ops_t properties[] = {
|
||||
{
|
||||
.id = LV_PROPERTY_IMAGE_SRC,
|
||||
.setter = lv_image_set_src,
|
||||
.getter = lv_image_get_src,
|
||||
},
|
||||
{
|
||||
.id = LV_PROPERTY_IMAGE_OFFSET_X,
|
||||
.setter = lv_image_set_offset_x,
|
||||
.getter = lv_image_get_offset_x,
|
||||
},
|
||||
{
|
||||
.id = LV_PROPERTY_IMAGE_OFFSET_Y,
|
||||
.setter = lv_image_set_offset_y,
|
||||
.getter = lv_image_get_offset_y,
|
||||
},
|
||||
{
|
||||
.id = LV_PROPERTY_IMAGE_ROTATION,
|
||||
.setter = lv_image_set_rotation,
|
||||
.getter = lv_image_get_rotation,
|
||||
},
|
||||
{
|
||||
.id = LV_PROPERTY_IMAGE_PIVOT,
|
||||
.setter = _lv_image_set_pivot,
|
||||
.getter = lv_image_get_pivot,
|
||||
},
|
||||
{
|
||||
.id = LV_PROPERTY_IMAGE_SCALE,
|
||||
.setter = lv_image_set_scale,
|
||||
.getter = lv_image_get_scale,
|
||||
},
|
||||
{
|
||||
.id = LV_PROPERTY_IMAGE_ANTIALIAS,
|
||||
.setter = lv_image_set_antialias,
|
||||
.getter = lv_image_get_antialias,
|
||||
},
|
||||
{
|
||||
.id = LV_PROPERTY_IMAGE_SIZE_MODE,
|
||||
.setter = lv_image_set_size_mode,
|
||||
.getter = lv_image_get_size_mode,
|
||||
},
|
||||
};
|
||||
#endif
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
@ -40,6 +85,12 @@ const lv_obj_class_t lv_image_class = {
|
||||
.instance_size = sizeof(lv_image_t),
|
||||
.base_class = &lv_obj_class,
|
||||
.name = "image",
|
||||
#if LV_USE_OBJ_PROPERTY
|
||||
.prop_index_start = LV_PROPERTY_IMAGE_START,
|
||||
.prop_index_end = LV_PROPERTY_IMAGE_END,
|
||||
.properties = properties,
|
||||
.properties_count = sizeof(properties) / sizeof(properties[0]),
|
||||
#endif
|
||||
};
|
||||
|
||||
/**********************
|
||||
|
@ -75,6 +75,20 @@ typedef _lv_image_size_mode_t lv_image_size_mode_t;
|
||||
typedef uint8_t lv_image_size_mode_t;
|
||||
#endif /*DOXYGEN*/
|
||||
|
||||
#if LV_USE_OBJ_PROPERTY
|
||||
enum {
|
||||
LV_PROPERTY_ID(IMAGE, SRC, LV_PROPERTY_TYPE_POINTER, 0),
|
||||
LV_PROPERTY_ID(IMAGE, OFFSET_X, LV_PROPERTY_TYPE_INT, 1),
|
||||
LV_PROPERTY_ID(IMAGE, OFFSET_Y, LV_PROPERTY_TYPE_INT, 2),
|
||||
LV_PROPERTY_ID(IMAGE, ROTATION, LV_PROPERTY_TYPE_INT, 3),
|
||||
LV_PROPERTY_ID(IMAGE, PIVOT, LV_PROPERTY_TYPE_POINTER, 4),
|
||||
LV_PROPERTY_ID(IMAGE, SCALE, LV_PROPERTY_TYPE_INT, 5),
|
||||
LV_PROPERTY_ID(IMAGE, ANTIALIAS, LV_PROPERTY_TYPE_INT, 6),
|
||||
LV_PROPERTY_ID(IMAGE, SIZE_MODE, LV_PROPERTY_TYPE_INT, 7),
|
||||
LV_PROPERTY_IMAGE_END,
|
||||
};
|
||||
#endif
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
@ -134,6 +148,14 @@ void lv_image_set_rotation(lv_obj_t * obj, int32_t angle);
|
||||
*/
|
||||
void lv_image_set_pivot(lv_obj_t * obj, lv_coord_t x, lv_coord_t y);
|
||||
|
||||
/**
|
||||
* Set pivot similar to get_pivot
|
||||
*/
|
||||
static inline void _lv_image_set_pivot(lv_obj_t * obj, lv_point_t * pivot)
|
||||
{
|
||||
lv_image_set_pivot(obj, pivot->x, pivot->y);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the zoom factor of the image.
|
||||
|
@ -97,7 +97,7 @@ set(COMPILE_OPTIONS
|
||||
-Wmissing-prototypes
|
||||
-Wpointer-arith
|
||||
-Wmultichar
|
||||
-Wpedantic
|
||||
-Wno-pedantic # ignored for now, we convert functions to pointers for propertis table.
|
||||
-Wreturn-type
|
||||
-Wshadow
|
||||
-Wshift-negative-value
|
||||
|
@ -89,3 +89,4 @@
|
||||
|
||||
#define LV_USE_OBJ_ID 1
|
||||
#define LV_USE_OBJ_ID_BUILTIN 1
|
||||
#define LV_USE_OBJ_PROPERTY 1
|
||||
|
157
tests/src/test_cases/test_obj_property.c
Normal file
157
tests/src/test_cases/test_obj_property.c
Normal file
@ -0,0 +1,157 @@
|
||||
#if LV_BUILD_TEST
|
||||
#include "../lvgl.h"
|
||||
|
||||
#include "unity/unity.h"
|
||||
|
||||
void test_obj_property_fail_on_invalid_id(void)
|
||||
{
|
||||
lv_obj_t * obj = lv_obj_create(lv_scr_act());
|
||||
lv_property_t prop = { };
|
||||
|
||||
prop.id = LV_PROPERTY_ID_INVALID;
|
||||
TEST_ASSERT_EQUAL_INT(LV_RESULT_INVALID, lv_obj_set_property(obj, &prop));
|
||||
|
||||
prop.id = LV_PROPERTY_ID_BUILTIN_LAST; /* No widget use this ID */
|
||||
TEST_ASSERT_EQUAL_INT(LV_RESULT_INVALID, lv_obj_set_property(obj, &prop));
|
||||
|
||||
prop.id = LV_PROPERTY_OBJ_PARENT + 1; /* Not a valid ID for obj */
|
||||
TEST_ASSERT_EQUAL_INT(LV_RESULT_INVALID, lv_obj_set_property(obj, &prop));
|
||||
|
||||
prop.id = LV_PROPERTY_IMAGE_OFFSET_X; /* Not an ID for obj but for image */
|
||||
TEST_ASSERT_EQUAL_INT(LV_RESULT_INVALID, lv_obj_set_property(obj, &prop));
|
||||
|
||||
prop.id = LV_PROPERTY_OBJ_PARENT; /* Valid ID */
|
||||
prop.ptr = lv_scr_act();
|
||||
TEST_ASSERT_EQUAL_INT(LV_RESULT_OK, lv_obj_set_property(obj, &prop));
|
||||
}
|
||||
|
||||
void test_obj_property_set_get_should_match(void)
|
||||
{
|
||||
lv_obj_t * obj = lv_obj_create(lv_scr_act());
|
||||
lv_obj_t * root = lv_obj_create(lv_scr_act());
|
||||
lv_property_t prop = { };
|
||||
lv_color_t color = {.red = 0x11, .green = 0x22, .blue = 0x33};
|
||||
|
||||
/* Style property should work */
|
||||
/* int type */
|
||||
prop.id = LV_STYLE_X;
|
||||
prop.num = 0xaabb;
|
||||
TEST_ASSERT_TRUE(lv_obj_set_property(obj, &prop) == LV_RESULT_OK);
|
||||
TEST_ASSERT_EQUAL_UINT32(0xaabb, lv_obj_get_style_x(obj, 0));
|
||||
TEST_ASSERT_EQUAL_UINT32(0xaabb, lv_obj_get_property(obj, LV_STYLE_X).num);
|
||||
|
||||
/* color type */
|
||||
prop.id = LV_STYLE_BG_COLOR;
|
||||
prop.color = color;
|
||||
TEST_ASSERT_TRUE(lv_obj_set_property(obj, &prop) == LV_RESULT_OK);
|
||||
TEST_ASSERT_EQUAL_COLOR(color, lv_obj_get_style_bg_color(obj, LV_PART_MAIN));
|
||||
TEST_ASSERT_EQUAL_COLOR(color, lv_obj_get_property(obj, LV_STYLE_BG_COLOR).color);
|
||||
|
||||
/* pointer type */
|
||||
prop.id = LV_STYLE_TEXT_FONT;
|
||||
prop.ptr = &lv_font_montserrat_26;
|
||||
TEST_ASSERT_TRUE(lv_obj_set_property(obj, &prop) == LV_RESULT_OK);
|
||||
TEST_ASSERT_EQUAL_PTR(&lv_font_montserrat_26, lv_obj_get_style_text_font(obj, LV_PART_MAIN));
|
||||
TEST_ASSERT_EQUAL_PTR(&lv_font_montserrat_26, lv_obj_get_property(obj, LV_STYLE_TEXT_FONT).ptr);
|
||||
|
||||
/* Object flags */
|
||||
prop.id = LV_PROPERTY_OBJ_FLAG_HIDDEN ;
|
||||
prop.num = 1;
|
||||
TEST_ASSERT_TRUE(lv_obj_set_property(obj, &prop) == LV_RESULT_OK);
|
||||
TEST_ASSERT_TRUE(lv_obj_has_flag(obj, LV_OBJ_FLAG_HIDDEN));
|
||||
TEST_ASSERT_TRUE(lv_obj_get_property(obj, LV_PROPERTY_OBJ_FLAG_HIDDEN).num);
|
||||
|
||||
prop.id = LV_PROPERTY_OBJ_FLAG_CLICKABLE;
|
||||
prop.num = 0;
|
||||
TEST_ASSERT_TRUE(lv_obj_set_property(obj, &prop) == LV_RESULT_OK);
|
||||
TEST_ASSERT_FALSE(lv_obj_has_flag(obj, LV_OBJ_FLAG_CLICKABLE));
|
||||
TEST_ASSERT_FALSE(lv_obj_get_property(obj, LV_PROPERTY_OBJ_FLAG_CLICKABLE).num);
|
||||
|
||||
/* Obj property */
|
||||
prop.id = LV_PROPERTY_OBJ_PARENT;
|
||||
prop.ptr = root;
|
||||
TEST_ASSERT_TRUE(lv_obj_set_property(obj, &prop) == LV_RESULT_OK);
|
||||
TEST_ASSERT_EQUAL_PTR(root, lv_obj_get_parent(obj));
|
||||
TEST_ASSERT_EQUAL_PTR(root, lv_obj_get_property(obj, LV_PROPERTY_OBJ_PARENT).ptr);
|
||||
|
||||
/* Derived widget could use same property */
|
||||
lv_obj_t * img = lv_image_create(obj);
|
||||
prop.id = LV_PROPERTY_OBJ_PARENT;
|
||||
prop.ptr = root;
|
||||
TEST_ASSERT_TRUE(lv_obj_set_property(img, &prop) == LV_RESULT_OK);
|
||||
TEST_ASSERT_EQUAL_PTR(root, lv_obj_get_parent(img));
|
||||
TEST_ASSERT_EQUAL_PTR(root, lv_obj_get_property(img, LV_PROPERTY_OBJ_PARENT).ptr);
|
||||
|
||||
/* Image properties */
|
||||
prop.id = LV_PROPERTY_IMAGE_OFFSET_X;
|
||||
prop.num = 0x1234;
|
||||
TEST_ASSERT_TRUE(lv_obj_set_property(img, &prop) == LV_RESULT_OK);
|
||||
TEST_ASSERT_EQUAL_UINT16(0x1234, lv_img_get_offset_x(img));
|
||||
TEST_ASSERT_EQUAL_UINT16(0x1234, lv_obj_get_property(img, LV_PROPERTY_IMAGE_OFFSET_X).num);
|
||||
}
|
||||
|
||||
void test_obj_property_flag(void)
|
||||
{
|
||||
const struct {
|
||||
uint32_t flag;
|
||||
uint32_t id;
|
||||
} properties[] = {
|
||||
{ LV_OBJ_FLAG_HIDDEN, LV_PROPERTY_OBJ_FLAG_HIDDEN },
|
||||
{ LV_OBJ_FLAG_CLICKABLE, LV_PROPERTY_OBJ_FLAG_CLICKABLE },
|
||||
{ LV_OBJ_FLAG_CLICK_FOCUSABLE, LV_PROPERTY_OBJ_FLAG_CLICK_FOCUSABLE },
|
||||
{ LV_OBJ_FLAG_CHECKABLE, LV_PROPERTY_OBJ_FLAG_CHECKABLE },
|
||||
{ LV_OBJ_FLAG_SCROLLABLE, LV_PROPERTY_OBJ_FLAG_SCROLLABLE },
|
||||
{ LV_OBJ_FLAG_SCROLL_ELASTIC, LV_PROPERTY_OBJ_FLAG_SCROLL_ELASTIC },
|
||||
{ LV_OBJ_FLAG_SCROLL_MOMENTUM, LV_PROPERTY_OBJ_FLAG_SCROLL_MOMENTUM },
|
||||
{ LV_OBJ_FLAG_SCROLL_ONE, LV_PROPERTY_OBJ_FLAG_SCROLL_ONE },
|
||||
{ LV_OBJ_FLAG_SCROLL_CHAIN_HOR, LV_PROPERTY_OBJ_FLAG_SCROLL_CHAIN_HOR },
|
||||
{ LV_OBJ_FLAG_SCROLL_CHAIN_VER, LV_PROPERTY_OBJ_FLAG_SCROLL_CHAIN_VER },
|
||||
{ LV_OBJ_FLAG_SCROLL_ON_FOCUS, LV_PROPERTY_OBJ_FLAG_SCROLL_ON_FOCUS },
|
||||
{ LV_OBJ_FLAG_SCROLL_WITH_ARROW, LV_PROPERTY_OBJ_FLAG_SCROLL_WITH_ARROW },
|
||||
{ LV_OBJ_FLAG_SNAPPABLE, LV_PROPERTY_OBJ_FLAG_SNAPPABLE },
|
||||
{ LV_OBJ_FLAG_PRESS_LOCK, LV_PROPERTY_OBJ_FLAG_PRESS_LOCK },
|
||||
{ LV_OBJ_FLAG_EVENT_BUBBLE, LV_PROPERTY_OBJ_FLAG_EVENT_BUBBLE },
|
||||
{ LV_OBJ_FLAG_GESTURE_BUBBLE, LV_PROPERTY_OBJ_FLAG_GESTURE_BUBBLE },
|
||||
{ LV_OBJ_FLAG_ADV_HITTEST, LV_PROPERTY_OBJ_FLAG_ADV_HITTEST },
|
||||
{ LV_OBJ_FLAG_IGNORE_LAYOUT, LV_PROPERTY_OBJ_FLAG_IGNORE_LAYOUT },
|
||||
{ LV_OBJ_FLAG_FLOATING, LV_PROPERTY_OBJ_FLAG_FLOATING },
|
||||
{ LV_OBJ_FLAG_SEND_DRAW_TASK_EVENTS, LV_PROPERTY_OBJ_FLAG_SEND_DRAW_TASK_EVENTS },
|
||||
{ LV_OBJ_FLAG_OVERFLOW_VISIBLE, LV_PROPERTY_OBJ_FLAG_OVERFLOW_VISIBLE },
|
||||
{ LV_OBJ_FLAG_FLEX_IN_NEW_TRACK, LV_PROPERTY_OBJ_FLAG_FLEX_IN_NEW_TRACK },
|
||||
{ LV_OBJ_FLAG_LAYOUT_1, LV_PROPERTY_OBJ_FLAG_LAYOUT_1 },
|
||||
{ LV_OBJ_FLAG_LAYOUT_2, LV_PROPERTY_OBJ_FLAG_LAYOUT_2 },
|
||||
{ LV_OBJ_FLAG_WIDGET_1, LV_PROPERTY_OBJ_FLAG_WIDGET_1 },
|
||||
{ LV_OBJ_FLAG_WIDGET_2, LV_PROPERTY_OBJ_FLAG_WIDGET_2 },
|
||||
{ LV_OBJ_FLAG_USER_1, LV_PROPERTY_OBJ_FLAG_USER_1 },
|
||||
{ LV_OBJ_FLAG_USER_2, LV_PROPERTY_OBJ_FLAG_USER_2 },
|
||||
{ LV_OBJ_FLAG_USER_3, LV_PROPERTY_OBJ_FLAG_USER_3 },
|
||||
{ LV_OBJ_FLAG_USER_4, LV_PROPERTY_OBJ_FLAG_USER_4 },
|
||||
};
|
||||
|
||||
lv_obj_t * obj = lv_obj_create(lv_scr_act());
|
||||
obj->flags = 0;
|
||||
for(unsigned long i = 0; i < sizeof(properties) / sizeof(properties[0]); i++) {
|
||||
|
||||
TEST_ASSERT_FALSE(lv_obj_get_property(obj, properties[i].id).num);
|
||||
lv_obj_add_flag(obj, properties[i].flag);
|
||||
TEST_ASSERT_TRUE(lv_obj_get_property(obj, properties[i].id).num);
|
||||
|
||||
lv_obj_remove_flag(obj, properties[i].flag);
|
||||
TEST_ASSERT_FALSE(lv_obj_get_property(obj, properties[i].id).num);
|
||||
|
||||
lv_property_t prop = { };
|
||||
prop.id = properties[i].id;
|
||||
prop.num = 1;
|
||||
TEST_ASSERT_TRUE(lv_obj_set_property(obj, &prop) == LV_RESULT_OK);
|
||||
TEST_ASSERT_TRUE(lv_obj_get_property(obj, properties[i].id).num);
|
||||
TEST_ASSERT_TRUE(lv_obj_has_flag(obj, properties[i].flag));
|
||||
|
||||
prop.id = properties[i].id;
|
||||
prop.num = 0;
|
||||
TEST_ASSERT_TRUE(lv_obj_set_property(obj, &prop) == LV_RESULT_OK);
|
||||
TEST_ASSERT_FALSE(lv_obj_get_property(obj, properties[i].id).num);
|
||||
TEST_ASSERT_FALSE(lv_obj_has_flag(obj, properties[i].flag));
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
Loading…
x
Reference in New Issue
Block a user