diff options
Diffstat (limited to 'firmware/drivers/lcd-bitmap-common.c')
-rw-r--r-- | firmware/drivers/lcd-bitmap-common.c | 180 |
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, /*** Line oriented text output ***/ -/* put a string at a given char position */ void LCDFN(puts_style_xyoffset)(int x, int y, const unsigned char *str, int style, int x_offset, int y_offset) { int xpos, ypos, h; - LCDFN(scroll_stop_viewport_line)(current_vp, y); if(!str) return; @@ -425,14 +423,15 @@ void LCDFN(puts_style_xyoffset)(int x, int y, const unsigned char *str, if ((style&STYLE_XY_PIXELS) == 0) { xpos = x * LCDFN(getstringsize)(" ", NULL, NULL); - ypos = y * h + y_offset; + ypos = y * h; } else { xpos = x; - ypos = y + y_offset; + ypos = y; } - LCDFN(putsxyofs_style)(xpos, ypos, str, style, h, x_offset); + LCDFN(scroll_stop_viewport_rect)(current_vp, x, y, current_vp->width - x, h); + LCDFN(putsxyofs_style)(xpos, ypos+y_offset, str, style, h, x_offset); } 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) /*** scrolling ***/ -static struct scrollinfo* find_scrolling_line(int line) +static struct scrollinfo* find_scrolling_line(int x, int y) { struct scrollinfo* s = NULL; int i; @@ -477,93 +476,101 @@ static struct scrollinfo* find_scrolling_line(int line) for(i=0; i<LCDFN(scroll_info).lines; i++) { s = &LCDFN(scroll_info).scroll[i]; - if (s->y == line && s->vp == current_vp) + if (s->x == x && s->y == y && s->vp == current_vp) return s; } return NULL; } -void LCDFN(puts_scroll_style_xyoffset)(int x, int y, const unsigned char *string, - int style, int x_offset, int y_offset) +void LCDFN(scroll_fn)(struct scrollinfo* s) +{ + LCDFN(putsxyofs_style)(s->x, s->y, s->line, s->style, s->height, s->offset); +} + +static void LCDFN(puts_scroll_worker)(int x, int y, const unsigned char *string, + int style, int x_offset, int y_offset, + bool linebased, + void (*scroll_func)(struct scrollinfo *), + void *data) { struct scrollinfo* s; - char *end; - int w, h; - int len; - bool restart = false; - int space_width; + int width, height; + int w, h, cwidth, margin; + bool restart; - if (!string || ((unsigned)y >= (unsigned)current_vp->height)) + if (!string) return; - s = find_scrolling_line(y); - if (!s) - restart = true; + /* prepare rectangle for scrolling. x and y must be calculated early + * for find_scrolling_line() to work */ + cwidth = font_get(current_vp->font)->maxwidth; + height = current_vp->line_height ?: (int)font_get(current_vp->font)->height; + y = y * (linebased ? height : 1) + y_offset; + x = x * (linebased ? cwidth : 1); + width = current_vp->width - x; - if (restart) - { + if (y >= current_vp->height) + return; + + s = find_scrolling_line(x, y); + restart = !s; + + if (restart) { /* remove any previously scrolling line at the same location */ - LCDFN(scroll_stop_viewport_line)(current_vp, y); + LCDFN(scroll_stop_viewport_rect)(current_vp, x, y, width, height); + LCDFN(putsxyofs_style)(x, y, string, style, height, x_offset); - if (LCDFN(scroll_info).lines >= LCDM(SCROLLABLE_LINES)) return; - LCDFN(puts_style_xyoffset)(x, y, string, style, x_offset, y_offset); + if (LCDFN(scroll_info).lines >= LCDM(SCROLLABLE_LINES)) + return; } + /* get width (pixeks) of the string */ LCDFN(getstringsize)(string, &w, &h); - if (current_vp->width - x * 8 >= w) + /* check if scrolling is actually necessary (consider the actual start + * of the line) */ + margin = x * linebased ? cwidth : 1; + if (current_vp->width >= margin+w) return; - if (restart) - { + if (restart) { /* prepare scroll line */ s = &LCDFN(scroll_info).scroll[LCDFN(scroll_info).lines]; s->start_tick = current_tick + LCDFN(scroll_info).delay; } - strlcpy(s->line, string, sizeof s->line); - space_width = LCDFN(getstringsize)(" ", NULL, NULL); - /* get width */ - LCDFN(getstringsize)(s->line, &w, &h); - if (!restart && s->width > w) - { - if (s->startx > w) - s->startx = w; - } - s->width = w; - - /* scroll bidirectional or forward only depending on the string - width */ + /* copy contents to the line buffer */ + strlcpy(s->linebuffer, string, sizeof(s->linebuffer)); + /* scroll bidirectional or forward only depending on the string width */ if ( LCDFN(scroll_info).bidir_limit ) { - s->bidir = s->width < (current_vp->width) * + s->bidir = w < (current_vp->width) * (100 + LCDFN(scroll_info).bidir_limit) / 100; } else s->bidir = false; - if (!s->bidir) { /* add spaces if scrolling in the round */ - strlcat(s->line, " ", sizeof s->line); - /* get new width incl. spaces */ - s->width += space_width * 3; - } - - end = strchr(s->line, '\0'); - len = sizeof s->line - (end - s->line); - strlcpy(end, string, MIN(current_vp->width/2, len)); + s->scroll_func = scroll_func; + s->userdata = data; - s->vp = current_vp; - s->y = y; - if (restart) - { + if (restart) { s->offset = x_offset; - s->startx = x * space_width; s->backward = false; s->style = style; + /* assign the rectangle. not necessary if continuing an earlier line */ + s->x = x; + s->y = y; + s->width = width; + s->height = height; + s->vp = current_vp; + LCDFN(scroll_info).lines++; } - s->y_offset = y_offset; +} - if (restart) - LCDFN(scroll_info).lines++; +void LCDFN(puts_scroll_style_xyoffset)(int x, int y, const unsigned char *string, + int style, int x_offset, int y_offset) +{ + LCDFN(puts_scroll_worker)(x, y, string, style, x_offset, y_offset, + true, LCDFN(scroll_fn), NULL); } 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, LCDFN(puts_scroll_style_offset)(x, y, string, STYLE_DEFAULT, offset); } -void LCDFN(scroll_fn)(void) -{ - struct scrollinfo* s; - int index; - int xpos, ypos, height; - struct viewport* old_vp = current_vp; - bool makedelay; - - for ( index = 0; index < LCDFN(scroll_info).lines; index++ ) { - s = &LCDFN(scroll_info).scroll[index]; - - /* check pause */ - if (TIME_BEFORE(current_tick, s->start_tick)) - continue; - - LCDFN(set_viewport)(s->vp); - height = s->vp->line_height ?: (int)font_get(s->vp->font)->height; - - if (s->backward) - s->offset -= LCDFN(scroll_info).step; - else - s->offset += LCDFN(scroll_info).step; - - xpos = s->startx; - ypos = s->y * height + s->y_offset; - - makedelay = false; - if (s->bidir) { /* scroll bidirectional */ - if (s->offset <= 0) { - /* at beginning of line */ - s->offset = 0; - s->backward = false; - makedelay = true; - } - else if (s->offset >= s->width - (current_vp->width - xpos)) { - /* at end of line */ - s->offset = s->width - (current_vp->width - xpos); - s->backward = true; - makedelay = true; - } - } - else { - /* scroll forward the whole time */ - if (s->offset >= s->width) { - s->offset = 0; - makedelay = true; - } - } - - if (makedelay) - s->start_tick = current_tick + LCDFN(scroll_info).delay + - LCDFN(scroll_info).ticks; - - LCDFN(putsxyofs_style)(xpos, ypos, s->line, s->style, height, s->offset); - LCDFN(update_viewport_rect)(xpos, ypos, current_vp->width-xpos, height); - } - LCDFN(set_viewport)(old_vp); -} - void LCDFN(puts_scroll_style_offset)(int x, int y, const unsigned char *string, int style, int x_offset) { |