diff options
| author | jacqueline <me@jacqueline.id.au> | 2024-06-12 17:54:40 +1000 |
|---|---|---|
| committer | jacqueline <me@jacqueline.id.au> | 2024-06-12 17:54:40 +1000 |
| commit | 64bd9053a25297f7a442ca831c7da5b44bd33f84 (patch) | |
| tree | a90c6cad25a12028302ab1a5334510fba0229bae /lib/lvgl/src/widgets/switch | |
| parent | 611176ed667c4ed7ee9f609e958f9404f4aee91d (diff) | |
| download | tangara-fw-64bd9053a25297f7a442ca831c7da5b44bd33f84.tar.gz | |
Update LVGL to v9.1.0
Diffstat (limited to 'lib/lvgl/src/widgets/switch')
| -rw-r--r-- | lib/lvgl/src/widgets/switch/lv_switch.c | 264 | ||||
| -rw-r--r-- | lib/lvgl/src/widgets/switch/lv_switch.h | 61 |
2 files changed, 325 insertions, 0 deletions
diff --git a/lib/lvgl/src/widgets/switch/lv_switch.c b/lib/lvgl/src/widgets/switch/lv_switch.c new file mode 100644 index 00000000..f1973e9c --- /dev/null +++ b/lib/lvgl/src/widgets/switch/lv_switch.c @@ -0,0 +1,264 @@ +/** + * @file lv_sw.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_switch.h" + +#if LV_USE_SWITCH != 0 + +#include "../../misc/lv_assert.h" +#include "../../misc/lv_math.h" +#include "../../misc/lv_anim.h" +#include "../../indev/lv_indev.h" +#include "../../display/lv_display.h" + +/********************* + * DEFINES + *********************/ +#define MY_CLASS (&lv_switch_class) + +#define LV_SWITCH_IS_ANIMATING(sw) (((sw)->anim_state) != LV_SWITCH_ANIM_STATE_INV) + +/** Switch animation start value. (Not the real value of the switch just indicates process animation)*/ +#define LV_SWITCH_ANIM_STATE_START 0 + +/** Switch animation end value. (Not the real value of the switch just indicates process animation)*/ +#define LV_SWITCH_ANIM_STATE_END 256 + +/** Mark no animation is in progress*/ +#define LV_SWITCH_ANIM_STATE_INV -1 + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +static void lv_switch_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj); +static void lv_switch_destructor(const lv_obj_class_t * class_p, lv_obj_t * obj); +static void lv_switch_event(const lv_obj_class_t * class_p, lv_event_t * e); +static void draw_main(lv_event_t * e); + +static void lv_switch_anim_exec_cb(void * sw, int32_t value); +static void lv_switch_trigger_anim(lv_obj_t * obj); +static void lv_switch_anim_completed(lv_anim_t * a); +/********************** + * STATIC VARIABLES + **********************/ +const lv_obj_class_t lv_switch_class = { + .constructor_cb = lv_switch_constructor, + .destructor_cb = lv_switch_destructor, + .event_cb = lv_switch_event, + .width_def = (4 * LV_DPI_DEF) / 10, + .height_def = (4 * LV_DPI_DEF) / 17, + .group_def = LV_OBJ_CLASS_GROUP_DEF_TRUE, + .instance_size = sizeof(lv_switch_t), + .base_class = &lv_obj_class, + .name = "switch", +}; + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +lv_obj_t * lv_switch_create(lv_obj_t * parent) +{ + LV_LOG_INFO("begin"); + lv_obj_t * obj = lv_obj_class_create_obj(MY_CLASS, parent); + lv_obj_class_init_obj(obj); + return obj; +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +static void lv_switch_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj) +{ + LV_UNUSED(class_p); + LV_TRACE_OBJ_CREATE("begin"); + + lv_switch_t * sw = (lv_switch_t *)obj; + + sw->anim_state = LV_SWITCH_ANIM_STATE_INV; + + lv_obj_remove_flag(obj, LV_OBJ_FLAG_SCROLLABLE); + lv_obj_add_flag(obj, LV_OBJ_FLAG_CHECKABLE); + lv_obj_add_flag(obj, LV_OBJ_FLAG_SCROLL_ON_FOCUS); + + LV_TRACE_OBJ_CREATE("finished"); +} + +static void lv_switch_destructor(const lv_obj_class_t * class_p, lv_obj_t * obj) +{ + LV_UNUSED(class_p); + lv_switch_t * sw = (lv_switch_t *)obj; + + lv_anim_delete(sw, NULL); +} + +static void lv_switch_event(const lv_obj_class_t * class_p, lv_event_t * e) +{ + LV_UNUSED(class_p); + + lv_result_t res; + + /*Call the ancestor's event handler*/ + res = lv_obj_event_base(MY_CLASS, e); + if(res != LV_RESULT_OK) return; + + lv_event_code_t code = lv_event_get_code(e); + lv_obj_t * obj = lv_event_get_current_target(e); + + if(code == LV_EVENT_REFR_EXT_DRAW_SIZE) { + int32_t knob_left = lv_obj_get_style_pad_left(obj, LV_PART_KNOB); + int32_t knob_right = lv_obj_get_style_pad_right(obj, LV_PART_KNOB); + int32_t knob_top = lv_obj_get_style_pad_top(obj, LV_PART_KNOB); + int32_t knob_bottom = lv_obj_get_style_pad_bottom(obj, LV_PART_KNOB); + + /*The smaller size is the knob diameter*/ + int32_t knob_size = LV_MAX4(knob_left, knob_right, knob_bottom, knob_top); + knob_size += _LV_SWITCH_KNOB_EXT_AREA_CORRECTION; + knob_size += lv_obj_calculate_ext_draw_size(obj, LV_PART_KNOB); + + int32_t * s = lv_event_get_param(e); + *s = LV_MAX(*s, knob_size); + *s = LV_MAX(*s, lv_obj_calculate_ext_draw_size(obj, LV_PART_INDICATOR)); + } + else if(code == LV_EVENT_VALUE_CHANGED) { + lv_switch_trigger_anim(obj); + lv_obj_invalidate(obj); + } + else if(code == LV_EVENT_DRAW_MAIN) { + draw_main(e); + } +} + +static void draw_main(lv_event_t * e) +{ + lv_obj_t * obj = lv_event_get_current_target(e); + lv_switch_t * sw = (lv_switch_t *)obj; + + lv_layer_t * layer = lv_event_get_layer(e); + + /*Draw the indicator*/ + lv_area_t indic_area; + /*Exclude background's padding*/ + lv_obj_get_content_coords(obj, &indic_area); + + lv_draw_rect_dsc_t draw_indic_dsc; + lv_draw_rect_dsc_init(&draw_indic_dsc); + lv_obj_init_draw_rect_dsc(obj, LV_PART_INDICATOR, &draw_indic_dsc); + lv_draw_rect(layer, &draw_indic_dsc, &indic_area); + + /*Draw the knob*/ + int32_t anim_value_x = 0; + int32_t knob_size = lv_obj_get_height(obj); + int32_t anim_length = lv_area_get_width(&obj->coords) - knob_size; + + if(LV_SWITCH_IS_ANIMATING(sw)) { + /* Use the animation's coordinate */ + anim_value_x = (anim_length * sw->anim_state) / LV_SWITCH_ANIM_STATE_END; + } + else { + /* Use LV_STATE_CHECKED to decide the coordinate */ + bool chk = lv_obj_get_state(obj) & LV_STATE_CHECKED; + anim_value_x = chk ? anim_length : 0; + } + + if(LV_BASE_DIR_RTL == lv_obj_get_style_base_dir(obj, LV_PART_MAIN)) { + anim_value_x = anim_length - anim_value_x; + } + + lv_area_t knob_area; + lv_area_copy(&knob_area, &obj->coords); + knob_area.x1 += anim_value_x; + knob_area.x2 = knob_area.x1 + (knob_size > 0 ? knob_size - 1 : 0); + + int32_t knob_left = lv_obj_get_style_pad_left(obj, LV_PART_KNOB); + int32_t knob_right = lv_obj_get_style_pad_right(obj, LV_PART_KNOB); + int32_t knob_top = lv_obj_get_style_pad_top(obj, LV_PART_KNOB); + int32_t knob_bottom = lv_obj_get_style_pad_bottom(obj, LV_PART_KNOB); + + /*Apply the paddings on the knob area*/ + knob_area.x1 -= knob_left; + knob_area.x2 += knob_right; + knob_area.y1 -= knob_top; + knob_area.y2 += knob_bottom; + + lv_draw_rect_dsc_t knob_rect_dsc; + lv_draw_rect_dsc_init(&knob_rect_dsc); + lv_obj_init_draw_rect_dsc(obj, LV_PART_KNOB, &knob_rect_dsc); + + lv_draw_rect(layer, &knob_rect_dsc, &knob_area); +} + +static void lv_switch_anim_exec_cb(void * var, int32_t value) +{ + lv_switch_t * sw = var; + sw->anim_state = value; + lv_obj_invalidate((lv_obj_t *)sw); +} + +/** + * Resets the switch's animation state to "no animation in progress". + */ +static void lv_switch_anim_completed(lv_anim_t * a) +{ + lv_switch_t * sw = a->var; + sw->anim_state = LV_SWITCH_ANIM_STATE_INV; + lv_obj_invalidate((lv_obj_t *)sw); +} + +/** + * Starts an animation for the switch knob. if the anim_time style property is greater than 0 + * @param obj the switch to animate + */ +static void lv_switch_trigger_anim(lv_obj_t * obj) +{ + LV_ASSERT_OBJ(obj, MY_CLASS); + lv_switch_t * sw = (lv_switch_t *)obj; + + uint32_t anim_dur_full = lv_obj_get_style_anim_duration(obj, LV_PART_MAIN); + + if(anim_dur_full > 0) { + bool chk = lv_obj_get_state(obj) & LV_STATE_CHECKED; + int32_t anim_start; + int32_t anim_end; + /*No animation in progress -> simply set the values*/ + if(sw->anim_state == LV_SWITCH_ANIM_STATE_INV) { + anim_start = chk ? LV_SWITCH_ANIM_STATE_START : LV_SWITCH_ANIM_STATE_END; + anim_end = chk ? LV_SWITCH_ANIM_STATE_END : LV_SWITCH_ANIM_STATE_START; + } + /*Animation in progress. Start from the animation end value*/ + else { + anim_start = sw->anim_state; + anim_end = chk ? LV_SWITCH_ANIM_STATE_END : LV_SWITCH_ANIM_STATE_START; + } + /*Calculate actual animation duration*/ + uint32_t anim_dur = (anim_dur_full * LV_ABS(anim_start - anim_end)) / LV_SWITCH_ANIM_STATE_END; + + /*Stop the previous animation if it exists*/ + lv_anim_delete(sw, NULL); + + lv_anim_t a; + lv_anim_init(&a); + lv_anim_set_var(&a, sw); + lv_anim_set_exec_cb(&a, lv_switch_anim_exec_cb); + lv_anim_set_values(&a, anim_start, anim_end); + lv_anim_set_completed_cb(&a, lv_switch_anim_completed); + lv_anim_set_duration(&a, anim_dur); + lv_anim_start(&a); + } +} + +#endif diff --git a/lib/lvgl/src/widgets/switch/lv_switch.h b/lib/lvgl/src/widgets/switch/lv_switch.h new file mode 100644 index 00000000..da14450a --- /dev/null +++ b/lib/lvgl/src/widgets/switch/lv_switch.h @@ -0,0 +1,61 @@ +/** + * @file lv_switch.h + * + */ + +#ifndef LV_SWITCH_H +#define LV_SWITCH_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "../../lv_conf_internal.h" + +#if LV_USE_SWITCH != 0 + +#include "../../core/lv_obj.h" + +/********************* + * DEFINES + *********************/ + +/** Switch knob extra area correction factor */ +#define _LV_SWITCH_KNOB_EXT_AREA_CORRECTION 2 + +/********************** + * TYPEDEFS + **********************/ + +typedef struct { + lv_obj_t obj; + int32_t anim_state; +} lv_switch_t; + +LV_ATTRIBUTE_EXTERN_DATA extern const lv_obj_class_t lv_switch_class; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a switch object + * @param parent pointer to an object, it will be the parent of the new switch + * @return pointer to the created switch + */ +lv_obj_t * lv_switch_create(lv_obj_t * parent); + +/********************** + * MACROS + **********************/ + +#endif /*LV_USE_SWITCH*/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_SWITCH_H*/ |
