summaryrefslogtreecommitdiff
path: root/firmware/drivers/lcd-bitmap-common.c
diff options
context:
space:
mode:
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{