diff options
-rw-r--r-- | apps/gui/line.c | 49 | ||||
-rw-r--r-- | apps/plugin.h | 2 | ||||
-rw-r--r-- | apps/screen_access.h | 4 | ||||
-rw-r--r-- | firmware/drivers/lcd-bitmap-common.c | 69 | ||||
-rw-r--r-- | firmware/drivers/lcd-scroll.c | 12 | ||||
-rw-r--r-- | firmware/export/lcd-remote.h | 4 | ||||
-rw-r--r-- | firmware/export/lcd.h | 4 | ||||
-rw-r--r-- | firmware/export/scroll_engine.h | 5 |
8 files changed, 95 insertions, 54 deletions
diff --git a/apps/gui/line.c b/apps/gui/line.c index d561f08c76..e2eb6f277b 100644 --- a/apps/gui/line.c +++ b/apps/gui/line.c | |||
@@ -50,18 +50,27 @@ static void style_line(struct screen *display, int x, int y, struct line_desc *l | |||
50 | static void put_text(struct screen *display, int x, int y, struct line_desc *line, | 50 | static void put_text(struct screen *display, int x, int y, struct line_desc *line, |
51 | const char *text, bool prevent_scroll, int text_skip_pixels); | 51 | const char *text, bool prevent_scroll, int text_skip_pixels); |
52 | 52 | ||
53 | struct line_desc_scroll { | ||
54 | struct line_desc desc; /* must be first! */ | ||
55 | bool used; | ||
56 | }; | ||
57 | |||
58 | #define NOINLINE __attribute__ ((noinline)) | ||
53 | 59 | ||
54 | static struct line_desc *get_line_desc(void) | 60 | struct line_desc_scroll *get_line_desc(void) NOINLINE; |
61 | struct line_desc_scroll *get_line_desc(void) | ||
55 | { | 62 | { |
56 | static struct line_desc lines[MAX_LINES]; | 63 | static struct line_desc_scroll lines[MAX_LINES]; |
57 | static unsigned line_index; | 64 | static unsigned line_index; |
58 | struct line_desc *ret; | 65 | struct line_desc_scroll *this; |
59 | 66 | ||
60 | ret = &lines[line_index++]; | 67 | do { |
61 | if (line_index >= ARRAYLEN(lines)) | 68 | this = &lines[line_index++]; |
62 | line_index = 0; | 69 | if (line_index >= ARRAYLEN(lines)) |
70 | line_index = 0; | ||
71 | } while (this->used); | ||
63 | 72 | ||
64 | return ret; | 73 | return this; |
65 | } | 74 | } |
66 | 75 | ||
67 | static void scroller(struct scrollinfo *s, struct screen *display) | 76 | static void scroller(struct scrollinfo *s, struct screen *display) |
@@ -72,9 +81,17 @@ static void scroller(struct scrollinfo *s, struct screen *display) | |||
72 | * line padding. this needs to be corrected for calling style_line(). | 81 | * line padding. this needs to be corrected for calling style_line(). |
73 | * The alternative would be to really redraw only the text area, | 82 | * The alternative would be to really redraw only the text area, |
74 | * but that would complicate the code a lot */ | 83 | * but that would complicate the code a lot */ |
75 | struct line_desc *line = s->userdata; | 84 | struct line_desc_scroll *line = s->userdata; |
76 | style_line(display, s->x, s->y - (line->height/2 - display->getcharheight()/2), line); | 85 | if (!s->line) |
77 | put_text(display, s->x, s->y, line, s->line, true, s->offset); | 86 | { |
87 | line->used = false; | ||
88 | } | ||
89 | else | ||
90 | if (s->line) | ||
91 | { | ||
92 | style_line(display, s->x, s->y - (line->desc.height/2 - display->getcharheight()/2), &line->desc); | ||
93 | put_text(display, s->x, s->y, &line->desc, s->line, true, s->offset); | ||
94 | } | ||
78 | } | 95 | } |
79 | 96 | ||
80 | static void scroller_main(struct scrollinfo *s) | 97 | static void scroller_main(struct scrollinfo *s) |
@@ -126,14 +143,16 @@ static void put_text(struct screen *display, | |||
126 | 143 | ||
127 | if (line->scroll && !prevent_scroll) | 144 | if (line->scroll && !prevent_scroll) |
128 | { | 145 | { |
129 | struct line_desc *line_data = get_line_desc(); | 146 | bool scrolls; |
130 | *line_data = *line; | 147 | struct line_desc_scroll *line_data = get_line_desc(); |
148 | line_data->desc = *line; | ||
131 | /* precalculate to avoid doing it in the scroller, it's save to | 149 | /* precalculate to avoid doing it in the scroller, it's save to |
132 | * do this on the copy of the original line_desc*/ | 150 | * do this on the copy of the original line_desc*/ |
133 | if (line_data->height == -1) | 151 | if (line_data->desc.height == -1) |
134 | line_data->height = display->getcharheight(); | 152 | line_data->desc.height = display->getcharheight(); |
135 | display->putsxy_scroll_func(x, y, text, | 153 | scrolls = display->putsxy_scroll_func(x, y, text, |
136 | scrollers[display->screen_type], line_data, text_skip_pixels); | 154 | scrollers[display->screen_type], line_data, text_skip_pixels); |
155 | line_data->used = scrolls; | ||
137 | } | 156 | } |
138 | else | 157 | else |
139 | display->putsxy_scroll_func(x, y, text, NULL, NULL, text_skip_pixels); | 158 | display->putsxy_scroll_func(x, y, text, NULL, NULL, text_skip_pixels); |
diff --git a/apps/plugin.h b/apps/plugin.h index 2cf40d5758..5d6527d7a4 100644 --- a/apps/plugin.h +++ b/apps/plugin.h | |||
@@ -197,7 +197,7 @@ struct plugin_api { | |||
197 | void (*lcd_putsxyf)(int x, int y, const unsigned char *fmt, ...); | 197 | void (*lcd_putsxyf)(int x, int y, const unsigned char *fmt, ...); |
198 | void (*lcd_puts)(int x, int y, const unsigned char *string); | 198 | void (*lcd_puts)(int x, int y, const unsigned char *string); |
199 | void (*lcd_putsf)(int x, int y, const unsigned char *fmt, ...); | 199 | void (*lcd_putsf)(int x, int y, const unsigned char *fmt, ...); |
200 | void (*lcd_puts_scroll)(int x, int y, const unsigned char* string); | 200 | bool (*lcd_puts_scroll)(int x, int y, const unsigned char* string); |
201 | void (*lcd_scroll_stop)(void); | 201 | void (*lcd_scroll_stop)(void); |
202 | #ifdef HAVE_LCD_CHARCELLS | 202 | #ifdef HAVE_LCD_CHARCELLS |
203 | void (*lcd_define_pattern)(unsigned long ucs, const char *pattern); | 203 | void (*lcd_define_pattern)(unsigned long ucs, const char *pattern); |
diff --git a/apps/screen_access.h b/apps/screen_access.h index 7efc38b174..c4a87849b8 100644 --- a/apps/screen_access.h +++ b/apps/screen_access.h | |||
@@ -126,8 +126,8 @@ struct screen | |||
126 | void (*putsxy)(int x, int y, const unsigned char *str); | 126 | void (*putsxy)(int x, int y, const unsigned char *str); |
127 | void (*puts)(int x, int y, const unsigned char *str); | 127 | void (*puts)(int x, int y, const unsigned char *str); |
128 | void (*putsf)(int x, int y, const unsigned char *str, ...); | 128 | void (*putsf)(int x, int y, const unsigned char *str, ...); |
129 | void (*puts_scroll)(int x, int y, const unsigned char *string); | 129 | bool (*puts_scroll)(int x, int y, const unsigned char *string); |
130 | void (*putsxy_scroll_func)(int x, int y, const unsigned char *string, | 130 | bool (*putsxy_scroll_func)(int x, int y, const unsigned char *string, |
131 | void (*scroll_func)(struct scrollinfo *), | 131 | void (*scroll_func)(struct scrollinfo *), |
132 | void *data, int x_offset); | 132 | void *data, int x_offset); |
133 | void (*scroll_speed)(int speed); | 133 | void (*scroll_speed)(int speed); |
diff --git a/firmware/drivers/lcd-bitmap-common.c b/firmware/drivers/lcd-bitmap-common.c index a71f5b2862..22430d4e50 100644 --- a/firmware/drivers/lcd-bitmap-common.c +++ b/firmware/drivers/lcd-bitmap-common.c | |||
@@ -316,15 +316,19 @@ static struct scrollinfo* find_scrolling_line(int x, int y) | |||
316 | 316 | ||
317 | void LCDFN(scroll_fn)(struct scrollinfo* s) | 317 | void LCDFN(scroll_fn)(struct scrollinfo* s) |
318 | { | 318 | { |
319 | /* with line == NULL when scrolling stops. This scroller | ||
320 | * maintains no userdata so there is nothing left to do */ | ||
321 | if (!s->line) | ||
322 | return; | ||
319 | /* Fill with background/backdrop to clear area. | 323 | /* Fill with background/backdrop to clear area. |
320 | * cannot use clear_viewport_rect() since stops scrolling as well */ | 324 | * cannot use clear_viewport_rect() since would stop scrolling as well */ |
321 | LCDFN(set_drawmode)(DRMODE_SOLID|DRMODE_INVERSEVID); | 325 | LCDFN(set_drawmode)(DRMODE_SOLID|DRMODE_INVERSEVID); |
322 | LCDFN(fillrect)(s->x, s->y, s->width, s->height); | 326 | LCDFN(fillrect)(s->x, s->y, s->width, s->height); |
323 | LCDFN(set_drawmode)(DRMODE_SOLID); | 327 | LCDFN(set_drawmode)(DRMODE_SOLID); |
324 | LCDFN(putsxyofs)(s->x, s->y, s->offset, s->line); | 328 | LCDFN(putsxyofs)(s->x, s->y, s->offset, s->line); |
325 | } | 329 | } |
326 | 330 | ||
327 | static void LCDFN(puts_scroll_worker)(int x, int y, const unsigned char *string, | 331 | static bool LCDFN(puts_scroll_worker)(int x, int y, const unsigned char *string, |
328 | int x_offset, | 332 | int x_offset, |
329 | bool linebased, | 333 | bool linebased, |
330 | void (*scroll_func)(struct scrollinfo *), | 334 | void (*scroll_func)(struct scrollinfo *), |
@@ -336,7 +340,7 @@ static void LCDFN(puts_scroll_worker)(int x, int y, const unsigned char *string, | |||
336 | bool restart; | 340 | bool restart; |
337 | 341 | ||
338 | if (!string) | 342 | if (!string) |
339 | return; | 343 | return false; |
340 | 344 | ||
341 | /* prepare rectangle for scrolling. x and y must be calculated early | 345 | /* prepare rectangle for scrolling. x and y must be calculated early |
342 | * for find_scrolling_line() to work */ | 346 | * for find_scrolling_line() to work */ |
@@ -347,32 +351,25 @@ static void LCDFN(puts_scroll_worker)(int x, int y, const unsigned char *string, | |||
347 | width = current_vp->width - x; | 351 | width = current_vp->width - x; |
348 | 352 | ||
349 | if (y >= current_vp->height) | 353 | if (y >= current_vp->height) |
350 | return; | 354 | return false; |
351 | 355 | ||
352 | s = find_scrolling_line(x, y); | 356 | s = find_scrolling_line(x, y); |
353 | restart = !s; | 357 | restart = !s; |
354 | 358 | ||
355 | if (restart) { | ||
356 | /* remove any previously scrolling line at the same location */ | ||
357 | LCDFN(scroll_stop_viewport_rect)(current_vp, x, y, width, height); | ||
358 | LCDFN(putsxyofs)(x, y, x_offset, string); | ||
359 | |||
360 | if (LCDFN(scroll_info).lines >= LCDM(SCROLLABLE_LINES)) | ||
361 | return; | ||
362 | } | ||
363 | |||
364 | /* get width (pixeks) of the string */ | 359 | /* get width (pixeks) of the string */ |
365 | LCDFN(getstringsize)(string, &w, &h); | 360 | LCDFN(getstringsize)(string, &w, &h); |
366 | 361 | ||
367 | /* check if scrolling is actually necessary (consider the actual start | 362 | /* Remove any previously scrolling line at the same location. If |
368 | * of the line) */ | 363 | * the string width is too small to scroll the scrolling line is |
369 | if (width >= w) | 364 | * cleared as well */ |
370 | return; | 365 | if (w < width || restart) { |
371 | 366 | LCDFN(scroll_stop_viewport_rect)(current_vp, x, y, width, height); | |
372 | if (restart) { | 367 | LCDFN(putsxyofs)(x, y, x_offset, string); |
373 | /* prepare scroll line */ | 368 | /* nothing to scroll, or out of scrolling lines. Either way, get out */ |
369 | if (w < width || LCDFN(scroll_info).lines >= LCDM(SCROLLABLE_LINES)) | ||
370 | return false; | ||
371 | /* else restarting: prepare scroll line */ | ||
374 | s = &LCDFN(scroll_info).scroll[LCDFN(scroll_info).lines]; | 372 | s = &LCDFN(scroll_info).scroll[LCDFN(scroll_info).lines]; |
375 | s->start_tick = current_tick + LCDFN(scroll_info).delay; | ||
376 | } | 373 | } |
377 | 374 | ||
378 | /* copy contents to the line buffer */ | 375 | /* copy contents to the line buffer */ |
@@ -385,9 +382,6 @@ static void LCDFN(puts_scroll_worker)(int x, int y, const unsigned char *string, | |||
385 | else | 382 | else |
386 | s->bidir = false; | 383 | s->bidir = false; |
387 | 384 | ||
388 | s->scroll_func = scroll_func; | ||
389 | s->userdata = data; | ||
390 | |||
391 | if (restart) { | 385 | if (restart) { |
392 | s->offset = x_offset; | 386 | s->offset = x_offset; |
393 | s->backward = false; | 387 | s->backward = false; |
@@ -397,26 +391,41 @@ static void LCDFN(puts_scroll_worker)(int x, int y, const unsigned char *string, | |||
397 | s->width = width; | 391 | s->width = width; |
398 | s->height = height; | 392 | s->height = height; |
399 | s->vp = current_vp; | 393 | s->vp = current_vp; |
394 | s->start_tick = current_tick + LCDFN(scroll_info).delay; | ||
400 | LCDFN(scroll_info).lines++; | 395 | LCDFN(scroll_info).lines++; |
401 | } else { | 396 | } else { |
402 | /* if only the text was updated render immediately */ | 397 | /* not restarting, however we are about to assign new userdata; |
403 | LCDFN(scroll_now(s)); | 398 | * therefore tell the scroller that it can release the previous userdata */ |
399 | s->line = NULL; | ||
400 | s->scroll_func(s); | ||
404 | } | 401 | } |
402 | |||
403 | s->scroll_func = scroll_func; | ||
404 | s->userdata = data; | ||
405 | |||
406 | /* if only the text was updated render immediately */ | ||
407 | if (!restart) | ||
408 | LCDFN(scroll_now(s)); | ||
409 | |||
410 | return true; | ||
405 | } | 411 | } |
406 | 412 | ||
407 | void LCDFN(putsxy_scroll_func)(int x, int y, const unsigned char *string, | 413 | bool LCDFN(putsxy_scroll_func)(int x, int y, const unsigned char *string, |
408 | void (*scroll_func)(struct scrollinfo *), | 414 | void (*scroll_func)(struct scrollinfo *), |
409 | void *data, int x_offset) | 415 | void *data, int x_offset) |
410 | { | 416 | { |
417 | bool retval = false; | ||
411 | if (!scroll_func) | 418 | if (!scroll_func) |
412 | LCDFN(putsxyofs)(x, y, x_offset, string); | 419 | LCDFN(putsxyofs)(x, y, x_offset, string); |
413 | else | 420 | else |
414 | LCDFN(puts_scroll_worker)(x, y, string, x_offset, false, scroll_func, data); | 421 | retval = LCDFN(puts_scroll_worker)(x, y, string, x_offset, false, scroll_func, data); |
422 | |||
423 | return retval; | ||
415 | } | 424 | } |
416 | 425 | ||
417 | void LCDFN(puts_scroll)(int x, int y, const unsigned char *string) | 426 | bool LCDFN(puts_scroll)(int x, int y, const unsigned char *string) |
418 | { | 427 | { |
419 | LCDFN(puts_scroll_worker)(x, y, string, 0, true, LCDFN(scroll_fn), NULL); | 428 | return LCDFN(puts_scroll_worker)(x, y, string, 0, true, LCDFN(scroll_fn), NULL); |
420 | } | 429 | } |
421 | 430 | ||
422 | #if !defined(HAVE_LCD_COLOR) || !defined(MAIN_LCD) | 431 | #if !defined(HAVE_LCD_COLOR) || !defined(MAIN_LCD) |
diff --git a/firmware/drivers/lcd-scroll.c b/firmware/drivers/lcd-scroll.c index a1bde9fe12..5162f9a100 100644 --- a/firmware/drivers/lcd-scroll.c +++ b/firmware/drivers/lcd-scroll.c | |||
@@ -30,7 +30,7 @@ | |||
30 | #define MAIN_LCD | 30 | #define MAIN_LCD |
31 | #endif | 31 | #endif |
32 | 32 | ||
33 | static struct scrollinfo LCDFN(scroll)[LCD_SCROLLABLE_LINES]; | 33 | static struct scrollinfo LCDFN(scroll)[LCDM(SCROLLABLE_LINES)]; |
34 | 34 | ||
35 | struct scroll_screen_info LCDFN(scroll_info) = | 35 | struct scroll_screen_info LCDFN(scroll_info) = |
36 | { | 36 | { |
@@ -51,6 +51,13 @@ struct scroll_screen_info LCDFN(scroll_info) = | |||
51 | 51 | ||
52 | void LCDFN(scroll_stop)(void) | 52 | void LCDFN(scroll_stop)(void) |
53 | { | 53 | { |
54 | for (int i = 0; i < LCDFN(scroll_info).lines; i++) | ||
55 | { | ||
56 | /* inform scroller about end of scrolling */ | ||
57 | struct scrollinfo *s = &LCDFN(scroll_info).scroll[i]; | ||
58 | s->line = NULL; | ||
59 | s->scroll_func(s); | ||
60 | } | ||
54 | LCDFN(scroll_info).lines = 0; | 61 | LCDFN(scroll_info).lines = 0; |
55 | } | 62 | } |
56 | 63 | ||
@@ -66,6 +73,9 @@ void LCDFN(scroll_stop_viewport_rect)(const struct viewport *vp, int x, int y, i | |||
66 | && (x < (s->x+s->width) && (x+width) >= s->x) | 73 | && (x < (s->x+s->width) && (x+width) >= s->x) |
67 | && (y < (s->y+s->height) && (y+height) >= s->y)) | 74 | && (y < (s->y+s->height) && (y+height) >= s->y)) |
68 | { | 75 | { |
76 | /* inform scroller about end of scrolling */ | ||
77 | s->line = NULL; | ||
78 | s->scroll_func(s); | ||
69 | /* If i is not the last active line in the array, then move | 79 | /* If i is not the last active line in the array, then move |
70 | the last item to position i. This compacts | 80 | the last item to position i. This compacts |
71 | the scroll array at the same time of removing the line */ | 81 | the scroll array at the same time of removing the line */ |
diff --git a/firmware/export/lcd-remote.h b/firmware/export/lcd-remote.h index bc26a23cb7..1819a4de72 100644 --- a/firmware/export/lcd-remote.h +++ b/firmware/export/lcd-remote.h | |||
@@ -176,8 +176,8 @@ extern void lcd_remote_clear_viewport(void); | |||
176 | extern void lcd_remote_puts(int x, int y, const unsigned char *str); | 176 | extern void lcd_remote_puts(int x, int y, const unsigned char *str); |
177 | extern void lcd_remote_putsf(int x, int y, const unsigned char *fmt, ...); | 177 | extern void lcd_remote_putsf(int x, int y, const unsigned char *fmt, ...); |
178 | extern void lcd_remote_putc(int x, int y, unsigned short ch); | 178 | extern void lcd_remote_putc(int x, int y, unsigned short ch); |
179 | extern void lcd_remote_puts_scroll(int x, int y, const unsigned char *str); | 179 | extern bool lcd_remote_puts_scroll(int x, int y, const unsigned char *str); |
180 | extern void lcd_remote_putsxy_scroll_func(int x, int y, const unsigned char *string, | 180 | extern bool lcd_remote_putsxy_scroll_func(int x, int y, const unsigned char *string, |
181 | void (*scroll_func)(struct scrollinfo *), | 181 | void (*scroll_func)(struct scrollinfo *), |
182 | void *data, int x_offset); | 182 | void *data, int x_offset); |
183 | 183 | ||
diff --git a/firmware/export/lcd.h b/firmware/export/lcd.h index 87476d9dda..386ac5a8bf 100644 --- a/firmware/export/lcd.h +++ b/firmware/export/lcd.h | |||
@@ -179,8 +179,8 @@ extern void lcd_putsxy_style_offset(int x, int y, const unsigned char *str, | |||
179 | extern void lcd_puts(int x, int y, const unsigned char *string); | 179 | extern void lcd_puts(int x, int y, const unsigned char *string); |
180 | extern void lcd_putsf(int x, int y, const unsigned char *fmt, ...); | 180 | extern void lcd_putsf(int x, int y, const unsigned char *fmt, ...); |
181 | extern void lcd_putc(int x, int y, unsigned long ucs); | 181 | extern void lcd_putc(int x, int y, unsigned long ucs); |
182 | extern void lcd_puts_scroll(int x, int y, const unsigned char* string); | 182 | extern bool lcd_puts_scroll(int x, int y, const unsigned char* string); |
183 | extern void lcd_putsxy_scroll_func(int x, int y, const unsigned char *string, | 183 | extern bool lcd_putsxy_scroll_func(int x, int y, const unsigned char *string, |
184 | void (*scroll_func)(struct scrollinfo *), | 184 | void (*scroll_func)(struct scrollinfo *), |
185 | void *data, int x_offset); | 185 | void *data, int x_offset); |
186 | 186 | ||
diff --git a/firmware/export/scroll_engine.h b/firmware/export/scroll_engine.h index 64e1d6d6ae..ce230a218c 100644 --- a/firmware/export/scroll_engine.h +++ b/firmware/export/scroll_engine.h | |||
@@ -79,7 +79,10 @@ struct scrollinfo | |||
79 | bool bidir; | 79 | bool bidir; |
80 | long start_tick; | 80 | long start_tick; |
81 | 81 | ||
82 | /* support for custom scrolling functions */ | 82 | /* support for custom scrolling functions, |
83 | * must be called with ::line == NULL to indicate that the line | ||
84 | * stops scrolling or when the userdata pointer is going to be changed | ||
85 | * (the custom scroller can release the userdata then) */ | ||
83 | void (*scroll_func)(struct scrollinfo *s); | 86 | void (*scroll_func)(struct scrollinfo *s); |
84 | void *userdata; | 87 | void *userdata; |
85 | }; | 88 | }; |