summaryrefslogtreecommitdiff
path: root/lib/lvgl/src/widgets/switch
diff options
context:
space:
mode:
authorjacqueline <me@jacqueline.id.au>2024-06-12 17:54:40 +1000
committerjacqueline <me@jacqueline.id.au>2024-06-12 17:54:40 +1000
commit64bd9053a25297f7a442ca831c7da5b44bd33f84 (patch)
treea90c6cad25a12028302ab1a5334510fba0229bae /lib/lvgl/src/widgets/switch
parent611176ed667c4ed7ee9f609e958f9404f4aee91d (diff)
downloadtangara-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.c264
-rw-r--r--lib/lvgl/src/widgets/switch/lv_switch.h61
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*/