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_obj_scroll.c (27720B)
1 /** 2 * @file lv_obj_scroll.c 3 * 4 */ 5 6 /********************* 7 * INCLUDES 8 *********************/ 9 #include "lv_obj_scroll.h" 10 #include "lv_obj.h" 11 #include "lv_indev.h" 12 #include "lv_disp.h" 13 #include "lv_indev_scroll.h" 14 15 /********************* 16 * DEFINES 17 *********************/ 18 #define MY_CLASS &lv_obj_class 19 #define SCROLL_ANIM_TIME_MIN 200 /*ms*/ 20 #define SCROLL_ANIM_TIME_MAX 400 /*ms*/ 21 #define SCROLLBAR_MIN_SIZE (LV_DPX(10)) 22 23 /********************** 24 * TYPEDEFS 25 **********************/ 26 27 /********************** 28 * GLOBAL PROTOTYPES 29 **********************/ 30 31 /********************** 32 * STATIC PROTOTYPES 33 **********************/ 34 static lv_res_t scroll_by_raw(lv_obj_t * obj, lv_coord_t x, lv_coord_t y); 35 static void scroll_x_anim(void * obj, int32_t v); 36 static void scroll_y_anim(void * obj, int32_t v); 37 static void scroll_anim_ready_cb(lv_anim_t * a); 38 static void scroll_area_into_view(const lv_area_t * area, lv_obj_t * child, lv_point_t * scroll_value, 39 lv_anim_enable_t anim_en); 40 41 /********************** 42 * STATIC VARIABLES 43 **********************/ 44 45 /********************** 46 * MACROS 47 **********************/ 48 49 /********************** 50 * GLOBAL FUNCTIONS 51 **********************/ 52 53 /*===================== 54 * Setter functions 55 *====================*/ 56 57 void lv_obj_set_scrollbar_mode(lv_obj_t * obj, lv_scrollbar_mode_t mode) 58 { 59 LV_ASSERT_OBJ(obj, MY_CLASS); 60 61 lv_obj_allocate_spec_attr(obj); 62 63 if(obj->spec_attr->scrollbar_mode == mode) return; 64 obj->spec_attr->scrollbar_mode = mode; 65 lv_obj_invalidate(obj); 66 } 67 68 void lv_obj_set_scroll_dir(lv_obj_t * obj, lv_dir_t dir) 69 { 70 lv_obj_allocate_spec_attr(obj); 71 72 if(dir != obj->spec_attr->scroll_dir) { 73 obj->spec_attr->scroll_dir = dir; 74 } 75 } 76 77 void lv_obj_set_scroll_snap_x(lv_obj_t * obj, lv_scroll_snap_t align) 78 { 79 lv_obj_allocate_spec_attr(obj); 80 obj->spec_attr->scroll_snap_x = align; 81 } 82 83 void lv_obj_set_scroll_snap_y(lv_obj_t * obj, lv_scroll_snap_t align) 84 { 85 lv_obj_allocate_spec_attr(obj); 86 obj->spec_attr->scroll_snap_y = align; 87 } 88 89 /*===================== 90 * Getter functions 91 *====================*/ 92 93 lv_scrollbar_mode_t lv_obj_get_scrollbar_mode(const lv_obj_t * obj) 94 { 95 if(obj->spec_attr) return obj->spec_attr->scrollbar_mode; 96 else return LV_SCROLLBAR_MODE_AUTO; 97 } 98 99 lv_dir_t lv_obj_get_scroll_dir(const lv_obj_t * obj) 100 { 101 if(obj->spec_attr) return obj->spec_attr->scroll_dir; 102 else return LV_DIR_ALL; 103 } 104 105 lv_scroll_snap_t lv_obj_get_scroll_snap_x(const lv_obj_t * obj) 106 { 107 if(obj->spec_attr) return obj->spec_attr->scroll_snap_x; 108 else return LV_SCROLL_SNAP_NONE; 109 } 110 111 lv_scroll_snap_t lv_obj_get_scroll_snap_y(const lv_obj_t * obj) 112 { 113 if(obj->spec_attr) return obj->spec_attr->scroll_snap_y; 114 else return LV_SCROLL_SNAP_NONE; 115 } 116 117 lv_coord_t lv_obj_get_scroll_x(const lv_obj_t * obj) 118 { 119 if(obj->spec_attr == NULL) return 0; 120 return -obj->spec_attr->scroll.x; 121 } 122 123 lv_coord_t lv_obj_get_scroll_y(const lv_obj_t * obj) 124 { 125 if(obj->spec_attr == NULL) return 0; 126 return -obj->spec_attr->scroll.y; 127 } 128 129 lv_coord_t lv_obj_get_scroll_top(lv_obj_t * obj) 130 { 131 if(obj->spec_attr == NULL) return 0; 132 return -obj->spec_attr->scroll.y; 133 } 134 135 lv_coord_t lv_obj_get_scroll_bottom(lv_obj_t * obj) 136 { 137 LV_ASSERT_OBJ(obj, MY_CLASS); 138 139 lv_coord_t child_res = LV_COORD_MIN; 140 uint32_t i; 141 uint32_t child_cnt = lv_obj_get_child_cnt(obj); 142 for(i = 0; i < child_cnt; i++) { 143 lv_obj_t * child = obj->spec_attr->children[i]; 144 if(lv_obj_has_flag_any(child, LV_OBJ_FLAG_HIDDEN | LV_OBJ_FLAG_FLOATING)) continue; 145 child_res = LV_MAX(child_res, child->coords.y2); 146 } 147 148 lv_coord_t pad_top = lv_obj_get_style_pad_top(obj, LV_PART_MAIN); 149 lv_coord_t pad_bottom = lv_obj_get_style_pad_bottom(obj, LV_PART_MAIN); 150 lv_coord_t border_width = lv_obj_get_style_border_width(obj, LV_PART_MAIN); 151 152 if(child_res != LV_COORD_MIN) { 153 child_res -= (obj->coords.y2 - pad_bottom - border_width); 154 } 155 156 lv_coord_t self_h = lv_obj_get_self_height(obj); 157 self_h = self_h - (lv_obj_get_height(obj) - pad_top - pad_bottom - 2 * border_width); 158 self_h -= lv_obj_get_scroll_y(obj); 159 return LV_MAX(child_res, self_h); 160 } 161 162 lv_coord_t lv_obj_get_scroll_left(lv_obj_t * obj) 163 { 164 LV_ASSERT_OBJ(obj, MY_CLASS); 165 166 /*Normally can't scroll the object out on the left. 167 *So simply use the current scroll position as "left size"*/ 168 if(lv_obj_get_style_base_dir(obj, LV_PART_MAIN) != LV_BASE_DIR_RTL) { 169 if(obj->spec_attr == NULL) return 0; 170 return -obj->spec_attr->scroll.x; 171 } 172 173 /*With RTL base direction scrolling the left is normal so find the left most coordinate*/ 174 lv_coord_t pad_right = lv_obj_get_style_pad_right(obj, LV_PART_MAIN); 175 lv_coord_t pad_left = lv_obj_get_style_pad_left(obj, LV_PART_MAIN); 176 lv_coord_t border_width = lv_obj_get_style_border_width(obj, LV_PART_MAIN); 177 178 lv_coord_t child_res = 0; 179 180 uint32_t i; 181 lv_coord_t x1 = LV_COORD_MAX; 182 uint32_t child_cnt = lv_obj_get_child_cnt(obj); 183 for(i = 0; i < child_cnt; i++) { 184 lv_obj_t * child = obj->spec_attr->children[i]; 185 if(lv_obj_has_flag_any(child, LV_OBJ_FLAG_HIDDEN | LV_OBJ_FLAG_FLOATING)) continue; 186 x1 = LV_MIN(x1, child->coords.x1); 187 188 } 189 190 if(x1 != LV_COORD_MAX) { 191 child_res = x1; 192 child_res = (obj->coords.x1 + pad_left + border_width) - child_res; 193 } 194 else { 195 child_res = LV_COORD_MIN; 196 } 197 198 lv_coord_t self_w = lv_obj_get_self_width(obj); 199 self_w = self_w - (lv_obj_get_width(obj) - pad_right - pad_left - 2 * border_width); 200 self_w += lv_obj_get_scroll_x(obj); 201 202 return LV_MAX(child_res, self_w); 203 } 204 205 lv_coord_t lv_obj_get_scroll_right(lv_obj_t * obj) 206 { 207 LV_ASSERT_OBJ(obj, MY_CLASS); 208 209 /*With RTL base dir can't scroll to the object out on the right. 210 *So simply use the current scroll position as "right size"*/ 211 if(lv_obj_get_style_base_dir(obj, LV_PART_MAIN) == LV_BASE_DIR_RTL) { 212 if(obj->spec_attr == NULL) return 0; 213 return obj->spec_attr->scroll.x; 214 } 215 216 /*With other base direction (LTR) scrolling to the right is normal so find the right most coordinate*/ 217 lv_coord_t child_res = LV_COORD_MIN; 218 uint32_t i; 219 uint32_t child_cnt = lv_obj_get_child_cnt(obj); 220 for(i = 0; i < child_cnt; i++) { 221 lv_obj_t * child = obj->spec_attr->children[i]; 222 if(lv_obj_has_flag_any(child, LV_OBJ_FLAG_HIDDEN | LV_OBJ_FLAG_FLOATING)) continue; 223 child_res = LV_MAX(child_res, child->coords.x2); 224 } 225 226 lv_coord_t pad_right = lv_obj_get_style_pad_right(obj, LV_PART_MAIN); 227 lv_coord_t pad_left = lv_obj_get_style_pad_left(obj, LV_PART_MAIN); 228 lv_coord_t border_width = lv_obj_get_style_border_width(obj, LV_PART_MAIN); 229 230 if(child_res != LV_COORD_MIN) { 231 child_res -= (obj->coords.x2 - pad_right - border_width); 232 } 233 234 lv_coord_t self_w; 235 self_w = lv_obj_get_self_width(obj); 236 self_w = self_w - (lv_obj_get_width(obj) - pad_right - pad_left - 2 * border_width); 237 self_w -= lv_obj_get_scroll_x(obj); 238 return LV_MAX(child_res, self_w); 239 } 240 241 void lv_obj_get_scroll_end(struct _lv_obj_t * obj, lv_point_t * end) 242 { 243 lv_anim_t * a; 244 a = lv_anim_get(obj, scroll_x_anim); 245 end->x = a ? -a->end_value : lv_obj_get_scroll_x(obj); 246 247 a = lv_anim_get(obj, scroll_y_anim); 248 end->y = a ? -a->end_value : lv_obj_get_scroll_y(obj); 249 } 250 251 /*===================== 252 * Other functions 253 *====================*/ 254 255 void lv_obj_scroll_by_bounded(lv_obj_t * obj, lv_coord_t dx, lv_coord_t dy, lv_anim_enable_t anim_en) 256 { 257 if(dx == 0 && dy == 0) return; 258 259 /*We need to know the final sizes for bound check*/ 260 lv_obj_update_layout(obj); 261 262 /*Don't let scroll more then naturally possible by the size of the content*/ 263 lv_coord_t x_current = -lv_obj_get_scroll_x(obj); 264 lv_coord_t x_bounded = x_current + dx; 265 266 if(lv_obj_get_style_base_dir(obj, LV_PART_MAIN) != LV_BASE_DIR_RTL) { 267 if(x_bounded > 0) x_bounded = 0; 268 if(x_bounded < 0) { 269 lv_coord_t scroll_max = lv_obj_get_scroll_left(obj) + lv_obj_get_scroll_right(obj); 270 if(scroll_max < 0) scroll_max = 0; 271 272 if(x_bounded < -scroll_max) x_bounded = -scroll_max; 273 } 274 } 275 else { 276 if(x_bounded < 0) x_bounded = 0; 277 if(x_bounded > 0) { 278 lv_coord_t scroll_max = lv_obj_get_scroll_left(obj) + lv_obj_get_scroll_right(obj); 279 if(scroll_max < 0) scroll_max = 0; 280 281 if(x_bounded > scroll_max) x_bounded = scroll_max; 282 } 283 } 284 285 /*Don't let scroll more then naturally possible by the size of the content*/ 286 lv_coord_t y_current = -lv_obj_get_scroll_y(obj); 287 lv_coord_t y_bounded = y_current + dy; 288 289 if(y_bounded > 0) y_bounded = 0; 290 if(y_bounded < 0) { 291 lv_coord_t scroll_max = lv_obj_get_scroll_top(obj) + lv_obj_get_scroll_bottom(obj); 292 if(scroll_max < 0) scroll_max = 0; 293 if(y_bounded < -scroll_max) y_bounded = -scroll_max; 294 } 295 296 dx = x_bounded - x_current; 297 dy = y_bounded - y_current; 298 if(dx || dy) { 299 lv_obj_scroll_by(obj, dx, dy, anim_en); 300 } 301 } 302 303 304 void lv_obj_scroll_by(lv_obj_t * obj, lv_coord_t dx, lv_coord_t dy, lv_anim_enable_t anim_en) 305 { 306 if(dx == 0 && dy == 0) return; 307 if(anim_en == LV_ANIM_ON) { 308 lv_disp_t * d = lv_obj_get_disp(obj); 309 lv_anim_t a; 310 lv_anim_init(&a); 311 lv_anim_set_var(&a, obj); 312 lv_anim_set_ready_cb(&a, scroll_anim_ready_cb); 313 314 if(dx) { 315 uint32_t t = lv_anim_speed_to_time((lv_disp_get_hor_res(d) * 2) >> 2, 0, dx); 316 if(t < SCROLL_ANIM_TIME_MIN) t = SCROLL_ANIM_TIME_MIN; 317 if(t > SCROLL_ANIM_TIME_MAX) t = SCROLL_ANIM_TIME_MAX; 318 lv_anim_set_time(&a, t); 319 lv_coord_t sx = lv_obj_get_scroll_x(obj); 320 lv_anim_set_values(&a, -sx, -sx + dx); 321 lv_anim_set_exec_cb(&a, scroll_x_anim); 322 lv_anim_set_path_cb(&a, lv_anim_path_ease_out); 323 324 lv_res_t res; 325 res = lv_event_send(obj, LV_EVENT_SCROLL_BEGIN, &a); 326 if(res != LV_RES_OK) return; 327 lv_anim_start(&a); 328 } 329 330 if(dy) { 331 uint32_t t = lv_anim_speed_to_time((lv_disp_get_ver_res(d) * 2) >> 2, 0, dy); 332 if(t < SCROLL_ANIM_TIME_MIN) t = SCROLL_ANIM_TIME_MIN; 333 if(t > SCROLL_ANIM_TIME_MAX) t = SCROLL_ANIM_TIME_MAX; 334 lv_anim_set_time(&a, t); 335 lv_coord_t sy = lv_obj_get_scroll_y(obj); 336 lv_anim_set_values(&a, -sy, -sy + dy); 337 lv_anim_set_exec_cb(&a, scroll_y_anim); 338 lv_anim_set_path_cb(&a, lv_anim_path_ease_out); 339 340 lv_res_t res; 341 res = lv_event_send(obj, LV_EVENT_SCROLL_BEGIN, &a); 342 if(res != LV_RES_OK) return; 343 lv_anim_start(&a); 344 } 345 } 346 else { 347 /*Remove pending animations*/ 348 lv_anim_del(obj, scroll_y_anim); 349 lv_anim_del(obj, scroll_x_anim); 350 351 lv_res_t res; 352 res = lv_event_send(obj, LV_EVENT_SCROLL_BEGIN, NULL); 353 if(res != LV_RES_OK) return; 354 355 res = scroll_by_raw(obj, dx, dy); 356 if(res != LV_RES_OK) return; 357 358 res = lv_event_send(obj, LV_EVENT_SCROLL_END, NULL); 359 if(res != LV_RES_OK) return; 360 } 361 } 362 363 void lv_obj_scroll_to(lv_obj_t * obj, lv_coord_t x, lv_coord_t y, lv_anim_enable_t anim_en) 364 { 365 lv_obj_scroll_to_x(obj, x, anim_en); 366 lv_obj_scroll_to_y(obj, y, anim_en); 367 } 368 369 void lv_obj_scroll_to_x(lv_obj_t * obj, lv_coord_t x, lv_anim_enable_t anim_en) 370 { 371 lv_anim_del(obj, scroll_x_anim); 372 373 lv_coord_t scroll_x = lv_obj_get_scroll_x(obj); 374 lv_coord_t diff = -x + scroll_x; 375 376 lv_obj_scroll_by_bounded(obj, diff, 0, anim_en); 377 } 378 379 void lv_obj_scroll_to_y(lv_obj_t * obj, lv_coord_t y, lv_anim_enable_t anim_en) 380 { 381 lv_anim_del(obj, scroll_y_anim); 382 383 lv_coord_t scroll_y = lv_obj_get_scroll_y(obj); 384 lv_coord_t diff = -y + scroll_y; 385 386 lv_obj_scroll_by_bounded(obj, 0, diff, anim_en); 387 } 388 389 void lv_obj_scroll_to_view(lv_obj_t * obj, lv_anim_enable_t anim_en) 390 { 391 /*Be sure the screens layout is correct*/ 392 lv_obj_update_layout(obj); 393 394 lv_point_t p = {0, 0}; 395 scroll_area_into_view(&obj->coords, obj, &p, anim_en); 396 } 397 398 void lv_obj_scroll_to_view_recursive(lv_obj_t * obj, lv_anim_enable_t anim_en) 399 { 400 /*Be sure the screens layout is correct*/ 401 lv_obj_update_layout(obj); 402 403 lv_point_t p = {0, 0}; 404 lv_obj_t * child = obj; 405 lv_obj_t * parent = lv_obj_get_parent(child); 406 while(parent) { 407 scroll_area_into_view(&obj->coords, child, &p, anim_en); 408 child = parent; 409 parent = lv_obj_get_parent(parent); 410 } 411 } 412 413 bool lv_obj_is_scrolling(const lv_obj_t * obj) 414 { 415 lv_indev_t * indev = lv_indev_get_next(NULL); 416 while(indev) { 417 if(lv_indev_get_scroll_obj(indev) == obj) return true; 418 indev = lv_indev_get_next(indev); 419 } 420 421 return false; 422 } 423 424 void lv_obj_update_snap(lv_obj_t * obj, lv_anim_enable_t anim_en) 425 { 426 lv_obj_update_layout(obj); 427 lv_point_t p; 428 lv_indev_scroll_get_snap_dist(obj, &p); 429 lv_obj_scroll_by(obj, p.x, p.y, anim_en); 430 } 431 432 void lv_obj_get_scrollbar_area(lv_obj_t * obj, lv_area_t * hor_area, lv_area_t * ver_area) 433 { 434 lv_area_set(hor_area, 0, 0, -1, -1); 435 lv_area_set(ver_area, 0, 0, -1, -1); 436 437 if(lv_obj_has_flag(obj, LV_OBJ_FLAG_SCROLLABLE) == false) return; 438 439 lv_dir_t sm = lv_obj_get_scrollbar_mode(obj); 440 if(sm == LV_SCROLLBAR_MODE_OFF) return; 441 442 /*If there is no indev scrolling this object but `mode==active` return*/ 443 lv_indev_t * indev = lv_indev_get_next(NULL); 444 if(sm == LV_SCROLLBAR_MODE_ACTIVE) { 445 while(indev) { 446 if(lv_indev_get_scroll_obj(indev) == obj) break; 447 indev = lv_indev_get_next(indev); 448 } 449 if(indev == NULL) return; 450 } 451 452 lv_coord_t st = lv_obj_get_scroll_top(obj); 453 lv_coord_t sb = lv_obj_get_scroll_bottom(obj); 454 lv_coord_t sl = lv_obj_get_scroll_left(obj); 455 lv_coord_t sr = lv_obj_get_scroll_right(obj); 456 457 lv_dir_t dir = lv_obj_get_scroll_dir(obj); 458 459 bool ver_draw = false; 460 if((dir & LV_DIR_VER) && 461 ((sm == LV_SCROLLBAR_MODE_ON) || 462 (sm == LV_SCROLLBAR_MODE_AUTO && (st > 0 || sb > 0)) || 463 (sm == LV_SCROLLBAR_MODE_ACTIVE && lv_indev_get_scroll_dir(indev) == LV_DIR_VER))) { 464 ver_draw = true; 465 } 466 467 468 bool hor_draw = false; 469 if((dir & LV_DIR_HOR) && 470 ((sm == LV_SCROLLBAR_MODE_ON) || 471 (sm == LV_SCROLLBAR_MODE_AUTO && (sl > 0 || sr > 0)) || 472 (sm == LV_SCROLLBAR_MODE_ACTIVE && lv_indev_get_scroll_dir(indev) == LV_DIR_HOR))) { 473 hor_draw = true; 474 } 475 476 if(!hor_draw && !ver_draw) return; 477 478 bool rtl = lv_obj_get_style_base_dir(obj, LV_PART_SCROLLBAR) == LV_BASE_DIR_RTL ? true : false; 479 480 lv_coord_t top_space = lv_obj_get_style_pad_top(obj, LV_PART_SCROLLBAR); 481 lv_coord_t bottom_space = lv_obj_get_style_pad_bottom(obj, LV_PART_SCROLLBAR); 482 lv_coord_t left_space = lv_obj_get_style_pad_left(obj, LV_PART_SCROLLBAR); 483 lv_coord_t right_space = lv_obj_get_style_pad_right(obj, LV_PART_SCROLLBAR); 484 lv_coord_t tickness = lv_obj_get_style_width(obj, LV_PART_SCROLLBAR); 485 486 lv_coord_t obj_h = lv_obj_get_height(obj); 487 lv_coord_t obj_w = lv_obj_get_width(obj); 488 489 /*Space required for the vertical and horizontal scrollbars*/ 490 lv_coord_t ver_reg_space = ver_draw ? tickness : 0; 491 lv_coord_t hor_req_space = hor_draw ? tickness : 0; 492 lv_coord_t rem; 493 494 if(lv_obj_get_style_bg_opa(obj, LV_PART_SCROLLBAR) < LV_OPA_MIN && 495 lv_obj_get_style_border_opa(obj, LV_PART_SCROLLBAR) < LV_OPA_MIN) { 496 return; 497 } 498 499 /*Draw vertical scrollbar if the mode is ON or can be scrolled in this direction*/ 500 lv_coord_t content_h = obj_h + st + sb; 501 if(ver_draw && content_h) { 502 ver_area->y1 = obj->coords.y1; 503 ver_area->y2 = obj->coords.y2; 504 if(rtl) { 505 ver_area->x1 = obj->coords.x1 + left_space; 506 ver_area->x2 = ver_area->x1 + tickness - 1; 507 } 508 else { 509 ver_area->x2 = obj->coords.x2 - right_space; 510 ver_area->x1 = ver_area->x2 - tickness + 1; 511 } 512 513 lv_coord_t sb_h = ((obj_h - top_space - bottom_space - hor_req_space) * obj_h) / content_h; 514 sb_h = LV_MAX(sb_h, SCROLLBAR_MIN_SIZE); 515 rem = (obj_h - top_space - bottom_space - hor_req_space) - 516 sb_h; /*Remaining size from the scrollbar track that is not the scrollbar itself*/ 517 lv_coord_t scroll_h = content_h - obj_h; /*The size of the content which can be really scrolled*/ 518 if(scroll_h <= 0) { 519 ver_area->y1 = obj->coords.y1 + top_space; 520 ver_area->y2 = obj->coords.y2 - bottom_space - hor_req_space - 1; 521 } 522 else { 523 lv_coord_t sb_y = (rem * sb) / scroll_h; 524 sb_y = rem - sb_y; 525 526 ver_area->y1 = obj->coords.y1 + sb_y + top_space; 527 ver_area->y2 = ver_area->y1 + sb_h - 1; 528 if(ver_area->y1 < obj->coords.y1 + top_space) { 529 ver_area->y1 = obj->coords.y1 + top_space; 530 if(ver_area->y1 + SCROLLBAR_MIN_SIZE > ver_area->y2) { 531 ver_area->y2 = ver_area->y1 + SCROLLBAR_MIN_SIZE; 532 } 533 } 534 if(ver_area->y2 > obj->coords.y2 - hor_req_space - bottom_space) { 535 ver_area->y2 = obj->coords.y2 - hor_req_space - bottom_space; 536 if(ver_area->y2 - SCROLLBAR_MIN_SIZE < ver_area->y1) { 537 ver_area->y1 = ver_area->y2 - SCROLLBAR_MIN_SIZE; 538 } 539 } 540 } 541 } 542 543 /*Draw horizontal scrollbar if the mode is ON or can be scrolled in this direction*/ 544 lv_coord_t content_w = obj_w + sl + sr; 545 if(hor_draw && content_w) { 546 hor_area->y2 = obj->coords.y2 - bottom_space; 547 hor_area->y1 = hor_area->y2 - tickness + 1; 548 hor_area->x1 = obj->coords.x1; 549 hor_area->x2 = obj->coords.x2; 550 551 lv_coord_t sb_w = ((obj_w - left_space - right_space - ver_reg_space) * obj_w) / content_w; 552 sb_w = LV_MAX(sb_w, SCROLLBAR_MIN_SIZE); 553 rem = (obj_w - left_space - right_space - ver_reg_space) - 554 sb_w; /*Remaining size from the scrollbar track that is not the scrollbar itself*/ 555 lv_coord_t scroll_w = content_w - obj_w; /*The size of the content which can be really scrolled*/ 556 if(scroll_w <= 0) { 557 if(rtl) { 558 hor_area->x1 = obj->coords.x1 + left_space + ver_reg_space - 1; 559 hor_area->x2 = obj->coords.x2 - right_space; 560 } 561 else { 562 hor_area->x1 = obj->coords.x1 + left_space; 563 hor_area->x2 = obj->coords.x2 - right_space - ver_reg_space - 1; 564 } 565 } 566 else { 567 lv_coord_t sb_x = (rem * sr) / scroll_w; 568 sb_x = rem - sb_x; 569 570 if(rtl) { 571 hor_area->x1 = obj->coords.x1 + sb_x + left_space + ver_reg_space; 572 hor_area->x2 = hor_area->x1 + sb_w - 1; 573 if(hor_area->x1 < obj->coords.x1 + left_space + ver_reg_space) { 574 hor_area->x1 = obj->coords.x1 + left_space + ver_reg_space; 575 if(hor_area->x1 + SCROLLBAR_MIN_SIZE > hor_area->x2) { 576 hor_area->x2 = hor_area->x1 + SCROLLBAR_MIN_SIZE; 577 } 578 } 579 if(hor_area->x2 > obj->coords.x2 - right_space) { 580 hor_area->x2 = obj->coords.x2 - right_space; 581 if(hor_area->x2 - SCROLLBAR_MIN_SIZE < hor_area->x1) { 582 hor_area->x1 = hor_area->x2 - SCROLLBAR_MIN_SIZE; 583 } 584 } 585 } 586 else { 587 hor_area->x1 = obj->coords.x1 + sb_x + left_space; 588 hor_area->x2 = hor_area->x1 + sb_w - 1; 589 if(hor_area->x1 < obj->coords.x1 + left_space) { 590 hor_area->x1 = obj->coords.x1 + left_space; 591 if(hor_area->x1 + SCROLLBAR_MIN_SIZE > hor_area->x2) { 592 hor_area->x2 = hor_area->x1 + SCROLLBAR_MIN_SIZE; 593 } 594 } 595 if(hor_area->x2 > obj->coords.x2 - ver_reg_space - right_space) { 596 hor_area->x2 = obj->coords.x2 - ver_reg_space - right_space; 597 if(hor_area->x2 - SCROLLBAR_MIN_SIZE < hor_area->x1) { 598 hor_area->x1 = hor_area->x2 - SCROLLBAR_MIN_SIZE; 599 } 600 } 601 } 602 } 603 } 604 } 605 606 void lv_obj_scrollbar_invalidate(lv_obj_t * obj) 607 { 608 lv_area_t hor_area; 609 lv_area_t ver_area; 610 lv_obj_get_scrollbar_area(obj, &hor_area, &ver_area); 611 612 if(lv_area_get_size(&hor_area) <= 0 && lv_area_get_size(&ver_area) <= 0) return; 613 614 if(lv_area_get_size(&hor_area) > 0) lv_obj_invalidate_area(obj, &hor_area); 615 if(lv_area_get_size(&ver_area) > 0) lv_obj_invalidate_area(obj, &ver_area); 616 } 617 618 void lv_obj_readjust_scroll(lv_obj_t * obj, lv_anim_enable_t anim_en) 619 { 620 /*Be sure the bottom side is not remains scrolled in*/ 621 /*With snapping the content can't be scrolled in*/ 622 if(lv_obj_get_scroll_snap_y(obj) == LV_SCROLL_SNAP_NONE) { 623 lv_coord_t st = lv_obj_get_scroll_top(obj); 624 lv_coord_t sb = lv_obj_get_scroll_bottom(obj); 625 if(sb < 0 && st > 0) { 626 sb = LV_MIN(st, -sb); 627 lv_obj_scroll_by(obj, 0, sb, anim_en); 628 } 629 } 630 631 if(lv_obj_get_scroll_snap_x(obj) == LV_SCROLL_SNAP_NONE) { 632 lv_coord_t sl = lv_obj_get_scroll_left(obj); 633 lv_coord_t sr = lv_obj_get_scroll_right(obj); 634 if(lv_obj_get_style_base_dir(obj, LV_PART_MAIN) != LV_BASE_DIR_RTL) { 635 /*Be sure the left side is not remains scrolled in*/ 636 if(sr < 0 && sl > 0) { 637 sr = LV_MIN(sl, -sr); 638 lv_obj_scroll_by(obj, sr, 0, anim_en); 639 } 640 } 641 else { 642 /*Be sure the right side is not remains scrolled in*/ 643 if(sl < 0 && sr > 0) { 644 sr = LV_MIN(sr, -sl); 645 lv_obj_scroll_by(obj, sl, 0, anim_en); 646 } 647 } 648 } 649 } 650 651 /********************** 652 * STATIC FUNCTIONS 653 **********************/ 654 655 static lv_res_t scroll_by_raw(lv_obj_t * obj, lv_coord_t x, lv_coord_t y) 656 { 657 if(x == 0 && y == 0) return LV_RES_OK; 658 659 lv_obj_allocate_spec_attr(obj); 660 661 obj->spec_attr->scroll.x += x; 662 obj->spec_attr->scroll.y += y; 663 664 lv_obj_move_children_by(obj, x, y, true); 665 lv_res_t res = lv_event_send(obj, LV_EVENT_SCROLL, NULL); 666 if(res != LV_RES_OK) return res; 667 lv_obj_invalidate(obj); 668 return LV_RES_OK; 669 } 670 671 static void scroll_x_anim(void * obj, int32_t v) 672 { 673 scroll_by_raw(obj, v + lv_obj_get_scroll_x(obj), 0); 674 } 675 676 static void scroll_y_anim(void * obj, int32_t v) 677 { 678 scroll_by_raw(obj, 0, v + lv_obj_get_scroll_y(obj)); 679 } 680 681 static void scroll_anim_ready_cb(lv_anim_t * a) 682 { 683 lv_event_send(a->var, LV_EVENT_SCROLL_END, NULL); 684 } 685 686 static void scroll_area_into_view(const lv_area_t * area, lv_obj_t * child, lv_point_t * scroll_value, 687 lv_anim_enable_t anim_en) 688 { 689 lv_obj_t * parent = lv_obj_get_parent(child); 690 if(!lv_obj_has_flag(parent, LV_OBJ_FLAG_SCROLLABLE)) return; 691 692 lv_dir_t scroll_dir = lv_obj_get_scroll_dir(parent); 693 lv_coord_t snap_goal = 0; 694 lv_coord_t act = 0; 695 const lv_area_t * area_tmp; 696 697 lv_coord_t y_scroll = 0; 698 lv_scroll_snap_t snap_y = lv_obj_get_scroll_snap_y(parent); 699 if(snap_y != LV_SCROLL_SNAP_NONE) area_tmp = &child->coords; 700 else area_tmp = area; 701 702 lv_coord_t border_width = lv_obj_get_style_border_width(parent, LV_PART_MAIN); 703 lv_coord_t ptop = lv_obj_get_style_pad_top(parent, LV_PART_MAIN) + border_width; 704 lv_coord_t pbottom = lv_obj_get_style_pad_bottom(parent, LV_PART_MAIN) + border_width; 705 lv_coord_t top_diff = parent->coords.y1 + ptop - area_tmp->y1 - scroll_value->y; 706 lv_coord_t bottom_diff = -(parent->coords.y2 - pbottom - area_tmp->y2 - scroll_value->y); 707 lv_coord_t parent_h = lv_obj_get_height(parent) - ptop - pbottom; 708 if((top_diff >= 0 && bottom_diff >= 0)) y_scroll = 0; 709 else if(top_diff > 0) { 710 y_scroll = top_diff; 711 /*Do not let scrolling in*/ 712 lv_coord_t st = lv_obj_get_scroll_top(parent); 713 if(st - y_scroll < 0) y_scroll = 0; 714 } 715 else if(bottom_diff > 0) { 716 y_scroll = -bottom_diff; 717 /*Do not let scrolling in*/ 718 lv_coord_t sb = lv_obj_get_scroll_bottom(parent); 719 if(sb + y_scroll < 0) y_scroll = 0; 720 } 721 722 switch(snap_y) { 723 case LV_SCROLL_SNAP_START: 724 snap_goal = parent->coords.y1 + ptop; 725 act = area_tmp->y1 + y_scroll; 726 y_scroll += snap_goal - act; 727 break; 728 case LV_SCROLL_SNAP_END: 729 snap_goal = parent->coords.y2 - pbottom; 730 act = area_tmp->y2 + y_scroll; 731 y_scroll += snap_goal - act; 732 break; 733 case LV_SCROLL_SNAP_CENTER: 734 snap_goal = parent->coords.y1 + ptop + parent_h / 2; 735 act = lv_area_get_height(area_tmp) / 2 + area_tmp->y1 + y_scroll; 736 y_scroll += snap_goal - act; 737 break; 738 } 739 740 lv_coord_t x_scroll = 0; 741 lv_scroll_snap_t snap_x = lv_obj_get_scroll_snap_x(parent); 742 if(snap_x != LV_SCROLL_SNAP_NONE) area_tmp = &child->coords; 743 else area_tmp = area; 744 745 lv_coord_t pleft = lv_obj_get_style_pad_left(parent, LV_PART_MAIN) + border_width; 746 lv_coord_t pright = lv_obj_get_style_pad_right(parent, LV_PART_MAIN) + border_width; 747 lv_coord_t left_diff = parent->coords.x1 + pleft - area_tmp->x1 - scroll_value->x; 748 lv_coord_t right_diff = -(parent->coords.x2 - pright - area_tmp->x2 - scroll_value->x); 749 if((left_diff >= 0 && right_diff >= 0)) x_scroll = 0; 750 else if(left_diff > 0) { 751 x_scroll = left_diff; 752 /*Do not let scrolling in*/ 753 lv_coord_t sl = lv_obj_get_scroll_left(parent); 754 if(sl - x_scroll < 0) x_scroll = 0; 755 } 756 else if(right_diff > 0) { 757 x_scroll = -right_diff; 758 /*Do not let scrolling in*/ 759 lv_coord_t sr = lv_obj_get_scroll_right(parent); 760 if(sr + x_scroll < 0) x_scroll = 0; 761 } 762 763 lv_coord_t parent_w = lv_obj_get_width(parent) - pleft - pright; 764 switch(snap_x) { 765 case LV_SCROLL_SNAP_START: 766 snap_goal = parent->coords.x1 + pleft; 767 act = area_tmp->x1 + x_scroll; 768 x_scroll += snap_goal - act; 769 break; 770 case LV_SCROLL_SNAP_END: 771 snap_goal = parent->coords.x2 - pright; 772 act = area_tmp->x2 + x_scroll; 773 x_scroll += snap_goal - act; 774 break; 775 case LV_SCROLL_SNAP_CENTER: 776 snap_goal = parent->coords.x1 + pleft + parent_w / 2; 777 act = lv_area_get_width(area_tmp) / 2 + area_tmp->x1 + x_scroll; 778 x_scroll += snap_goal - act; 779 break; 780 } 781 782 /*Remove any pending scroll animations.*/ 783 bool y_del = lv_anim_del(parent, scroll_y_anim); 784 bool x_del = lv_anim_del(parent, scroll_x_anim); 785 if(y_del || x_del) { 786 lv_res_t res; 787 res = lv_event_send(parent, LV_EVENT_SCROLL_END, NULL); 788 if(res != LV_RES_OK) return; 789 } 790 791 if((scroll_dir & LV_DIR_LEFT) == 0 && x_scroll < 0) x_scroll = 0; 792 if((scroll_dir & LV_DIR_RIGHT) == 0 && x_scroll > 0) x_scroll = 0; 793 if((scroll_dir & LV_DIR_TOP) == 0 && y_scroll < 0) y_scroll = 0; 794 if((scroll_dir & LV_DIR_BOTTOM) == 0 && y_scroll > 0) y_scroll = 0; 795 796 scroll_value->x += anim_en == LV_ANIM_OFF ? 0 : x_scroll; 797 scroll_value->y += anim_en == LV_ANIM_OFF ? 0 : y_scroll; 798 lv_obj_scroll_by(parent, x_scroll, y_scroll, anim_en); 799 }