diff --git a/firmware/drivers/lcd-2bit-vert.c b/firmware/drivers/lcd-2bit-vert.c index 08ec6cac79..501e568a69 100644 --- a/firmware/drivers/lcd-2bit-vert.c +++ b/firmware/drivers/lcd-2bit-vert.c @@ -387,7 +387,7 @@ void lcd_clear_viewport(void) current_vp->drawmode = lastmode; - lcd_scroll_stop(current_vp); + lcd_scroll_stop_viewport(current_vp); } } diff --git a/firmware/drivers/lcd-charcell.c b/firmware/drivers/lcd-charcell.c index bdd02de1b6..db867cdb0a 100644 --- a/firmware/drivers/lcd-charcell.c +++ b/firmware/drivers/lcd-charcell.c @@ -110,11 +110,26 @@ void lcd_set_viewport(struct viewport* vp) #endif } +struct viewport *lcd_get_viewport(bool *is_default) +{ + *is_default = (current_vp == &default_vp); + return current_vp; +} + void lcd_update_viewport(void) { lcd_update(); } +void lcd_update_viewport_rect(int x, int y, int width, int height) +{ + (void) x; + (void) y; + (void) width; + (void) height; + lcd_update(); +} + /** parameter handling **/ int lcd_getwidth(void) @@ -486,7 +501,7 @@ void lcd_puts_offset(int x, int y, const unsigned char *str, int offset) return; /* make sure scrolling is turned off on the line we are updating */ - lcd_scroll_stop_viewport_line(current_vp, y); + lcd_scroll_stop_viewport_rect(current_vp, x, y, current_vp->width - x, 1); x = lcd_putsxyofs(x, y, offset, str); while (x < current_vp->width) @@ -499,8 +514,9 @@ void lcd_puts_scroll(int x, int y, const unsigned char *string) lcd_puts_scroll_offset(x, y, string, 0); } -void lcd_puts_scroll_offset(int x, int y, const unsigned char *string, - int offset) +void lcd_puts_scroll_worker(int x, int y, const unsigned char *string, + int offset, + void (*scroll_func)(struct scrollinfo *), void *data) { struct scrollinfo* s; int len; @@ -509,7 +525,7 @@ void lcd_puts_scroll_offset(int x, int y, const unsigned char *string, return; /* remove any previously scrolling line at the same location */ - lcd_scroll_stop_viewport_line(current_vp, y); + lcd_scroll_stop_viewport_rect(current_vp, x, y, current_vp->width - x, 1); if (lcd_scroll_info.lines >= LCD_SCROLLABLE_LINES) return; @@ -520,120 +536,48 @@ void lcd_puts_scroll_offset(int x, int y, const unsigned char *string, lcd_puts_offset(x, y, string, offset); len = utf8length(string); - if (current_vp->width - x < len) + if (current_vp->width - x >= len) + return; + /* prepare scroll line */ + strlcpy(s->linebuffer, string, sizeof s->linebuffer); + + /* scroll bidirectional or forward only depending on the string width */ + if (lcd_scroll_info.bidir_limit) { - /* prepare scroll line */ - char *end; - int count; - - memset(s->line, 0, sizeof s->line); - strlcpy(s->line, string, sizeof s->line); - - /* get width */ - s->len = utf8length(s->line); - - /* scroll bidirectional or forward only depending on the string width */ - if (lcd_scroll_info.bidir_limit) - { - s->bidir = s->len < (current_vp->width) * - (100 + lcd_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->len += SCROLL_SPACING; - } - - end = strchr(s->line, '\0'); - len = sizeof s->line - (end - s->line); - count = utf8seek(s->line, current_vp->width); - strlcpy(end, string, MIN(count, len)); - - s->vp = current_vp; - s->y = y; - s->offset = offset; - s->startx = x; - s->backward = false; - lcd_scroll_info.lines++; + s->bidir = len < (current_vp->width) * + (100 + lcd_scroll_info.bidir_limit) / 100; } + else + s->bidir = false; + + s->scroll_func = scroll_func; + s->userdata = data; + + s->vp = current_vp; + s->x = x; + s->y = y; + s->height = 1; + s->width = current_vp->width - x; + s->offset = offset; + s->backward = false; + lcd_scroll_info.lines++; } -void lcd_scroll_fn(void) +void lcd_scroll_fn(struct scrollinfo* s) { - struct scrollinfo* s; - int index; - int xpos, ypos; - bool update; - struct viewport* old_vp = current_vp; - bool makedelay; - - update = false; - for ( index = 0; index < lcd_scroll_info.lines; index++ ) { - s = &lcd_scroll_info.scroll[index]; - - /* check pause */ - if (TIME_BEFORE(current_tick, s->start_tick)) - continue; - - lcd_set_viewport(s->vp); - - if (s->backward) - s->offset--; - else - s->offset++; - - xpos = s->startx; - ypos = s->y; - - 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->len - (current_vp->width - xpos)) { - /* at end of line */ - s->offset = s->len - (current_vp->width - xpos); - s->backward = true; - makedelay = true; - } - } - else /* scroll forward the whole time */ - { - if (s->offset >= s->len) { - s->offset = 0; - makedelay = true; - } - } - - if (makedelay) - s->start_tick = current_tick + lcd_scroll_info.delay + - lcd_scroll_info.ticks; - - lcd_putsxyofs(xpos, ypos, s->offset, s->line); - update = true; - } - - lcd_set_viewport(old_vp); - + lcd_putsxyofs(s->x, s->y, s->offset, s->line); if (lcd_cursor.enabled) { if (--lcd_cursor.downcount <= 0) { lcd_cursor.downcount = lcd_cursor.divider; lcd_cursor.visible = !lcd_cursor.visible; - update = true; } } - - if (update) - lcd_update(); } +void lcd_puts_scroll_offset(int x, int y, const unsigned char *string, + int offset) +{ + lcd_puts_scroll_worker(x, y, string, offset, lcd_scroll_fn, NULL); +} diff --git a/firmware/drivers/lcd-scroll.c b/firmware/drivers/lcd-scroll.c index 31c2cf20b0..d524ce81c8 100644 --- a/firmware/drivers/lcd-scroll.c +++ b/firmware/drivers/lcd-scroll.c @@ -132,10 +132,10 @@ static void LCDFN(scroll_worker)(void) struct scroll_screen_info *si = &LCDFN(scroll_info); struct scrollinfo *s; struct viewport *vp; + int step; - unsigned fg_pattern, bg_pattern, drawmode; - - for ( index = 0; index < si->lines; index++ ) { + for ( index = 0; index < si->lines; index++ ) + { s = &si->scroll[index]; /* check pause */ @@ -154,14 +154,19 @@ static void LCDFN(scroll_worker)(void) width = LCDFN(getstringsize)(s->linebuffer, NULL, NULL); makedelay = false; - +#ifdef HAVE_LCD_BITMAP + step = si->step; +#else + step = 1; +#endif + if (s->backward) - s->offset -= si->step; + s->offset -= step; else - s->offset += si->step; - - if (s->bidir) { /* scroll bidirectional */ + s->offset += step; + if (s->bidir) + { /* scroll bidirectional */ s->line = s->linebuffer; if (s->offset <= 0) { /* at beginning of line */ @@ -169,15 +174,15 @@ static void LCDFN(scroll_worker)(void) s->backward = false; makedelay = true; } - else if (s->offset >= width - (s->width - s->x)) { + else if (s->offset >= width - s->width) { /* at end of line */ - s->offset = width - (s->width - s->x); + s->offset = width - s->width; s->backward = true; makedelay = true; } } - else { - + else + { snprintf(line_buf, sizeof(line_buf)-1, "%s%s%s", s->linebuffer, " ", s->linebuffer); s->line = line_buf; @@ -191,17 +196,26 @@ static void LCDFN(scroll_worker)(void) /* Stash and restore these three, so that the scroll_func * can do whatever it likes without destroying the state */ +#ifdef HAVE_LCD_BITMAP + unsigned drawmode; +#if LCD_DEPTH > 1 + unsigned fg_pattern, bg_pattern; fg_pattern = s->vp->fg_pattern; bg_pattern = s->vp->bg_pattern; +#endif drawmode = s->vp->drawmode; - +#endif s->scroll_func(s); + LCDFN(update_viewport_rect)(s->x, s->y, s->width, s->height); +#ifdef HAVE_LCD_BITMAP +#if LCD_DEPTH > 1 s->vp->fg_pattern = fg_pattern; s->vp->bg_pattern = bg_pattern; +#endif s->vp->drawmode = drawmode; - +#endif LCDFN(set_viewport)(vp); if (makedelay) diff --git a/firmware/export/lcd.h b/firmware/export/lcd.h index 37e6bf4d16..f6b32a37ee 100644 --- a/firmware/export/lcd.h +++ b/firmware/export/lcd.h @@ -195,6 +195,7 @@ extern int lcd_getstringsize(const unsigned char *str, int *w, int *h); extern void lcd_set_viewport(struct viewport* vp); extern void lcd_update(void); extern void lcd_update_viewport(void); +extern void lcd_update_viewport_rect(int x, int y, int width, int height); extern void lcd_clear_viewport(void); extern void lcd_clear_display(void); extern void lcd_putsxy(int x, int y, const unsigned char *string); @@ -234,7 +235,6 @@ extern void lcd_blit_grey_phase(unsigned char *values, unsigned char *phases, /* update a fraction of the screen */ extern void lcd_update_rect(int x, int y, int width, int height); -extern void lcd_update_viewport_rect(int x, int y, int width, int height); #ifdef HAVE_REMOTE_LCD extern void lcd_remote_update(void); diff --git a/firmware/export/scroll_engine.h b/firmware/export/scroll_engine.h index c7eb97aecc..5e4b744c59 100644 --- a/firmware/export/scroll_engine.h +++ b/firmware/export/scroll_engine.h @@ -62,9 +62,6 @@ struct scrollinfo struct viewport* vp; char linebuffer[9*MAX_PATH/10]; const char *line; -#ifdef HAVE_LCD_CHARCELLS - int len; /* length of line in chars */ -#endif /* rectangle for the line */ int x, y; /* relative to the viewort */ int width, height; diff --git a/firmware/rolo.c b/firmware/rolo.c index 79969bbbcf..923199f9d4 100644 --- a/firmware/rolo.c +++ b/firmware/rolo.c @@ -24,6 +24,7 @@ #ifdef HAVE_REMOTE_LCD #include "lcd-remote.h" #endif +#include "scroll_engine.h" #include "thread.h" #include "kernel.h" #include "button.h"