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