summaryrefslogtreecommitdiff
path: root/firmware/drivers/lcd-bitmap-common.c
diff options
context:
space:
mode:
authorThomas Martitz <kugel@rockbox.org>2013-01-31 07:24:19 +0100
committerThomas Martitz <kugel@rockbox.org>2013-12-14 23:11:31 +0100
commit50eb528bc1f9d2f7b7260eff8b85a5ed5b96e679 (patch)
tree47b53d62c0880a3ea6b9e761efdf0628855d13e0 /firmware/drivers/lcd-bitmap-common.c
parent26801b3bd8f11fe680146086aa0a2fd12e7de289 (diff)
downloadrockbox-50eb528bc1f9d2f7b7260eff8b85a5ed5b96e679.tar.gz
rockbox-50eb528bc1f9d2f7b7260eff8b85a5ed5b96e679.zip
scroll_engine: Major rework to support pixel-based scrolling and scroll callbacks.
Much of the scrolling work is moved from lcd-bitmap-common to lcd-scroll.c, a small scroll callback routine remains. This callback can potentially be overridden by more extensive scrollers. The callback also gets fed with pixel-based scrolling information, which finally removes the strict line-based nature of the scroll engine. Along with this is the change from scroll_stop_viewport_line() to scroll_stop_viewport_rect() which works on a pixel-based rectangle instead of lines. The ultimate goal is to move most of the scroll work to apps, which can much better decide which line decorations to apply etc. This work is laying the ground work. Change-Id: I3b2885cf7d8696ddd9253d5a9a73318d3d42831a
Diffstat (limited to 'firmware/drivers/lcd-bitmap-common.c')
-rw-r--r--firmware/drivers/lcd-bitmap-common.c180
1 files changed, 64 insertions, 116 deletions
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 */
416void LCDFN(puts_style_xyoffset)(int x, int y, const unsigned char *str, 415void 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
438void LCDFN(puts_style_offset)(int x, int y, const unsigned char *str, 437void 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
472static struct scrollinfo* find_scrolling_line(int line) 471static 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
486void LCDFN(puts_scroll_style_xyoffset)(int x, int y, const unsigned char *string, 485void 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
490static 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) 569void 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
569void LCDFN(puts_scroll)(int x, int y, const unsigned char *string) 576void 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
586void 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
645void LCDFN(puts_scroll_style_offset)(int x, int y, const unsigned char *string, 593void 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{