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_imgbtn.c (12249B)

      1 /**
      2  * @file lv_imgbtn.c
      3  *
      4  */
      5 
      6 /*********************
      7  *      INCLUDES
      8  *********************/
      9 
     10 #include "lv_imgbtn.h"
     11 
     12 #if LV_USE_IMGBTN != 0
     13 
     14 /*********************
     15  *      DEFINES
     16  *********************/
     17 #define MY_CLASS &lv_imgbtn_class
     18 
     19 /**********************
     20  *      TYPEDEFS
     21  **********************/
     22 
     23 /**********************
     24  *  STATIC PROTOTYPES
     25  **********************/
     26 static void lv_imgbtn_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj);
     27 static void draw_main(lv_event_t * e);
     28 static void lv_imgbtn_event(const lv_obj_class_t * class_p, lv_event_t * e);
     29 static void refr_img(lv_obj_t * imgbtn);
     30 static lv_imgbtn_state_t suggest_state(lv_obj_t * imgbtn, lv_imgbtn_state_t state);
     31 lv_imgbtn_state_t get_state(const lv_obj_t * imgbtn);
     32 
     33 /**********************
     34  *  STATIC VARIABLES
     35  **********************/
     36 const lv_obj_class_t lv_imgbtn_class = {
     37     .base_class = &lv_obj_class,
     38     .instance_size = sizeof(lv_imgbtn_t),
     39     .constructor_cb = lv_imgbtn_constructor,
     40     .event_cb = lv_imgbtn_event,
     41 };
     42 
     43 /**********************
     44  *      MACROS
     45  **********************/
     46 
     47 /**********************
     48  *   GLOBAL FUNCTIONS
     49  **********************/
     50 
     51 /**
     52  * Create an image button object
     53  * @param parent pointer to an object, it will be the parent of the new image button
     54  * @return pointer to the created image button
     55  */
     56 lv_obj_t * lv_imgbtn_create(lv_obj_t * parent)
     57 {
     58     LV_LOG_INFO("begin");
     59     lv_obj_t * obj = lv_obj_class_create_obj(MY_CLASS, parent);
     60     lv_obj_class_init_obj(obj);
     61     return obj;
     62 }
     63 
     64 /*=====================
     65  * Setter functions
     66  *====================*/
     67 
     68 /**
     69  * Set images for a state of the image button
     70  * @param obj pointer to an image button object
     71  * @param state for which state set the new image
     72  * @param src_left pointer to an image source for the left side of the button (a C array or path to
     73  * a file)
     74  * @param src_mid pointer to an image source for the middle of the button (ideally 1px wide) (a C
     75  * array or path to a file)
     76  * @param src_right pointer to an image source for the right side of the button (a C array or path
     77  * to a file)
     78  */
     79 void lv_imgbtn_set_src(lv_obj_t * obj, lv_imgbtn_state_t state, const void * src_left, const void * src_mid,
     80                        const void * src_right)
     81 {
     82     LV_ASSERT_OBJ(obj, MY_CLASS);
     83 
     84     lv_imgbtn_t * imgbtn = (lv_imgbtn_t *)obj;
     85 
     86     imgbtn->img_src_left[state] = src_left;
     87     imgbtn->img_src_mid[state] = src_mid;
     88     imgbtn->img_src_right[state] = src_right;
     89 
     90     refr_img(obj);
     91 }
     92 
     93 void lv_imgbtn_set_state(lv_obj_t * obj, lv_imgbtn_state_t state)
     94 {
     95     LV_ASSERT_OBJ(obj, MY_CLASS);
     96 
     97     lv_state_t obj_state = LV_STATE_DEFAULT;
     98     if(state == LV_IMGBTN_STATE_PRESSED || state == LV_IMGBTN_STATE_CHECKED_PRESSED) obj_state |= LV_STATE_PRESSED;
     99     if(state == LV_IMGBTN_STATE_DISABLED || state == LV_IMGBTN_STATE_CHECKED_DISABLED) obj_state |= LV_STATE_DISABLED;
    100     if(state == LV_IMGBTN_STATE_CHECKED_DISABLED || state == LV_IMGBTN_STATE_CHECKED_PRESSED ||
    101        state == LV_IMGBTN_STATE_CHECKED_RELEASED) {
    102         obj_state |= LV_STATE_CHECKED;
    103     }
    104 
    105     lv_obj_clear_state(obj, LV_STATE_CHECKED | LV_STATE_PRESSED | LV_STATE_DISABLED);
    106     lv_obj_add_state(obj, obj_state);
    107 
    108     refr_img(obj);
    109 }
    110 
    111 /*=====================
    112  * Getter functions
    113  *====================*/
    114 
    115 
    116 /**
    117  * Get the left image in a given state
    118  * @param obj pointer to an image button object
    119  * @param state the state where to get the image (from `lv_btn_state_t`) `
    120  * @return pointer to the left image source (a C array or path to a file)
    121  */
    122 const void * lv_imgbtn_get_src_left(lv_obj_t * obj, lv_imgbtn_state_t state)
    123 {
    124     LV_ASSERT_OBJ(obj, MY_CLASS);
    125 
    126     lv_imgbtn_t * imgbtn = (lv_imgbtn_t *)obj;
    127 
    128     return imgbtn->img_src_left[state];
    129 }
    130 
    131 /**
    132  * Get the middle image in a given state
    133  * @param obj pointer to an image button object
    134  * @param state the state where to get the image (from `lv_btn_state_t`) `
    135  * @return pointer to the middle image source (a C array or path to a file)
    136  */
    137 const void * lv_imgbtn_get_src_middle(lv_obj_t * obj, lv_imgbtn_state_t state)
    138 {
    139     LV_ASSERT_OBJ(obj, MY_CLASS);
    140     lv_imgbtn_t * imgbtn = (lv_imgbtn_t *)obj;
    141 
    142     return imgbtn->img_src_mid[state];
    143 }
    144 
    145 /**
    146  * Get the right image in a given state
    147  * @param obj pointer to an image button object
    148  * @param state the state where to get the image (from `lv_btn_state_t`) `
    149  * @return pointer to the left image source (a C array or path to a file)
    150  */
    151 const void * lv_imgbtn_get_src_right(lv_obj_t * obj, lv_imgbtn_state_t state)
    152 {
    153     LV_ASSERT_OBJ(obj, MY_CLASS);
    154     lv_imgbtn_t * imgbtn = (lv_imgbtn_t *)obj;
    155 
    156     return imgbtn->img_src_right[state];
    157 }
    158 
    159 
    160 /**********************
    161  *   STATIC FUNCTIONS
    162  **********************/
    163 
    164 static void lv_imgbtn_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj)
    165 {
    166     LV_UNUSED(class_p);
    167     lv_imgbtn_t * imgbtn = (lv_imgbtn_t *)obj;
    168     /*Initialize the allocated 'ext'*/
    169     lv_memset_00((void *)imgbtn->img_src_mid, sizeof(imgbtn->img_src_mid));
    170     lv_memset_00(imgbtn->img_src_left, sizeof(imgbtn->img_src_left));
    171     lv_memset_00(imgbtn->img_src_right, sizeof(imgbtn->img_src_right));
    172 
    173     imgbtn->act_cf = LV_IMG_CF_UNKNOWN;
    174 }
    175 
    176 
    177 static void lv_imgbtn_event(const lv_obj_class_t * class_p, lv_event_t * e)
    178 {
    179     LV_UNUSED(class_p);
    180 
    181     lv_res_t res = lv_obj_event_base(&lv_imgbtn_class, e);
    182     if(res != LV_RES_OK) return;
    183 
    184     lv_event_code_t code = lv_event_get_code(e);
    185     lv_obj_t * obj = lv_event_get_target(e);
    186     if(code == LV_EVENT_PRESSED || code == LV_EVENT_RELEASED || code == LV_EVENT_PRESS_LOST) {
    187         refr_img(obj);
    188     }
    189     else if(code == LV_EVENT_DRAW_MAIN) {
    190         draw_main(e);
    191     }
    192     else if(code == LV_EVENT_COVER_CHECK) {
    193         lv_cover_check_info_t * info = lv_event_get_param(e);
    194         if(info->res != LV_COVER_RES_MASKED) info->res = LV_COVER_RES_NOT_COVER;
    195     }
    196     else if(code == LV_EVENT_GET_SELF_SIZE) {
    197         lv_point_t * p = lv_event_get_self_size_info(e);
    198         lv_imgbtn_t * imgbtn = (lv_imgbtn_t *)obj;
    199         lv_imgbtn_state_t state  = suggest_state(obj, get_state(obj));
    200         if(imgbtn->img_src_left[state] == NULL &&
    201            imgbtn->img_src_mid[state] != NULL &&
    202            imgbtn->img_src_right[state] == NULL) {
    203             lv_img_header_t header;
    204             lv_img_decoder_get_info(imgbtn->img_src_mid[state], &header);
    205             p->x = LV_MAX(p->x, header.w);
    206         }
    207     }
    208 }
    209 
    210 static void draw_main(lv_event_t * e)
    211 {
    212     lv_obj_t * obj = lv_event_get_target(e);
    213     lv_imgbtn_t * imgbtn = (lv_imgbtn_t *)obj;
    214     lv_draw_ctx_t * draw_ctx = lv_event_get_draw_ctx(e);
    215 
    216     /*Just draw_main an image*/
    217     lv_imgbtn_state_t state  = suggest_state(obj, get_state(obj));
    218 
    219     /*Simply draw the middle src if no tiled*/
    220     const void * src = imgbtn->img_src_left[state];
    221 
    222     lv_coord_t tw = lv_obj_get_style_transform_width(obj, LV_PART_MAIN);
    223     lv_coord_t th = lv_obj_get_style_transform_height(obj, LV_PART_MAIN);
    224     lv_area_t coords;
    225     lv_area_copy(&coords, &obj->coords);
    226     coords.x1 -= tw;
    227     coords.x2 += tw;
    228     coords.y1 -= th;
    229     coords.y2 += th;
    230 
    231     lv_draw_img_dsc_t img_dsc;
    232     lv_draw_img_dsc_init(&img_dsc);
    233     lv_obj_init_draw_img_dsc(obj, LV_PART_MAIN, &img_dsc);
    234 
    235     lv_img_header_t header;
    236     lv_area_t coords_part;
    237     lv_coord_t left_w = 0;
    238     lv_coord_t right_w = 0;
    239 
    240     if(src) {
    241         lv_img_decoder_get_info(src, &header);
    242         left_w = header.w;
    243         coords_part.x1 = coords.x1;
    244         coords_part.y1 = coords.y1;
    245         coords_part.x2 = coords.x1 + header.w - 1;
    246         coords_part.y2 = coords.y1 + header.h - 1;
    247         lv_draw_img(draw_ctx, &img_dsc, &coords_part, src);
    248     }
    249 
    250     src = imgbtn->img_src_right[state];
    251     if(src) {
    252         lv_img_decoder_get_info(src, &header);
    253         right_w = header.w;
    254         coords_part.x1 = coords.x2 - header.w + 1;
    255         coords_part.y1 = coords.y1;
    256         coords_part.x2 = coords.x2;
    257         coords_part.y2 = coords.y1 + header.h - 1;
    258         lv_draw_img(draw_ctx, &img_dsc, &coords_part, src);
    259     }
    260 
    261     src = imgbtn->img_src_mid[state];
    262     if(src) {
    263         lv_area_t clip_area_center;
    264         clip_area_center.x1 = coords.x1 + left_w;
    265         clip_area_center.x2 = coords.x2 - right_w;
    266         clip_area_center.y1 = coords.y1;
    267         clip_area_center.y2 = coords.y2;
    268 
    269 
    270         bool comm_res;
    271         comm_res = _lv_area_intersect(&clip_area_center, &clip_area_center, draw_ctx->clip_area);
    272         if(comm_res) {
    273             lv_coord_t i;
    274             lv_img_decoder_get_info(src, &header);
    275 
    276             const lv_area_t * clip_area_ori = draw_ctx->clip_area;
    277             draw_ctx->clip_area = &clip_area_center;
    278 
    279             coords_part.x1 = coords.x1 + left_w;
    280             coords_part.y1 = coords.y1;
    281             coords_part.x2 = coords_part.x1 + header.w - 1;
    282             coords_part.y2 = coords_part.y1 + header.h - 1;
    283 
    284             for(i = coords_part.x1; i < (lv_coord_t)(clip_area_center.x2 + header.w - 1); i += header.w) {
    285                 lv_draw_img(draw_ctx, &img_dsc, &coords_part, src);
    286                 coords_part.x1 = coords_part.x2 + 1;
    287                 coords_part.x2 += header.w;
    288             }
    289             draw_ctx->clip_area = clip_area_ori;
    290         }
    291     }
    292 }
    293 
    294 static void refr_img(lv_obj_t * obj)
    295 {
    296     lv_imgbtn_t * imgbtn = (lv_imgbtn_t *)obj;
    297     lv_imgbtn_state_t state  = suggest_state(obj, get_state(obj));
    298     lv_img_header_t header;
    299 
    300     const void * src = imgbtn->img_src_mid[state];
    301     if(src == NULL) return;
    302 
    303     lv_res_t info_res = LV_RES_OK;
    304     info_res = lv_img_decoder_get_info(src, &header);
    305 
    306     if(info_res == LV_RES_OK) {
    307         imgbtn->act_cf = header.cf;
    308         lv_obj_refresh_self_size(obj);
    309         lv_obj_set_height(obj, header.h); /*Keep the user defined width*/
    310     }
    311     else {
    312         imgbtn->act_cf = LV_IMG_CF_UNKNOWN;
    313     }
    314 
    315     lv_obj_invalidate(obj);
    316 }
    317 
    318 /**
    319  * If `src` is not defined for the current state try to get a state which is related to the current but has `src`.
    320  * E.g. if the PRESSED src is not set but the RELEASED does, use the RELEASED.
    321  * @param imgbtn pointer to an image button
    322  * @param state the state to convert
    323  * @return the suggested state
    324  */
    325 static lv_imgbtn_state_t suggest_state(lv_obj_t * obj, lv_imgbtn_state_t state)
    326 {
    327     lv_imgbtn_t * imgbtn = (lv_imgbtn_t *)obj;
    328     if(imgbtn->img_src_mid[state] == NULL) {
    329         switch(state) {
    330             case LV_IMGBTN_STATE_PRESSED:
    331                 if(imgbtn->img_src_mid[LV_IMGBTN_STATE_RELEASED]) return LV_IMGBTN_STATE_RELEASED;
    332                 break;
    333             case LV_IMGBTN_STATE_CHECKED_RELEASED:
    334                 if(imgbtn->img_src_mid[LV_IMGBTN_STATE_RELEASED]) return LV_IMGBTN_STATE_RELEASED;
    335                 break;
    336             case LV_IMGBTN_STATE_CHECKED_PRESSED:
    337                 if(imgbtn->img_src_mid[LV_IMGBTN_STATE_CHECKED_RELEASED]) return LV_IMGBTN_STATE_CHECKED_RELEASED;
    338                 if(imgbtn->img_src_mid[LV_IMGBTN_STATE_PRESSED]) return LV_IMGBTN_STATE_PRESSED;
    339                 if(imgbtn->img_src_mid[LV_IMGBTN_STATE_RELEASED]) return LV_IMGBTN_STATE_RELEASED;
    340                 break;
    341             case LV_IMGBTN_STATE_DISABLED:
    342                 if(imgbtn->img_src_mid[LV_IMGBTN_STATE_RELEASED]) return LV_IMGBTN_STATE_RELEASED;
    343                 break;
    344             case LV_IMGBTN_STATE_CHECKED_DISABLED:
    345                 if(imgbtn->img_src_mid[LV_IMGBTN_STATE_CHECKED_RELEASED]) return LV_IMGBTN_STATE_CHECKED_RELEASED;
    346                 if(imgbtn->img_src_mid[LV_IMGBTN_STATE_RELEASED]) return LV_IMGBTN_STATE_RELEASED;
    347                 break;
    348             default:
    349                 break;
    350         }
    351     }
    352 
    353     return state;
    354 }
    355 
    356 lv_imgbtn_state_t get_state(const lv_obj_t * imgbtn)
    357 {
    358     LV_ASSERT_OBJ(imgbtn, MY_CLASS);
    359 
    360     lv_state_t obj_state = lv_obj_get_state(imgbtn);
    361 
    362     if(obj_state & LV_STATE_DISABLED) {
    363         if(obj_state & LV_STATE_CHECKED) return LV_IMGBTN_STATE_CHECKED_DISABLED;
    364         else return LV_IMGBTN_STATE_DISABLED;
    365     }
    366 
    367     if(obj_state & LV_STATE_CHECKED) {
    368         if(obj_state & LV_STATE_PRESSED) return LV_IMGBTN_STATE_CHECKED_PRESSED;
    369         else return LV_IMGBTN_STATE_CHECKED_RELEASED;
    370     }
    371     else {
    372         if(obj_state & LV_STATE_PRESSED) return LV_IMGBTN_STATE_PRESSED;
    373         else return LV_IMGBTN_STATE_RELEASED;
    374     }
    375 }
    376 
    377 #endif