diff options
-rw-r--r-- | apps/gui/skin_engine/skin_render.c | 9 | ||||
-rw-r--r-- | apps/screen_access.c | 4 | ||||
-rw-r--r-- | apps/screen_access.h | 2 | ||||
-rw-r--r-- | firmware/drivers/lcd-bitmap-common.c | 180 | ||||
-rw-r--r-- | firmware/drivers/lcd-scroll.c | 111 | ||||
-rw-r--r-- | firmware/export/scroll_engine.h | 30 | ||||
-rw-r--r-- | firmware/scroll_engine.c | 19 |
7 files changed, 201 insertions, 154 deletions
diff --git a/apps/gui/skin_engine/skin_render.c b/apps/gui/skin_engine/skin_render.c index 67f1f0f448..28483cbc49 100644 --- a/apps/gui/skin_engine/skin_render.c +++ b/apps/gui/skin_engine/skin_render.c | |||
@@ -779,7 +779,9 @@ void skin_render_viewport(struct skin_element* viewport, struct gui_wps *gwps, | |||
779 | if (refresh_type && needs_update) | 779 | if (refresh_type && needs_update) |
780 | { | 780 | { |
781 | if (info.force_redraw) | 781 | if (info.force_redraw) |
782 | display->scroll_stop_viewport_line(&skin_viewport->vp, info.line_number); | 782 | display->scroll_stop_viewport_rect(&skin_viewport->vp, |
783 | 0, info.line_number*display->getcharheight(), | ||
784 | skin_viewport->vp.width, display->getcharheight()); | ||
783 | write_line(display, align, info.line_number, | 785 | write_line(display, align, info.line_number, |
784 | info.line_scrolls, info.text_style); | 786 | info.line_scrolls, info.text_style); |
785 | } | 787 | } |
@@ -967,8 +969,11 @@ void skin_render_playlistviewer(struct playlistviewer* viewer, | |||
967 | /* only update if the line needs to be, and there is something to write */ | 969 | /* only update if the line needs to be, and there is something to write */ |
968 | if (refresh_type && needs_update) | 970 | if (refresh_type && needs_update) |
969 | { | 971 | { |
972 | struct viewport *vp = SKINOFFSETTOPTR(skin_buffer, viewer->vp); | ||
970 | if (!info.force_redraw) | 973 | if (!info.force_redraw) |
971 | display->scroll_stop_viewport_line(&skin_viewport->vp, info.line_number); | 974 | display->scroll_stop_viewport_rect(vp, |
975 | 0, info.line_number*display->getcharheight(), | ||
976 | vp->width, display->getcharheight()); | ||
972 | write_line(display, align, info.line_number, | 977 | write_line(display, align, info.line_number, |
973 | info.line_scrolls, info.text_style); | 978 | info.line_scrolls, info.text_style); |
974 | } | 979 | } |
diff --git a/apps/screen_access.c b/apps/screen_access.c index 161e596aa2..f454e0adef 100644 --- a/apps/screen_access.c +++ b/apps/screen_access.c | |||
@@ -247,9 +247,9 @@ struct screen screens[NB_SCREENS] = | |||
247 | .scroll_delay=&lcd_scroll_delay, | 247 | .scroll_delay=&lcd_scroll_delay, |
248 | .clear_display=&lcd_clear_display, | 248 | .clear_display=&lcd_clear_display, |
249 | .clear_viewport=&lcd_clear_viewport, | 249 | .clear_viewport=&lcd_clear_viewport, |
250 | .scroll_stop_viewport_rect=&lcd_scroll_stop_viewport_rect, | ||
250 | .scroll_stop=&lcd_scroll_stop, | 251 | .scroll_stop=&lcd_scroll_stop, |
251 | .scroll_stop_viewport=&lcd_scroll_stop_viewport, | 252 | .scroll_stop_viewport=&lcd_scroll_stop_viewport, |
252 | .scroll_stop_viewport_line=&lcd_scroll_stop_viewport_line, | ||
253 | .update=&lcd_update, | 253 | .update=&lcd_update, |
254 | .update_viewport=&lcd_update_viewport, | 254 | .update_viewport=&lcd_update_viewport, |
255 | .backlight_on=&backlight_on, | 255 | .backlight_on=&backlight_on, |
@@ -348,9 +348,9 @@ struct screen screens[NB_SCREENS] = | |||
348 | .scroll_delay=&lcd_remote_scroll_delay, | 348 | .scroll_delay=&lcd_remote_scroll_delay, |
349 | .clear_display=&lcd_remote_clear_display, | 349 | .clear_display=&lcd_remote_clear_display, |
350 | .clear_viewport=&lcd_remote_clear_viewport, | 350 | .clear_viewport=&lcd_remote_clear_viewport, |
351 | .scroll_stop_viewport_rect=&lcd_remote_scroll_stop_viewport_rect, | ||
351 | .scroll_stop=&lcd_remote_scroll_stop, | 352 | .scroll_stop=&lcd_remote_scroll_stop, |
352 | .scroll_stop_viewport=&lcd_remote_scroll_stop_viewport, | 353 | .scroll_stop_viewport=&lcd_remote_scroll_stop_viewport, |
353 | .scroll_stop_viewport_line=&lcd_remote_scroll_stop_viewport_line, | ||
354 | .update=&lcd_remote_update, | 354 | .update=&lcd_remote_update, |
355 | .update_viewport=&lcd_remote_update_viewport, | 355 | .update_viewport=&lcd_remote_update_viewport, |
356 | .backlight_on=&remote_backlight_on, | 356 | .backlight_on=&remote_backlight_on, |
diff --git a/apps/screen_access.h b/apps/screen_access.h index 448437c637..90b63ea338 100644 --- a/apps/screen_access.h +++ b/apps/screen_access.h | |||
@@ -149,7 +149,7 @@ struct screen | |||
149 | void (*clear_viewport)(void); | 149 | void (*clear_viewport)(void); |
150 | void (*scroll_stop)(void); | 150 | void (*scroll_stop)(void); |
151 | void (*scroll_stop_viewport)(const struct viewport *vp); | 151 | void (*scroll_stop_viewport)(const struct viewport *vp); |
152 | void (*scroll_stop_viewport_line)(const struct viewport *vp, int line); | 152 | void (*scroll_stop_viewport_rect)(const struct viewport* vp, int x, int y, int width, int height); |
153 | void (*update)(void); | 153 | void (*update)(void); |
154 | void (*update_viewport)(void); | 154 | void (*update_viewport)(void); |
155 | void (*backlight_on)(void); | 155 | void (*backlight_on)(void); |
diff --git a/firmware/drivers/lcd-bitmap-common.c b/firmware/drivers/lcd-bitmap-common.c index c04f57ef22..f3e700a4a1 100644 --- a/firmware/drivers/lcd-bitmap-common.c +++ b/firmware/drivers/lcd-bitmap-common.c | |||
@@ -412,12 +412,10 @@ static void LCDFN(putsxyofs_style)(int xpos, int ypos, | |||
412 | 412 | ||
413 | /*** Line oriented text output ***/ | 413 | /*** Line oriented text output ***/ |
414 | 414 | ||
415 | /* put a string at a given char position */ | ||
416 | void LCDFN(puts_style_xyoffset)(int x, int y, const unsigned char *str, | 415 | void LCDFN(puts_style_xyoffset)(int x, int y, const unsigned char *str, |
417 | int style, int x_offset, int y_offset) | 416 | int style, int x_offset, int y_offset) |
418 | { | 417 | { |
419 | int xpos, ypos, h; | 418 | int xpos, ypos, h; |
420 | LCDFN(scroll_stop_viewport_line)(current_vp, y); | ||
421 | if(!str) | 419 | if(!str) |
422 | return; | 420 | return; |
423 | 421 | ||
@@ -425,14 +423,15 @@ void LCDFN(puts_style_xyoffset)(int x, int y, const unsigned char *str, | |||
425 | if ((style&STYLE_XY_PIXELS) == 0) | 423 | if ((style&STYLE_XY_PIXELS) == 0) |
426 | { | 424 | { |
427 | xpos = x * LCDFN(getstringsize)(" ", NULL, NULL); | 425 | xpos = x * LCDFN(getstringsize)(" ", NULL, NULL); |
428 | ypos = y * h + y_offset; | 426 | ypos = y * h; |
429 | } | 427 | } |
430 | else | 428 | else |
431 | { | 429 | { |
432 | xpos = x; | 430 | xpos = x; |
433 | ypos = y + y_offset; | 431 | ypos = y; |
434 | } | 432 | } |
435 | LCDFN(putsxyofs_style)(xpos, ypos, str, style, h, x_offset); | 433 | LCDFN(scroll_stop_viewport_rect)(current_vp, x, y, current_vp->width - x, h); |
434 | LCDFN(putsxyofs_style)(xpos, ypos+y_offset, str, style, h, x_offset); | ||
436 | } | 435 | } |
437 | 436 | ||
438 | void LCDFN(puts_style_offset)(int x, int y, const unsigned char *str, | 437 | void LCDFN(puts_style_offset)(int x, int y, const unsigned char *str, |
@@ -469,7 +468,7 @@ void LCDFN(puts_offset)(int x, int y, const unsigned char *str, int offset) | |||
469 | 468 | ||
470 | /*** scrolling ***/ | 469 | /*** scrolling ***/ |
471 | 470 | ||
472 | static struct scrollinfo* find_scrolling_line(int line) | 471 | static struct scrollinfo* find_scrolling_line(int x, int y) |
473 | { | 472 | { |
474 | struct scrollinfo* s = NULL; | 473 | struct scrollinfo* s = NULL; |
475 | int i; | 474 | int i; |
@@ -477,93 +476,101 @@ static struct scrollinfo* find_scrolling_line(int line) | |||
477 | for(i=0; i<LCDFN(scroll_info).lines; i++) | 476 | for(i=0; i<LCDFN(scroll_info).lines; i++) |
478 | { | 477 | { |
479 | s = &LCDFN(scroll_info).scroll[i]; | 478 | s = &LCDFN(scroll_info).scroll[i]; |
480 | if (s->y == line && s->vp == current_vp) | 479 | if (s->x == x && s->y == y && s->vp == current_vp) |
481 | return s; | 480 | return s; |
482 | } | 481 | } |
483 | return NULL; | 482 | return NULL; |
484 | } | 483 | } |
485 | 484 | ||
486 | void LCDFN(puts_scroll_style_xyoffset)(int x, int y, const unsigned char *string, | 485 | void LCDFN(scroll_fn)(struct scrollinfo* s) |
487 | int style, int x_offset, int y_offset) | 486 | { |
487 | LCDFN(putsxyofs_style)(s->x, s->y, s->line, s->style, s->height, s->offset); | ||
488 | } | ||
489 | |||
490 | static void LCDFN(puts_scroll_worker)(int x, int y, const unsigned char *string, | ||
491 | int style, int x_offset, int y_offset, | ||
492 | bool linebased, | ||
493 | void (*scroll_func)(struct scrollinfo *), | ||
494 | void *data) | ||
488 | { | 495 | { |
489 | struct scrollinfo* s; | 496 | struct scrollinfo* s; |
490 | char *end; | 497 | int width, height; |
491 | int w, h; | 498 | int w, h, cwidth, margin; |
492 | int len; | 499 | bool restart; |
493 | bool restart = false; | ||
494 | int space_width; | ||
495 | 500 | ||
496 | if (!string || ((unsigned)y >= (unsigned)current_vp->height)) | 501 | if (!string) |
497 | return; | 502 | return; |
498 | 503 | ||
499 | s = find_scrolling_line(y); | 504 | /* prepare rectangle for scrolling. x and y must be calculated early |
500 | if (!s) | 505 | * for find_scrolling_line() to work */ |
501 | restart = true; | 506 | cwidth = font_get(current_vp->font)->maxwidth; |
507 | height = current_vp->line_height ?: (int)font_get(current_vp->font)->height; | ||
508 | y = y * (linebased ? height : 1) + y_offset; | ||
509 | x = x * (linebased ? cwidth : 1); | ||
510 | width = current_vp->width - x; | ||
502 | 511 | ||
503 | if (restart) | 512 | if (y >= current_vp->height) |
504 | { | 513 | return; |
514 | |||
515 | s = find_scrolling_line(x, y); | ||
516 | restart = !s; | ||
517 | |||
518 | if (restart) { | ||
505 | /* remove any previously scrolling line at the same location */ | 519 | /* remove any previously scrolling line at the same location */ |
506 | LCDFN(scroll_stop_viewport_line)(current_vp, y); | 520 | LCDFN(scroll_stop_viewport_rect)(current_vp, x, y, width, height); |
521 | LCDFN(putsxyofs_style)(x, y, string, style, height, x_offset); | ||
507 | 522 | ||
508 | if (LCDFN(scroll_info).lines >= LCDM(SCROLLABLE_LINES)) return; | 523 | if (LCDFN(scroll_info).lines >= LCDM(SCROLLABLE_LINES)) |
509 | LCDFN(puts_style_xyoffset)(x, y, string, style, x_offset, y_offset); | 524 | return; |
510 | } | 525 | } |
511 | 526 | ||
527 | /* get width (pixeks) of the string */ | ||
512 | LCDFN(getstringsize)(string, &w, &h); | 528 | LCDFN(getstringsize)(string, &w, &h); |
513 | 529 | ||
514 | if (current_vp->width - x * 8 >= w) | 530 | /* check if scrolling is actually necessary (consider the actual start |
531 | * of the line) */ | ||
532 | margin = x * linebased ? cwidth : 1; | ||
533 | if (current_vp->width >= margin+w) | ||
515 | return; | 534 | return; |
516 | 535 | ||
517 | if (restart) | 536 | if (restart) { |
518 | { | ||
519 | /* prepare scroll line */ | 537 | /* prepare scroll line */ |
520 | s = &LCDFN(scroll_info).scroll[LCDFN(scroll_info).lines]; | 538 | s = &LCDFN(scroll_info).scroll[LCDFN(scroll_info).lines]; |
521 | s->start_tick = current_tick + LCDFN(scroll_info).delay; | 539 | s->start_tick = current_tick + LCDFN(scroll_info).delay; |
522 | } | 540 | } |
523 | strlcpy(s->line, string, sizeof s->line); | ||
524 | space_width = LCDFN(getstringsize)(" ", NULL, NULL); | ||
525 | 541 | ||
526 | /* get width */ | 542 | /* copy contents to the line buffer */ |
527 | LCDFN(getstringsize)(s->line, &w, &h); | 543 | strlcpy(s->linebuffer, string, sizeof(s->linebuffer)); |
528 | if (!restart && s->width > w) | 544 | /* scroll bidirectional or forward only depending on the string width */ |
529 | { | ||
530 | if (s->startx > w) | ||
531 | s->startx = w; | ||
532 | } | ||
533 | s->width = w; | ||
534 | |||
535 | /* scroll bidirectional or forward only depending on the string | ||
536 | width */ | ||
537 | if ( LCDFN(scroll_info).bidir_limit ) { | 545 | if ( LCDFN(scroll_info).bidir_limit ) { |
538 | s->bidir = s->width < (current_vp->width) * | 546 | s->bidir = w < (current_vp->width) * |
539 | (100 + LCDFN(scroll_info).bidir_limit) / 100; | 547 | (100 + LCDFN(scroll_info).bidir_limit) / 100; |
540 | } | 548 | } |
541 | else | 549 | else |
542 | s->bidir = false; | 550 | s->bidir = false; |
543 | 551 | ||
544 | if (!s->bidir) { /* add spaces if scrolling in the round */ | 552 | s->scroll_func = scroll_func; |
545 | strlcat(s->line, " ", sizeof s->line); | 553 | s->userdata = data; |
546 | /* get new width incl. spaces */ | ||
547 | s->width += space_width * 3; | ||
548 | } | ||
549 | |||
550 | end = strchr(s->line, '\0'); | ||
551 | len = sizeof s->line - (end - s->line); | ||
552 | strlcpy(end, string, MIN(current_vp->width/2, len)); | ||
553 | 554 | ||
554 | s->vp = current_vp; | 555 | if (restart) { |
555 | s->y = y; | ||
556 | if (restart) | ||
557 | { | ||
558 | s->offset = x_offset; | 556 | s->offset = x_offset; |
559 | s->startx = x * space_width; | ||
560 | s->backward = false; | 557 | s->backward = false; |
561 | s->style = style; | 558 | s->style = style; |
559 | /* assign the rectangle. not necessary if continuing an earlier line */ | ||
560 | s->x = x; | ||
561 | s->y = y; | ||
562 | s->width = width; | ||
563 | s->height = height; | ||
564 | s->vp = current_vp; | ||
565 | LCDFN(scroll_info).lines++; | ||
562 | } | 566 | } |
563 | s->y_offset = y_offset; | 567 | } |
564 | 568 | ||
565 | if (restart) | 569 | void LCDFN(puts_scroll_style_xyoffset)(int x, int y, const unsigned char *string, |
566 | LCDFN(scroll_info).lines++; | 570 | int style, int x_offset, int y_offset) |
571 | { | ||
572 | LCDFN(puts_scroll_worker)(x, y, string, style, x_offset, y_offset, | ||
573 | true, LCDFN(scroll_fn), NULL); | ||
567 | } | 574 | } |
568 | 575 | ||
569 | void LCDFN(puts_scroll)(int x, int y, const unsigned char *string) | 576 | void LCDFN(puts_scroll)(int x, int y, const unsigned char *string) |
@@ -583,65 +590,6 @@ void LCDFN(puts_scroll_offset)(int x, int y, const unsigned char *string, | |||
583 | LCDFN(puts_scroll_style_offset)(x, y, string, STYLE_DEFAULT, offset); | 590 | LCDFN(puts_scroll_style_offset)(x, y, string, STYLE_DEFAULT, offset); |
584 | } | 591 | } |
585 | 592 | ||
586 | void LCDFN(scroll_fn)(void) | ||
587 | { | ||
588 | struct scrollinfo* s; | ||
589 | int index; | ||
590 | int xpos, ypos, height; | ||
591 | struct viewport* old_vp = current_vp; | ||
592 | bool makedelay; | ||
593 | |||
594 | for ( index = 0; index < LCDFN(scroll_info).lines; index++ ) { | ||
595 | s = &LCDFN(scroll_info).scroll[index]; | ||
596 | |||
597 | /* check pause */ | ||
598 | if (TIME_BEFORE(current_tick, s->start_tick)) | ||
599 | continue; | ||
600 | |||
601 | LCDFN(set_viewport)(s->vp); | ||
602 | height = s->vp->line_height ?: (int)font_get(s->vp->font)->height; | ||
603 | |||
604 | if (s->backward) | ||
605 | s->offset -= LCDFN(scroll_info).step; | ||
606 | else | ||
607 | s->offset += LCDFN(scroll_info).step; | ||
608 | |||
609 | xpos = s->startx; | ||
610 | ypos = s->y * height + s->y_offset; | ||
611 | |||
612 | makedelay = false; | ||
613 | if (s->bidir) { /* scroll bidirectional */ | ||
614 | if (s->offset <= 0) { | ||
615 | /* at beginning of line */ | ||
616 | s->offset = 0; | ||
617 | s->backward = false; | ||
618 | makedelay = true; | ||
619 | } | ||
620 | else if (s->offset >= s->width - (current_vp->width - xpos)) { | ||
621 | /* at end of line */ | ||
622 | s->offset = s->width - (current_vp->width - xpos); | ||
623 | s->backward = true; | ||
624 | makedelay = true; | ||
625 | } | ||
626 | } | ||
627 | else { | ||
628 | /* scroll forward the whole time */ | ||
629 | if (s->offset >= s->width) { | ||
630 | s->offset = 0; | ||
631 | makedelay = true; | ||
632 | } | ||
633 | } | ||
634 | |||
635 | if (makedelay) | ||
636 | s->start_tick = current_tick + LCDFN(scroll_info).delay + | ||
637 | LCDFN(scroll_info).ticks; | ||
638 | |||
639 | LCDFN(putsxyofs_style)(xpos, ypos, s->line, s->style, height, s->offset); | ||
640 | LCDFN(update_viewport_rect)(xpos, ypos, current_vp->width-xpos, height); | ||
641 | } | ||
642 | LCDFN(set_viewport)(old_vp); | ||
643 | } | ||
644 | |||
645 | void LCDFN(puts_scroll_style_offset)(int x, int y, const unsigned char *string, | 593 | void LCDFN(puts_scroll_style_offset)(int x, int y, const unsigned char *string, |
646 | int style, int x_offset) | 594 | int style, int x_offset) |
647 | { | 595 | { |
diff --git a/firmware/drivers/lcd-scroll.c b/firmware/drivers/lcd-scroll.c index ffd4663c79..31c2cf20b0 100644 --- a/firmware/drivers/lcd-scroll.c +++ b/firmware/drivers/lcd-scroll.c | |||
@@ -54,30 +54,27 @@ void LCDFN(scroll_stop)(void) | |||
54 | LCDFN(scroll_info).lines = 0; | 54 | LCDFN(scroll_info).lines = 0; |
55 | } | 55 | } |
56 | 56 | ||
57 | /* Stop scrolling line y in the specified viewport, or all lines if y < 0 */ | 57 | /* Clears scrolling lines that intersect with the area */ |
58 | void LCDFN(scroll_stop_viewport_line)(const struct viewport *current_vp, int line) | 58 | void LCDFN(scroll_stop_viewport_rect)(const struct viewport *vp, int x, int y, int width, int height) |
59 | { | 59 | { |
60 | int i = 0; | 60 | int i = 0; |
61 | |||
62 | while (i < LCDFN(scroll_info).lines) | 61 | while (i < LCDFN(scroll_info).lines) |
63 | { | 62 | { |
64 | struct viewport *vp = LCDFN(scroll_info).scroll[i].vp; | 63 | struct scrollinfo *s = &LCDFN(scroll_info).scroll[i]; |
65 | if (((vp == current_vp)) && | 64 | /* check if the specified area crosses the viewport in some way */ |
66 | ((line < 0) || (LCDFN(scroll_info).scroll[i].y == line))) | 65 | if (s->vp == vp |
66 | && (x < (s->x+s->width) && (x+width) >= s->x) | ||
67 | && (y < (s->y+s->height) && (y+height) >= s->y)) | ||
67 | { | 68 | { |
68 | /* If i is not the last active line in the array, then move | 69 | /* If i is not the last active line in the array, then move |
69 | the last item to position i */ | 70 | the last item to position i. This compacts |
71 | the scroll array at the same time of removing the line */ | ||
70 | if ((i + 1) != LCDFN(scroll_info).lines) | 72 | if ((i + 1) != LCDFN(scroll_info).lines) |
71 | { | 73 | { |
72 | LCDFN(scroll_info).scroll[i] = | 74 | LCDFN(scroll_info).scroll[i] = |
73 | LCDFN(scroll_info).scroll[LCDFN(scroll_info).lines-1]; | 75 | LCDFN(scroll_info).scroll[LCDFN(scroll_info).lines-1]; |
74 | } | 76 | } |
75 | LCDFN(scroll_info).lines--; | 77 | LCDFN(scroll_info).lines--; |
76 | |||
77 | /* A line can only appear once, so we're done, | ||
78 | * unless we are clearing the whole viewport */ | ||
79 | if (line >= 0) | ||
80 | return ; | ||
81 | } | 78 | } |
82 | else | 79 | else |
83 | { | 80 | { |
@@ -87,9 +84,9 @@ void LCDFN(scroll_stop_viewport_line)(const struct viewport *current_vp, int lin | |||
87 | } | 84 | } |
88 | 85 | ||
89 | /* Stop all scrolling lines in the specified viewport */ | 86 | /* Stop all scrolling lines in the specified viewport */ |
90 | void LCDFN(scroll_stop_viewport)(const struct viewport *current_vp) | 87 | void LCDFN(scroll_stop_viewport)(const struct viewport *vp) |
91 | { | 88 | { |
92 | LCDFN(scroll_stop_viewport_line)(current_vp, -1); | 89 | LCDFN(scroll_stop_viewport_rect)(vp, 0, 0, vp->width, vp->height); |
93 | } | 90 | } |
94 | 91 | ||
95 | void LCDFN(scroll_speed)(int speed) | 92 | void LCDFN(scroll_speed)(int speed) |
@@ -125,3 +122,89 @@ void LCDFN(jump_scroll_delay)(int ms) | |||
125 | LCDFN(scroll_info).jump_scroll_delay = ms / (HZ / 10); | 122 | LCDFN(scroll_info).jump_scroll_delay = ms / (HZ / 10); |
126 | } | 123 | } |
127 | #endif | 124 | #endif |
125 | |||
126 | static void LCDFN(scroll_worker)(void) | ||
127 | { | ||
128 | int index, width; | ||
129 | bool makedelay; | ||
130 | static char line_buf[SCROLL_LINE_SIZE]; | ||
131 | bool is_default; | ||
132 | struct scroll_screen_info *si = &LCDFN(scroll_info); | ||
133 | struct scrollinfo *s; | ||
134 | struct viewport *vp; | ||
135 | |||
136 | unsigned fg_pattern, bg_pattern, drawmode; | ||
137 | |||
138 | for ( index = 0; index < si->lines; index++ ) { | ||
139 | s = &si->scroll[index]; | ||
140 | |||
141 | /* check pause */ | ||
142 | if (TIME_BEFORE(current_tick, s->start_tick)) | ||
143 | continue; | ||
144 | |||
145 | s->start_tick = current_tick; | ||
146 | |||
147 | /* this runs out of the ui thread, thus we need to | ||
148 | * save and restore the current viewport since the ui thread | ||
149 | * is unaware of the swapped viewports. the vp must | ||
150 | * be switched early so that lcd_getstringsize() picks the | ||
151 | * correct font */ | ||
152 | vp = LCDFN(get_viewport)(&is_default); | ||
153 | LCDFN(set_viewport)(s->vp); | ||
154 | |||
155 | width = LCDFN(getstringsize)(s->linebuffer, NULL, NULL); | ||
156 | makedelay = false; | ||
157 | |||
158 | if (s->backward) | ||
159 | s->offset -= si->step; | ||
160 | else | ||
161 | s->offset += si->step; | ||
162 | |||
163 | if (s->bidir) { /* scroll bidirectional */ | ||
164 | |||
165 | s->line = s->linebuffer; | ||
166 | if (s->offset <= 0) { | ||
167 | /* at beginning of line */ | ||
168 | s->offset = 0; | ||
169 | s->backward = false; | ||
170 | makedelay = true; | ||
171 | } | ||
172 | else if (s->offset >= width - (s->width - s->x)) { | ||
173 | /* at end of line */ | ||
174 | s->offset = width - (s->width - s->x); | ||
175 | s->backward = true; | ||
176 | makedelay = true; | ||
177 | } | ||
178 | } | ||
179 | else { | ||
180 | |||
181 | snprintf(line_buf, sizeof(line_buf)-1, "%s%s%s", | ||
182 | s->linebuffer, " ", s->linebuffer); | ||
183 | s->line = line_buf; | ||
184 | width += LCDFN(getstringsize)(" ", NULL, NULL); | ||
185 | /* scroll forward the whole time */ | ||
186 | if (s->offset >= width) { | ||
187 | s->offset = 0; | ||
188 | makedelay = true; | ||
189 | } | ||
190 | } | ||
191 | |||
192 | /* Stash and restore these three, so that the scroll_func | ||
193 | * can do whatever it likes without destroying the state */ | ||
194 | fg_pattern = s->vp->fg_pattern; | ||
195 | bg_pattern = s->vp->bg_pattern; | ||
196 | drawmode = s->vp->drawmode; | ||
197 | |||
198 | s->scroll_func(s); | ||
199 | LCDFN(update_viewport_rect)(s->x, s->y, s->width, s->height); | ||
200 | |||
201 | s->vp->fg_pattern = fg_pattern; | ||
202 | s->vp->bg_pattern = bg_pattern; | ||
203 | s->vp->drawmode = drawmode; | ||
204 | |||
205 | LCDFN(set_viewport)(vp); | ||
206 | |||
207 | if (makedelay) | ||
208 | s->start_tick += si->delay + si->ticks; | ||
209 | } | ||
210 | } | ||
diff --git a/firmware/export/scroll_engine.h b/firmware/export/scroll_engine.h index 01a9a5e33d..c7eb97aecc 100644 --- a/firmware/export/scroll_engine.h +++ b/firmware/export/scroll_engine.h | |||
@@ -37,19 +37,19 @@ extern void lcd_scroll_delay(int ms); | |||
37 | 37 | ||
38 | extern void lcd_scroll_stop(void); | 38 | extern void lcd_scroll_stop(void); |
39 | extern void lcd_scroll_stop_viewport(const struct viewport *vp); | 39 | extern void lcd_scroll_stop_viewport(const struct viewport *vp); |
40 | extern void lcd_scroll_stop_viewport_line(const struct viewport *vp, int line); | 40 | extern void lcd_scroll_stop_viewport_rect(const struct viewport *vp, int x, int y, int width, int height); |
41 | extern void lcd_scroll_fn(void); | ||
42 | #ifdef HAVE_REMOTE_LCD | 41 | #ifdef HAVE_REMOTE_LCD |
43 | extern void lcd_remote_scroll_speed(int speed); | 42 | extern void lcd_remote_scroll_speed(int speed); |
44 | extern void lcd_remote_scroll_delay(int ms); | 43 | extern void lcd_remote_scroll_delay(int ms); |
45 | 44 | ||
46 | extern void lcd_remote_scroll_stop(void); | 45 | extern void lcd_remote_scroll_stop(void); |
47 | extern void lcd_remote_scroll_stop_viewport(const struct viewport *vp); | 46 | extern void lcd_remote_scroll_stop_viewport(const struct viewport *vp); |
48 | extern void lcd_remote_scroll_stop_viewport_line(const struct viewport *vp, int line); | 47 | extern void lcd_remote_scroll_stop_viewport_rect(const struct viewport *vp, int x, int y, int width, int height); |
49 | extern void lcd_remote_scroll_fn(void); | ||
50 | #endif | 48 | #endif |
51 | 49 | ||
52 | /* internal usage, but in multiple drivers */ | 50 | /* internal usage, but in multiple drivers |
51 | * larger than the normal linebuffer since it holds the line a second | ||
52 | * time (+3 spaces) for non-bidir scrolling */ | ||
53 | #define SCROLL_SPACING 3 | 53 | #define SCROLL_SPACING 3 |
54 | #ifdef HAVE_LCD_BITMAP | 54 | #ifdef HAVE_LCD_BITMAP |
55 | #define SCROLL_LINE_SIZE (MAX_PATH + SCROLL_SPACING + 3*LCD_WIDTH/2 + 2) | 55 | #define SCROLL_LINE_SIZE (MAX_PATH + SCROLL_SPACING + 3*LCD_WIDTH/2 + 2) |
@@ -60,21 +60,27 @@ extern void lcd_remote_scroll_fn(void); | |||
60 | struct scrollinfo | 60 | struct scrollinfo |
61 | { | 61 | { |
62 | struct viewport* vp; | 62 | struct viewport* vp; |
63 | char line[SCROLL_LINE_SIZE]; | 63 | char linebuffer[9*MAX_PATH/10]; |
64 | const char *line; | ||
64 | #ifdef HAVE_LCD_CHARCELLS | 65 | #ifdef HAVE_LCD_CHARCELLS |
65 | int len; /* length of line in chars */ | 66 | int len; /* length of line in chars */ |
66 | #endif | 67 | #endif |
67 | int y; /* Position of the line on the screen (char co-ordinates) */ | 68 | /* rectangle for the line */ |
69 | int x, y; /* relative to the viewort */ | ||
70 | int width, height; | ||
71 | /* pixel to skip from the beginning of the string, increments as the text scrolls */ | ||
68 | int offset; | 72 | int offset; |
69 | int startx; | ||
70 | int y_offset; /* y offset of the line, used for pixel-accurate list scrolling */ | ||
71 | #ifdef HAVE_LCD_BITMAP | 73 | #ifdef HAVE_LCD_BITMAP |
72 | int width; /* length of line in pixels */ | ||
73 | int style; /* line style */ | 74 | int style; /* line style */ |
74 | #endif/* HAVE_LCD_BITMAP */ | 75 | #endif /* HAVE_LCD_BITMAP */ |
75 | bool backward; /* scroll presently forward or backward? */ | 76 | /* scroll presently forward or backward? */ |
77 | bool backward; | ||
76 | bool bidir; | 78 | bool bidir; |
77 | long start_tick; | 79 | long start_tick; |
80 | |||
81 | /* support for custom scrolling functions */ | ||
82 | void (*scroll_func)(struct scrollinfo *s); | ||
83 | void *userdata; | ||
78 | }; | 84 | }; |
79 | 85 | ||
80 | struct scroll_screen_info | 86 | struct scroll_screen_info |
diff --git a/firmware/scroll_engine.c b/firmware/scroll_engine.c index d134f7b2ce..d1bc2976a1 100644 --- a/firmware/scroll_engine.c +++ b/firmware/scroll_engine.c | |||
@@ -23,6 +23,7 @@ | |||
23 | * | 23 | * |
24 | ****************************************************************************/ | 24 | ****************************************************************************/ |
25 | 25 | ||
26 | #include <stdio.h> | ||
26 | #include "config.h" | 27 | #include "config.h" |
27 | #include "gcc_extensions.h" | 28 | #include "gcc_extensions.h" |
28 | #include "cpu.h" | 29 | #include "cpu.h" |
@@ -36,16 +37,20 @@ | |||
36 | #endif | 37 | #endif |
37 | #include "scroll_engine.h" | 38 | #include "scroll_engine.h" |
38 | 39 | ||
40 | |||
41 | /* private helper function for the scroll engine. Do not use in apps/. | ||
42 | * defined in lcd-bitmap-common.c */ | ||
43 | extern struct viewport *lcd_get_viewport(bool *is_defaut); | ||
44 | #ifdef HAVE_REMOTE_LCD | ||
45 | extern struct viewport *lcd_remote_get_viewport(bool *is_defaut); | ||
46 | #endif | ||
47 | |||
39 | static const char scroll_tick_table[18] = { | 48 | static const char scroll_tick_table[18] = { |
40 | /* Hz values [f(x)=100.8/(x+.048)]: | 49 | /* Hz values [f(x)=100.8/(x+.048)]: |
41 | 1, 1.25, 1.55, 2, 2.5, 3.12, 4, 5, 6.25, 8.33, 10, 12.5, 16.7, 20, 25, 33, 49.2, 96.2 */ | 50 | 1, 1.25, 1.55, 2, 2.5, 3.12, 4, 5, 6.25, 8.33, 10, 12.5, 16.7, 20, 25, 33, 49.2, 96.2 */ |
42 | 100, 80, 64, 50, 40, 32, 25, 20, 16, 12, 10, 8, 6, 5, 4, 3, 2, 1 | 51 | 100, 80, 64, 50, 40, 32, 25, 20, 16, 12, 10, 8, 6, 5, 4, 3, 2, 1 |
43 | }; | 52 | }; |
44 | 53 | ||
45 | /* imported private functions from lcd-bitmap-common.c */ | ||
46 | extern struct viewport *lcd_get_viewport(void); | ||
47 | extern struct viewport *lcd_remote_get_viewport(void); | ||
48 | |||
49 | static void scroll_thread(void); | 54 | static void scroll_thread(void); |
50 | static char scroll_stack[DEFAULT_STACK_SIZE*3]; | 55 | static char scroll_stack[DEFAULT_STACK_SIZE*3]; |
51 | static const char scroll_name[] = "scroll"; | 56 | static const char scroll_name[] = "scroll"; |
@@ -156,7 +161,7 @@ static void scroll_thread(void) | |||
156 | #if defined(HAVE_LCD_ENABLE) || defined(HAVE_LCD_SLEEP) | 161 | #if defined(HAVE_LCD_ENABLE) || defined(HAVE_LCD_SLEEP) |
157 | if (lcd_active()) | 162 | if (lcd_active()) |
158 | #endif | 163 | #endif |
159 | lcd_scroll_fn(); | 164 | lcd_scroll_worker(); |
160 | lcd_scroll_info.last_scroll = current_tick; | 165 | lcd_scroll_info.last_scroll = current_tick; |
161 | } | 166 | } |
162 | 167 | ||
@@ -165,7 +170,7 @@ static void scroll_thread(void) | |||
165 | 170 | ||
166 | if (scroll & SCROLL_LCD_REMOTE) | 171 | if (scroll & SCROLL_LCD_REMOTE) |
167 | { | 172 | { |
168 | lcd_remote_scroll_fn(); | 173 | lcd_remote_scroll_worker(); |
169 | lcd_remote_scroll_info.last_scroll = current_tick; | 174 | lcd_remote_scroll_info.last_scroll = current_tick; |
170 | } | 175 | } |
171 | } | 176 | } |
@@ -179,7 +184,7 @@ static void scroll_thread(void) | |||
179 | #if defined(HAVE_LCD_ENABLE) || defined(HAVE_LCD_SLEEP) | 184 | #if defined(HAVE_LCD_ENABLE) || defined(HAVE_LCD_SLEEP) |
180 | if (lcd_active()) | 185 | if (lcd_active()) |
181 | #endif | 186 | #endif |
182 | lcd_scroll_fn(); | 187 | lcd_scroll_worker(); |
183 | } | 188 | } |
184 | } | 189 | } |
185 | #endif /* HAVE_REMOTE_LCD */ | 190 | #endif /* HAVE_REMOTE_LCD */ |