acid-drop

- Hacking the planet from a LilyGo T-Deck using custom firmware
git clone git://git.acid.vegas/acid-drop.git
Log | Files | Refs | Archive | README | LICENSE

lv_switch.c (8747B)

      1 /**
      2  * @file lv_sw.c
      3  *
      4  */
      5 
      6 /*********************
      7  *      INCLUDES
      8  *********************/
      9 #include "lv_switch.h"
     10 
     11 #if LV_USE_SWITCH != 0
     12 
     13 #include "../misc/lv_assert.h"
     14 #include "../misc/lv_math.h"
     15 #include "../misc/lv_anim.h"
     16 #include "../core/lv_indev.h"
     17 #include "../core/lv_disp.h"
     18 #include "lv_img.h"
     19 
     20 /*********************
     21  *      DEFINES
     22  *********************/
     23 #define MY_CLASS &lv_switch_class
     24 
     25 #define LV_SWITCH_IS_ANIMATING(sw) (((sw)->anim_state) != LV_SWITCH_ANIM_STATE_INV)
     26 
     27 /** Switch animation start value. (Not the real value of the switch just indicates process animation)*/
     28 #define LV_SWITCH_ANIM_STATE_START 0
     29 
     30 /** Switch animation end value.  (Not the real value of the switch just indicates process animation)*/
     31 #define LV_SWITCH_ANIM_STATE_END   256
     32 
     33 /** Mark no animation is in progress*/
     34 #define LV_SWITCH_ANIM_STATE_INV   -1
     35 
     36 /**********************
     37  *      TYPEDEFS
     38  **********************/
     39 
     40 /**********************
     41  *  STATIC PROTOTYPES
     42  **********************/
     43 static void lv_switch_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj);
     44 static void lv_switch_destructor(const lv_obj_class_t * class_p, lv_obj_t * obj);
     45 static void lv_switch_event(const lv_obj_class_t * class_p, lv_event_t * e);
     46 static void draw_main(lv_event_t * e);
     47 
     48 static void lv_switch_anim_exec_cb(void * sw, int32_t value);
     49 static void lv_switch_trigger_anim(lv_obj_t * obj);
     50 static void lv_switch_anim_ready(lv_anim_t * a);
     51 /**********************
     52  *  STATIC VARIABLES
     53  **********************/
     54 const lv_obj_class_t lv_switch_class = {
     55     .constructor_cb = lv_switch_constructor,
     56     .destructor_cb = lv_switch_destructor,
     57     .event_cb = lv_switch_event,
     58     .width_def = (4 * LV_DPI_DEF) / 10,
     59     .height_def = (4 * LV_DPI_DEF) / 17,
     60     .group_def = LV_OBJ_CLASS_GROUP_DEF_TRUE,
     61     .instance_size = sizeof(lv_switch_t),
     62     .base_class = &lv_obj_class
     63 };
     64 
     65 /**********************
     66  *      MACROS
     67  **********************/
     68 
     69 /**********************
     70  *   GLOBAL FUNCTIONS
     71  **********************/
     72 
     73 lv_obj_t * lv_switch_create(lv_obj_t * parent)
     74 {
     75     LV_LOG_INFO("begin");
     76     lv_obj_t * obj = lv_obj_class_create_obj(MY_CLASS, parent);
     77     lv_obj_class_init_obj(obj);
     78     return obj;
     79 }
     80 
     81 /**********************
     82  *   STATIC FUNCTIONS
     83  **********************/
     84 
     85 static void lv_switch_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj)
     86 {
     87     LV_UNUSED(class_p);
     88     LV_TRACE_OBJ_CREATE("begin");
     89 
     90     lv_switch_t * sw = (lv_switch_t *)obj;
     91 
     92     sw->anim_state = LV_SWITCH_ANIM_STATE_INV;
     93 
     94     lv_obj_clear_flag(obj, LV_OBJ_FLAG_SCROLLABLE);
     95     lv_obj_add_flag(obj, LV_OBJ_FLAG_CHECKABLE);
     96     lv_obj_add_flag(obj, LV_OBJ_FLAG_SCROLL_ON_FOCUS);
     97 
     98     LV_TRACE_OBJ_CREATE("finished");
     99 }
    100 
    101 static void lv_switch_destructor(const lv_obj_class_t * class_p, lv_obj_t * obj)
    102 {
    103     LV_UNUSED(class_p);
    104     lv_switch_t * sw = (lv_switch_t *)obj;
    105 
    106     lv_anim_del(sw, NULL);
    107 }
    108 
    109 static void lv_switch_event(const lv_obj_class_t * class_p, lv_event_t * e)
    110 {
    111     LV_UNUSED(class_p);
    112 
    113     lv_res_t res;
    114 
    115     /*Call the ancestor's event handler*/
    116     res = lv_obj_event_base(MY_CLASS, e);
    117     if(res != LV_RES_OK) return;
    118 
    119     lv_event_code_t code = lv_event_get_code(e);
    120     lv_obj_t * obj = lv_event_get_target(e);
    121 
    122     if(code == LV_EVENT_REFR_EXT_DRAW_SIZE) {
    123         lv_coord_t knob_left = lv_obj_get_style_pad_left(obj,   LV_PART_KNOB);
    124         lv_coord_t knob_right = lv_obj_get_style_pad_right(obj,  LV_PART_KNOB);
    125         lv_coord_t knob_top = lv_obj_get_style_pad_top(obj,    LV_PART_KNOB);
    126         lv_coord_t knob_bottom = lv_obj_get_style_pad_bottom(obj, LV_PART_KNOB);
    127 
    128         /*The smaller size is the knob diameter*/
    129         lv_coord_t knob_size = LV_MAX4(knob_left, knob_right, knob_bottom, knob_top);
    130         knob_size += _LV_SWITCH_KNOB_EXT_AREA_CORRECTION;
    131         knob_size += lv_obj_calculate_ext_draw_size(obj, LV_PART_KNOB);
    132 
    133         lv_coord_t * s = lv_event_get_param(e);
    134         *s = LV_MAX(*s, knob_size);
    135         *s = LV_MAX(*s, lv_obj_calculate_ext_draw_size(obj, LV_PART_INDICATOR));
    136     }
    137     else if(code == LV_EVENT_VALUE_CHANGED) {
    138         lv_switch_trigger_anim(obj);
    139         lv_obj_invalidate(obj);
    140     }
    141     else if(code == LV_EVENT_DRAW_MAIN) {
    142         draw_main(e);
    143     }
    144 }
    145 
    146 static void draw_main(lv_event_t * e)
    147 {
    148     lv_obj_t * obj = lv_event_get_target(e);
    149     lv_switch_t * sw = (lv_switch_t *)obj;
    150 
    151     lv_draw_ctx_t * draw_ctx = lv_event_get_draw_ctx(e);
    152 
    153     /*Calculate the indicator area*/
    154     lv_coord_t bg_left = lv_obj_get_style_pad_left(obj,     LV_PART_MAIN);
    155     lv_coord_t bg_right = lv_obj_get_style_pad_right(obj,   LV_PART_MAIN);
    156     lv_coord_t bg_top = lv_obj_get_style_pad_top(obj,       LV_PART_MAIN);
    157     lv_coord_t bg_bottom = lv_obj_get_style_pad_bottom(obj, LV_PART_MAIN);
    158 
    159     /*Draw the indicator*/
    160     /*Respect the background's padding*/
    161     lv_area_t indic_area;
    162     lv_area_copy(&indic_area, &obj->coords);
    163     indic_area.x1 += bg_left;
    164     indic_area.x2 -= bg_right;
    165     indic_area.y1 += bg_top;
    166     indic_area.y2 -= bg_bottom;
    167 
    168     lv_draw_rect_dsc_t draw_indic_dsc;
    169     lv_draw_rect_dsc_init(&draw_indic_dsc);
    170     lv_obj_init_draw_rect_dsc(obj, LV_PART_INDICATOR, &draw_indic_dsc);
    171     lv_draw_rect(draw_ctx, &draw_indic_dsc, &indic_area);
    172 
    173     /*Draw the knob*/
    174     lv_coord_t anim_value_x = 0;
    175     lv_coord_t knob_size = lv_obj_get_height(obj);
    176     lv_coord_t anim_length = lv_area_get_width(&obj->coords) - knob_size;
    177 
    178     if(LV_SWITCH_IS_ANIMATING(sw)) {
    179         /* Use the animation's coordinate */
    180         anim_value_x = (anim_length * sw->anim_state) / LV_SWITCH_ANIM_STATE_END;
    181     }
    182     else {
    183         /* Use LV_STATE_CHECKED to decide the coordinate */
    184         bool chk = lv_obj_get_state(obj) & LV_STATE_CHECKED;
    185         anim_value_x = chk ? anim_length : 0;
    186     }
    187 
    188     if(LV_BASE_DIR_RTL == lv_obj_get_style_base_dir(obj, LV_PART_MAIN)) {
    189         anim_value_x = anim_length - anim_value_x;
    190     }
    191 
    192     lv_area_t knob_area;
    193     knob_area.x1 = obj->coords.x1 + anim_value_x;
    194     knob_area.x2 = knob_area.x1 + knob_size;
    195 
    196     knob_area.y1 = obj->coords.y1;
    197     knob_area.y2 = obj->coords.y2;
    198 
    199     lv_coord_t knob_left = lv_obj_get_style_pad_left(obj, LV_PART_KNOB);
    200     lv_coord_t knob_right = lv_obj_get_style_pad_right(obj, LV_PART_KNOB);
    201     lv_coord_t knob_top = lv_obj_get_style_pad_top(obj, LV_PART_KNOB);
    202     lv_coord_t knob_bottom = lv_obj_get_style_pad_bottom(obj, LV_PART_KNOB);
    203 
    204     /*Apply the paddings on the knob area*/
    205     knob_area.x1 -= knob_left;
    206     knob_area.x2 += knob_right;
    207     knob_area.y1 -= knob_top;
    208     knob_area.y2 += knob_bottom;
    209 
    210     lv_draw_rect_dsc_t knob_rect_dsc;
    211     lv_draw_rect_dsc_init(&knob_rect_dsc);
    212     lv_obj_init_draw_rect_dsc(obj, LV_PART_KNOB, &knob_rect_dsc);
    213 
    214     lv_draw_rect(draw_ctx, &knob_rect_dsc, &knob_area);
    215 }
    216 
    217 static void lv_switch_anim_exec_cb(void * var, int32_t value)
    218 {
    219     lv_switch_t * sw = var;
    220     sw->anim_state = value;
    221     lv_obj_invalidate((lv_obj_t *)sw);
    222 }
    223 
    224 /**
    225  * Resets the switch's animation state to "no animation in progress".
    226  */
    227 static void lv_switch_anim_ready(lv_anim_t * a)
    228 {
    229     lv_switch_t * sw = a->var;
    230     sw->anim_state = LV_SWITCH_ANIM_STATE_INV;
    231     lv_obj_invalidate((lv_obj_t *)sw);
    232 }
    233 
    234 /**
    235  * Starts an animation for the switch knob. if the anim_time style property is greater than 0
    236  * @param obj the switch to animate
    237  */
    238 static void lv_switch_trigger_anim(lv_obj_t * obj)
    239 {
    240     LV_ASSERT_OBJ(obj, MY_CLASS);
    241     lv_switch_t * sw = (lv_switch_t *)obj;
    242 
    243     uint32_t anim_dur_full = lv_obj_get_style_anim_time(obj, LV_PART_MAIN);
    244 
    245     if(anim_dur_full > 0) {
    246         bool chk = lv_obj_get_state(obj) & LV_STATE_CHECKED;
    247         int32_t anim_start;
    248         int32_t anim_end;
    249         /*No animation in progress -> simply set the values*/
    250         if(sw->anim_state == LV_SWITCH_ANIM_STATE_INV) {
    251             anim_start = chk ? LV_SWITCH_ANIM_STATE_START : LV_SWITCH_ANIM_STATE_END;
    252             anim_end   = chk ? LV_SWITCH_ANIM_STATE_END : LV_SWITCH_ANIM_STATE_START;
    253         }
    254         /*Animation in progress. Start from the animation end value*/
    255         else {
    256             anim_start = sw->anim_state;
    257             anim_end   = chk ? LV_SWITCH_ANIM_STATE_END : LV_SWITCH_ANIM_STATE_START;
    258         }
    259         /*Calculate actual animation duration*/
    260         uint32_t anim_dur = (anim_dur_full * LV_ABS(anim_start - anim_end)) / LV_SWITCH_ANIM_STATE_END;
    261 
    262         /*Stop the previous animation if it exists*/
    263         lv_anim_del(sw, NULL);
    264 
    265         lv_anim_t a;
    266         lv_anim_init(&a);
    267         lv_anim_set_var(&a, sw);
    268         lv_anim_set_exec_cb(&a, lv_switch_anim_exec_cb);
    269         lv_anim_set_values(&a, anim_start, anim_end);
    270         lv_anim_set_ready_cb(&a, lv_switch_anim_ready);
    271         lv_anim_set_time(&a, anim_dur);
    272         lv_anim_start(&a);
    273     }
    274 }
    275 
    276 
    277 #endif