1
0
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:
Neo Xu 2023-10-26 15:39:30 +08:00 committed by GitHub
parent ce6f56a742
commit 726620d0fc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 736 additions and 2 deletions

View File

@ -14,3 +14,4 @@ Others
imgfont
ime_pinyin
obj_id
obj_property

View 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);

View File

@ -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
*====================*/

View File

@ -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

View File

@ -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"

View File

@ -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
View 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
View 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*/

View File

@ -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
*====================*/

View File

@ -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
};
/**********************

View File

@ -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.

View File

@ -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

View File

@ -89,3 +89,4 @@
#define LV_USE_OBJ_ID 1
#define LV_USE_OBJ_ID_BUILTIN 1
#define LV_USE_OBJ_PROPERTY 1

View 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