diff options
author | Thomas Martitz <kugel@rockbox.org> | 2014-01-12 01:30:26 +0100 |
---|---|---|
committer | Thomas Martitz <kugel@rockbox.org> | 2014-01-12 01:34:06 +0100 |
commit | 488a1b983e1c2fac14de25aa781caf12628e53c8 (patch) | |
tree | 8d5b5b33e0c7eb9e5222b843f84c6b2d65d1a352 /firmware | |
parent | 656261bde1122612d1bf8ffc3c992c75a7fbc52e (diff) | |
download | rockbox-488a1b983e1c2fac14de25aa781caf12628e53c8.tar.gz rockbox-488a1b983e1c2fac14de25aa781caf12628e53c8.zip |
put_line/scrolling: Make the scroll engine inform custom scrollers about start/stop of scrolling.
With the new lcd_putsxy_scroll_func() code can register custom scroll functions
(put_line() makes use of that). In order for the custom scroller to be able
to properly manage its userdata pointer (set via struct scrollinfo::userdata)
the scroll engine must inform the scroller about start and stop of scrolling.
To inform about start the lcd_scroll_* functions now return true when
the line will scroll. To inform about stop the scroll engine calls into the
scroller one last time, with the text set to NULL.
put_line() can use this to release the userdata registered per scrolling line
so that it can be recycled.
This fixes that some scrolling lines became glitchy after some time because
the userdata was recycled too early.
Change-Id: Iff0a6ce2a4f9ae2bada1b8e62f4f5950224942a9
Diffstat (limited to 'firmware')
-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 |
5 files changed, 58 insertions, 36 deletions
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 | }; |