summaryrefslogtreecommitdiff
path: root/firmware/drivers/lcd-remote-1bit-v.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/drivers/lcd-remote-1bit-v.c')
-rw-r--r--firmware/drivers/lcd-remote-1bit-v.c884
1 files changed, 5 insertions, 879 deletions
diff --git a/firmware/drivers/lcd-remote-1bit-v.c b/firmware/drivers/lcd-remote-1bit-v.c
index 20c6f6655c..bed7cc6671 100644
--- a/firmware/drivers/lcd-remote-1bit-v.c
+++ b/firmware/drivers/lcd-remote-1bit-v.c
@@ -17,885 +17,11 @@
17 * 17 *
18 ****************************************************************************/ 18 ****************************************************************************/
19 19
20#include "config.h"
21#include "cpu.h"
22#include "lcd.h"
23#include "lcd-remote.h" 20#include "lcd-remote.h"
24#include "kernel.h"
25#include "thread.h"
26#include <string.h>
27#include <stdlib.h>
28#include "file.h"
29#include "debug.h"
30#include "system.h"
31#include "font.h"
32#include "rbunicode.h"
33#include "bidi.h"
34#include "scroll_engine.h"
35 21
36/*** globals ***/ 22/* Compile 1 bit vertical packing LCD driver for remote LCD */
23#define LCDFN(fn) lcd_remote_ ## fn
24#define FBFN(fn) fb_remote_ ## fn
25#define LCDM(ma) LCD_REMOTE_ ## ma
37 26
38fb_remote_data lcd_remote_framebuffer[LCD_REMOTE_FBHEIGHT][LCD_REMOTE_FBWIDTH] 27#include "lcd-1bit-vert.c"
39 IBSS_ATTR;
40
41static struct viewport default_vp =
42{
43 .x = 0,
44 .y = 0,
45 .width = LCD_REMOTE_WIDTH,
46 .height = LCD_REMOTE_HEIGHT,
47 .font = FONT_SYSFIXED,
48 .drawmode = DRMODE_SOLID,
49 .xmargin = 0,
50 .ymargin = 0,
51};
52
53static struct viewport* current_vp IDATA_ATTR = &default_vp;
54
55/*** Viewports ***/
56
57void lcd_remote_set_viewport(struct viewport* vp)
58{
59 if (vp == NULL)
60 current_vp = &default_vp;
61 else
62 current_vp = vp;
63}
64
65void lcd_remote_update_viewport(void)
66{
67 lcd_remote_update_rect(current_vp->x, current_vp->y,
68 current_vp->width, current_vp->height);
69}
70
71void lcd_remote_update_viewport_rect(int x, int y, int width, int height)
72{
73 lcd_remote_update_rect(current_vp->x + x, current_vp->y + y, width, height);
74}
75
76
77/*** parameter handling ***/
78
79void lcd_remote_set_drawmode(int mode)
80{
81 current_vp->drawmode = mode & (DRMODE_SOLID|DRMODE_INVERSEVID);
82}
83
84int lcd_remote_get_drawmode(void)
85{
86 return current_vp->drawmode;
87}
88
89void lcd_remote_setmargins(int x, int y)
90{
91 current_vp->xmargin = x;
92 current_vp->ymargin = y;
93}
94
95int lcd_remote_getwidth(void)
96{
97 return current_vp->width;
98}
99
100int lcd_remote_getheight(void)
101{
102 return current_vp->height;
103}
104
105int lcd_remote_getxmargin(void)
106{
107 return current_vp->xmargin;
108}
109
110int lcd_remote_getymargin(void)
111{
112 return current_vp->ymargin;
113}
114
115void lcd_remote_setfont(int newfont)
116{
117 current_vp->font = newfont;
118}
119
120int lcd_remote_getfont(void)
121{
122 return current_vp->font;
123}
124
125int lcd_remote_getstringsize(const unsigned char *str, int *w, int *h)
126{
127 return font_getstringsize(str, w, h, current_vp->font);
128}
129
130/*** low-level drawing functions ***/
131
132static void setpixel(int x, int y)
133{
134 lcd_remote_framebuffer[y>>3][x] |= 1 << (y & 7);
135}
136
137static void clearpixel(int x, int y)
138{
139 lcd_remote_framebuffer[y>>3][x] &= ~(1 << (y & 7));
140}
141
142static void flippixel(int x, int y)
143{
144 lcd_remote_framebuffer[y>>3][x] ^= 1 << (y & 7);
145}
146
147static void nopixel(int x, int y)
148{
149 (void)x;
150 (void)y;
151}
152
153lcd_remote_pixelfunc_type* const lcd_remote_pixelfuncs[8] = {
154 flippixel, nopixel, setpixel, setpixel,
155 nopixel, clearpixel, nopixel, clearpixel
156};
157
158static void flipblock(fb_remote_data *address, unsigned mask, unsigned bits)
159 ICODE_ATTR;
160static void flipblock(fb_remote_data *address, unsigned mask, unsigned bits)
161{
162 *address ^= bits & mask;
163}
164
165static void bgblock(fb_remote_data *address, unsigned mask, unsigned bits)
166 ICODE_ATTR;
167static void bgblock(fb_remote_data *address, unsigned mask, unsigned bits)
168{
169 *address &= bits | ~mask;
170}
171
172static void fgblock(fb_remote_data *address, unsigned mask, unsigned bits)
173 ICODE_ATTR;
174static void fgblock(fb_remote_data *address, unsigned mask, unsigned bits)
175{
176 *address |= bits & mask;
177}
178
179static void solidblock(fb_remote_data *address, unsigned mask, unsigned bits)
180 ICODE_ATTR;
181static void solidblock(fb_remote_data *address, unsigned mask, unsigned bits)
182{
183 unsigned data = *address;
184
185 bits ^= data;
186 *address = data ^ (bits & mask);
187}
188
189static void flipinvblock(fb_remote_data *address, unsigned mask, unsigned bits)
190 ICODE_ATTR;
191static void flipinvblock(fb_remote_data *address, unsigned mask, unsigned bits)
192{
193 *address ^= ~bits & mask;
194}
195
196static void bginvblock(fb_remote_data *address, unsigned mask, unsigned bits)
197 ICODE_ATTR;
198static void bginvblock(fb_remote_data *address, unsigned mask, unsigned bits)
199{
200 *address &= ~(bits & mask);
201}
202
203static void fginvblock(fb_remote_data *address, unsigned mask, unsigned bits)
204 ICODE_ATTR;
205static void fginvblock(fb_remote_data *address, unsigned mask, unsigned bits)
206{
207 *address |= ~bits & mask;
208}
209
210static void solidinvblock(fb_remote_data *address, unsigned mask, unsigned bits)
211 ICODE_ATTR;
212static void solidinvblock(fb_remote_data *address, unsigned mask, unsigned bits)
213{
214 unsigned data = *address;
215
216 bits = ~bits ^ data;
217 *address = data ^ (bits & mask);
218}
219
220lcd_remote_blockfunc_type* const lcd_remote_blockfuncs[8] = {
221 flipblock, bgblock, fgblock, solidblock,
222 flipinvblock, bginvblock, fginvblock, solidinvblock
223};
224
225/*** drawing functions ***/
226
227/* Clear the whole display */
228void lcd_remote_clear_display(void)
229{
230 unsigned bits = (current_vp->drawmode & DRMODE_INVERSEVID) ? 0xFFu : 0;
231
232 memset(lcd_remote_framebuffer, bits, sizeof lcd_remote_framebuffer);
233
234 lcd_remote_scroll_info.lines = 0;
235}
236
237/* Clear the current viewport */
238void lcd_remote_clear_viewport(void)
239{
240 int oldmode;
241
242 if (current_vp == &default_vp)
243 {
244 lcd_remote_clear_display();
245 }
246 else
247 {
248 oldmode = current_vp->drawmode;
249
250 /* Invert the INVERSEVID bit and set basic mode to SOLID */
251 current_vp->drawmode = (~current_vp->drawmode & DRMODE_INVERSEVID) |
252 DRMODE_SOLID;
253
254 lcd_remote_fillrect(0, 0, current_vp->width, current_vp->height);
255
256 current_vp->drawmode = oldmode;
257
258 lcd_remote_scroll_stop(current_vp);
259 }
260}
261
262/* Set a single pixel */
263void lcd_remote_drawpixel(int x, int y)
264{
265 if (((unsigned)x < (unsigned)current_vp->width) &&
266 ((unsigned)y < (unsigned)current_vp->height))
267 lcd_remote_pixelfuncs[current_vp->drawmode](current_vp->x+x, current_vp->y+y);
268}
269
270/* Draw a line */
271void lcd_remote_drawline(int x1, int y1, int x2, int y2)
272{
273 int numpixels;
274 int i;
275 int deltax, deltay;
276 int d, dinc1, dinc2;
277 int x, xinc1, xinc2;
278 int y, yinc1, yinc2;
279 lcd_remote_pixelfunc_type *pfunc = lcd_remote_pixelfuncs[current_vp->drawmode];
280
281 deltax = abs(x2 - x1);
282 deltay = abs(y2 - y1);
283 xinc2 = 1;
284 yinc2 = 1;
285
286 if (deltax >= deltay)
287 {
288 numpixels = deltax;
289 d = 2 * deltay - deltax;
290 dinc1 = deltay * 2;
291 dinc2 = (deltay - deltax) * 2;
292 xinc1 = 1;
293 yinc1 = 0;
294 }
295 else
296 {
297 numpixels = deltay;
298 d = 2 * deltax - deltay;
299 dinc1 = deltax * 2;
300 dinc2 = (deltax - deltay) * 2;
301 xinc1 = 0;
302 yinc1 = 1;
303 }
304 numpixels++; /* include endpoints */
305
306 if (x1 > x2)
307 {
308 xinc1 = -xinc1;
309 xinc2 = -xinc2;
310 }
311
312 if (y1 > y2)
313 {
314 yinc1 = -yinc1;
315 yinc2 = -yinc2;
316 }
317
318 x = x1;
319 y = y1;
320
321 for (i = 0; i < numpixels; i++)
322 {
323 if (((unsigned)x < (unsigned)current_vp->width) && ((unsigned)y < (unsigned)current_vp->height))
324 pfunc(x + current_vp->x, y + current_vp->y);
325
326 if (d < 0)
327 {
328 d += dinc1;
329 x += xinc1;
330 y += yinc1;
331 }
332 else
333 {
334 d += dinc2;
335 x += xinc2;
336 y += yinc2;
337 }
338 }
339}
340
341/* Draw a horizontal line (optimised) */
342void lcd_remote_hline(int x1, int x2, int y)
343{
344 int x, width;
345 fb_remote_data *dst, *dst_end;
346 unsigned mask;
347 lcd_remote_blockfunc_type *bfunc;
348
349 /* direction flip */
350 if (x2 < x1)
351 {
352 x = x1;
353 x1 = x2;
354 x2 = x;
355 }
356
357 /* nothing to draw? */
358 if (((unsigned)y >= (unsigned)current_vp->height) || (x1 >= current_vp->width)
359 || (x2 < 0))
360 return;
361
362 /* clipping */
363 if (x1 < 0)
364 x1 = 0;
365 if (x2 >= current_vp->width)
366 x2 = current_vp->width-1;
367
368 width = x2 - x1 + 1;
369
370 /* Adjust x1 and y to viewport */
371 x1 += current_vp->x;
372 y += current_vp->y;
373
374 bfunc = lcd_remote_blockfuncs[current_vp->drawmode];
375 dst = &lcd_remote_framebuffer[y>>3][x1];
376 mask = 1 << (y & 7);
377
378 dst_end = dst + width;
379 do
380 bfunc(dst++, mask, 0xFFu);
381 while (dst < dst_end);
382}
383
384/* Draw a vertical line (optimised) */
385void lcd_remote_vline(int x, int y1, int y2)
386{
387 int ny;
388 fb_remote_data *dst;
389 unsigned mask, mask_bottom;
390 lcd_remote_blockfunc_type *bfunc;
391
392 /* direction flip */
393 if (y2 < y1)
394 {
395 ny = y1;
396 y1 = y2;
397 y2 = ny;
398 }
399
400 /* nothing to draw? */
401 if (((unsigned)x >= (unsigned)current_vp->width) || (y1 >= current_vp->height)
402 || (y2 < 0))
403 return;
404
405 /* clipping */
406 if (y1 < 0)
407 y1 = 0;
408 if (y2 >= current_vp->height)
409 y2 = current_vp->height-1;
410
411 /* adjust for viewport */
412 y1 += current_vp->y;
413 y2 += current_vp->y;
414 x += current_vp->x;
415
416 bfunc = lcd_remote_blockfuncs[current_vp->drawmode];
417 dst = &lcd_remote_framebuffer[y1>>3][x];
418 ny = y2 - (y1 & ~7);
419 mask = 0xFFu << (y1 & 7);
420 mask_bottom = 0xFFu >> (~ny & 7);
421
422 for (; ny >= 8; ny -= 8)
423 {
424 bfunc(dst, mask, 0xFFu);
425 dst += LCD_REMOTE_WIDTH;
426 mask = 0xFFu;
427 }
428 mask &= mask_bottom;
429 bfunc(dst, mask, 0xFFu);
430}
431
432/* Draw a rectangular box */
433void lcd_remote_drawrect(int x, int y, int width, int height)
434{
435 if ((width <= 0) || (height <= 0))
436 return;
437
438 int x2 = x + width - 1;
439 int y2 = y + height - 1;
440
441 lcd_remote_vline(x, y, y2);
442 lcd_remote_vline(x2, y, y2);
443 lcd_remote_hline(x, x2, y);
444 lcd_remote_hline(x, x2, y2);
445}
446
447/* Fill a rectangular area */
448void lcd_remote_fillrect(int x, int y, int width, int height)
449{
450 int ny;
451 fb_remote_data *dst, *dst_end;
452 unsigned mask, mask_bottom;
453 unsigned bits = 0;
454 lcd_remote_blockfunc_type *bfunc;
455 bool fillopt = false;
456
457 /* nothing to draw? */
458 if ((width <= 0) || (height <= 0) || (x >= current_vp->width)
459 || (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0))
460 return;
461
462 /* clipping */
463 if (x < 0)
464 {
465 width += x;
466 x = 0;
467 }
468 if (y < 0)
469 {
470 height += y;
471 y = 0;
472 }
473 if (x + width > current_vp->width)
474 width = current_vp->width - x;
475 if (y + height > current_vp->height)
476 height = current_vp->height - y;
477
478 /* adjust for viewport */
479 x += current_vp->x;
480 y += current_vp->y;
481
482 if (current_vp->drawmode & DRMODE_INVERSEVID)
483 {
484 if (current_vp->drawmode & DRMODE_BG)
485 {
486 fillopt = true;
487 }
488 }
489 else
490 {
491 if (current_vp->drawmode & DRMODE_FG)
492 {
493 fillopt = true;
494 bits = 0xFFu;
495 }
496 }
497
498 bfunc = lcd_remote_blockfuncs[current_vp->drawmode];
499 dst = &lcd_remote_framebuffer[y>>3][x];
500 ny = height - 1 + (y & 7);
501 mask = 0xFFu << (y & 7);
502 mask_bottom = 0xFFu >> (~ny & 7);
503
504 for (; ny >= 8; ny -= 8)
505 {
506 if (fillopt && (mask == 0xFFu))
507 memset(dst, bits, width);
508 else
509 {
510 fb_remote_data *dst_row = dst;
511
512 dst_end = dst_row + width;
513 do
514 bfunc(dst_row++, mask, 0xFFu);
515 while (dst_row < dst_end);
516 }
517
518 dst += LCD_REMOTE_WIDTH;
519 mask = 0xFFu;
520 }
521 mask &= mask_bottom;
522
523 if (fillopt && (mask == 0xFFu))
524 memset(dst, bits, width);
525 else
526 {
527 dst_end = dst + width;
528 do
529 bfunc(dst++, mask, 0xFFu);
530 while (dst < dst_end);
531 }
532}
533
534/* About Rockbox' internal bitmap format:
535 *
536 * A bitmap contains one bit for every pixel that defines if that pixel is
537 * black (1) or white (0). Bits within a byte are arranged vertically, LSB
538 * at top.
539 * The bytes are stored in row-major order, with byte 0 being top left,
540 * byte 1 2nd from left etc. The first row of bytes defines pixel rows
541 * 0..7, the second row defines pixel row 8..15 etc.
542 *
543 * This is the same as the internal lcd hw format. */
544
545/* Draw a partial bitmap */
546void lcd_remote_bitmap_part(const unsigned char *src, int src_x, int src_y,
547 int stride, int x, int y, int width, int height)
548 ICODE_ATTR;
549void lcd_remote_bitmap_part(const unsigned char *src, int src_x, int src_y,
550 int stride, int x, int y, int width, int height)
551{
552 int shift, ny;
553 fb_remote_data *dst, *dst_end;
554 unsigned mask, mask_bottom;
555 lcd_remote_blockfunc_type *bfunc;
556
557 /* nothing to draw? */
558 if ((width <= 0) || (height <= 0) || (x >= current_vp->width)
559 || (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0))
560 return;
561
562 /* clipping */
563 if (x < 0)
564 {
565 width += x;
566 src_x -= x;
567 x = 0;
568 }
569 if (y < 0)
570 {
571 height += y;
572 src_y -= y;
573 y = 0;
574 }
575 if (x + width > current_vp->width)
576 width = current_vp->width - x;
577 if (y + height > current_vp->height)
578 height = current_vp->height - y;
579
580 /* adjust for viewports */
581 x += current_vp->x;
582 y += current_vp->y;
583
584 src += stride * (src_y >> 3) + src_x; /* move starting point */
585 src_y &= 7;
586 y -= src_y;
587 dst = &lcd_remote_framebuffer[y>>3][x];
588 shift = y & 7;
589 ny = height - 1 + shift + src_y;
590
591 bfunc = lcd_remote_blockfuncs[current_vp->drawmode];
592 mask = 0xFFu << (shift + src_y);
593 mask_bottom = 0xFFu >> (~ny & 7);
594
595 if (shift == 0)
596 {
597 bool copyopt = (current_vp->drawmode == DRMODE_SOLID);
598
599 for (; ny >= 8; ny -= 8)
600 {
601 if (copyopt && (mask == 0xFFu))
602 memcpy(dst, src, width);
603 else
604 {
605 const unsigned char *src_row = src;
606 fb_remote_data *dst_row = dst;
607
608 dst_end = dst_row + width;
609 do
610 bfunc(dst_row++, mask, *src_row++);
611 while (dst_row < dst_end);
612 }
613
614 src += stride;
615 dst += LCD_REMOTE_WIDTH;
616 mask = 0xFFu;
617 }
618 mask &= mask_bottom;
619
620 if (copyopt && (mask == 0xFFu))
621 memcpy(dst, src, width);
622 else
623 {
624 dst_end = dst + width;
625 do
626 bfunc(dst++, mask, *src++);
627 while (dst < dst_end);
628 }
629 }
630 else
631 {
632 dst_end = dst + width;
633 do
634 {
635 const unsigned char *src_col = src++;
636 fb_remote_data *dst_col = dst++;
637 unsigned mask_col = mask;
638 unsigned data = 0;
639
640 for (y = ny; y >= 8; y -= 8)
641 {
642 data |= *src_col << shift;
643
644 if (mask_col & 0xFFu)
645 {
646 bfunc(dst_col, mask_col, data);
647 mask_col = 0xFFu;
648 }
649 else
650 mask_col >>= 8;
651
652 src_col += stride;
653 dst_col += LCD_REMOTE_WIDTH;
654 data >>= 8;
655 }
656 data |= *src_col << shift;
657 bfunc(dst_col, mask_col & mask_bottom, data);
658 }
659 while (dst < dst_end);
660 }
661}
662
663/* Draw a full bitmap */
664void lcd_remote_bitmap(const unsigned char *src, int x, int y, int width,
665 int height)
666{
667 lcd_remote_bitmap_part(src, 0, 0, width, x, y, width, height);
668}
669
670/* put a string at a given pixel position, skipping first ofs pixel columns */
671void lcd_remote_putsxyofs(int x, int y, int ofs, const unsigned char *str)
672{
673 unsigned short ch;
674 unsigned short *ucs;
675 struct font* pf = font_get(current_vp->font);
676
677 ucs = bidi_l2v(str, 1);
678
679 while ((ch = *ucs++) != 0 && x < current_vp->width)
680 {
681 int width;
682 const unsigned char *bits;
683
684 /* get proportional width and glyph bits */
685 width = font_get_width(pf, ch);
686
687 if (ofs > width)
688 {
689 ofs -= width;
690 continue;
691 }
692
693 bits = font_get_bits(pf, ch);
694
695 lcd_remote_bitmap_part(bits, ofs, 0, width, x, y, width - ofs,
696 pf->height);
697
698 x += width - ofs;
699 ofs = 0;
700 }
701}
702
703/* put a string at a given pixel position */
704void lcd_remote_putsxy(int x, int y, const unsigned char *str)
705{
706 lcd_remote_putsxyofs(x, y, 0, str);
707}
708
709/*** line oriented text output ***/
710
711/* put a string at a given char position */
712void lcd_remote_puts(int x, int y, const unsigned char *str)
713{
714 lcd_remote_puts_style_offset(x, y, str, STYLE_DEFAULT, 0);
715}
716
717void lcd_remote_puts_style(int x, int y, const unsigned char *str, int style)
718{
719 lcd_remote_puts_style_offset(x, y, str, style, 0);
720}
721
722void lcd_remote_puts_offset(int x, int y, const unsigned char *str, int offset)
723{
724 lcd_remote_puts_style_offset(x, y, str, STYLE_DEFAULT, offset);
725}
726
727/* put a string at a given char position, style, and pixel position,
728 * skipping first offset pixel columns */
729void lcd_remote_puts_style_offset(int x, int y, const unsigned char *str,
730 int style, int offset)
731{
732 int xpos,ypos,w,h,xrect;
733 int lastmode = current_vp->drawmode;
734
735 /* make sure scrolling is turned off on the line we are updating */
736 lcd_remote_scroll_stop_line(current_vp, y);
737
738 if(!str || !str[0])
739 return;
740
741 lcd_remote_getstringsize(str, &w, &h);
742 xpos = current_vp->xmargin + x*w / utf8length((char *)str);
743 ypos = current_vp->ymargin + y*h;
744 current_vp->drawmode = (style & STYLE_INVERT) ?
745 (DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID;
746 lcd_remote_putsxyofs(xpos, ypos, offset, str);
747 current_vp->drawmode ^= DRMODE_INVERSEVID;
748 xrect = xpos + MAX(w - offset, 0);
749 lcd_remote_fillrect(xrect, ypos, current_vp->width - xrect, h);
750 current_vp->drawmode = lastmode;
751}
752
753/*** scrolling ***/
754
755void lcd_remote_puts_scroll(int x, int y, const unsigned char *string)
756{
757 lcd_remote_puts_scroll_style(x, y, string, STYLE_DEFAULT);
758}
759
760void lcd_remote_puts_scroll_style(int x, int y, const unsigned char *string, int style)
761{
762 lcd_remote_puts_scroll_style_offset(x, y, string, style, 0);
763}
764
765void lcd_remote_puts_scroll_offset(int x, int y, const unsigned char *string, int offset)
766{
767 lcd_remote_puts_scroll_style_offset(x, y, string, STYLE_DEFAULT, offset);
768}
769
770void lcd_remote_puts_scroll_style_offset(int x, int y, const unsigned char *string,
771 int style, int offset)
772{
773 struct scrollinfo* s;
774 int w, h;
775
776 if ((unsigned)y >= (unsigned)current_vp->height)
777 return;
778
779 /* remove any previously scrolling line at the same location */
780 lcd_remote_scroll_stop_line(current_vp, y);
781
782 if (lcd_remote_scroll_info.lines >= LCD_REMOTE_SCROLLABLE_LINES) return;
783
784 s = &lcd_remote_scroll_info.scroll[lcd_remote_scroll_info.lines];
785
786 s->start_tick = current_tick + lcd_remote_scroll_info.delay;
787 s->style = style;
788 if (style & STYLE_INVERT) {
789 lcd_remote_puts_style_offset(x,y,string,STYLE_INVERT,offset);
790 }
791 else
792 lcd_remote_puts_offset(x,y,string,offset);
793
794 lcd_remote_getstringsize(string, &w, &h);
795
796 if (current_vp->width - x * 8 - current_vp->xmargin < w) {
797 /* prepare scroll line */
798 char *end;
799
800 memset(s->line, 0, sizeof s->line);
801 strcpy(s->line, (char *)string);
802
803 /* get width */
804 s->width = lcd_remote_getstringsize((unsigned char *)s->line, &w, &h);
805
806 /* scroll bidirectional or forward only depending on the string
807 width */
808 if ( lcd_remote_scroll_info.bidir_limit ) {
809 s->bidir = s->width < (current_vp->width - current_vp->xmargin) *
810 (100 + lcd_remote_scroll_info.bidir_limit) / 100;
811 }
812 else
813 s->bidir = false;
814
815 if (!s->bidir) { /* add spaces if scrolling in the round */
816 strcat(s->line, " ");
817 /* get new width incl. spaces */
818 s->width = lcd_remote_getstringsize((unsigned char *)s->line, &w, &h);
819 }
820
821 end = strchr(s->line, '\0');
822 strncpy(end, (char *)string, current_vp->width/2);
823
824 s->vp = current_vp;
825 s->y = y;
826 s->len = utf8length((char *)string);
827 s->offset = offset;
828 s->startx = current_vp->xmargin + x * s->width / s->len;
829 s->backward = false;
830
831 lcd_remote_scroll_info.lines++;
832 }
833}
834
835void lcd_remote_scroll_fn(void)
836{
837 struct font* pf;
838 struct scrollinfo* s;
839 int index;
840 int xpos, ypos;
841 int lastmode;
842 struct viewport* old_vp = current_vp;
843
844 for ( index = 0; index < lcd_remote_scroll_info.lines; index++ ) {
845 s = &lcd_remote_scroll_info.scroll[index];
846
847 /* check pause */
848 if (TIME_BEFORE(current_tick, s->start_tick))
849 continue;
850
851 lcd_remote_set_viewport(s->vp);
852
853 if (s->backward)
854 s->offset -= lcd_remote_scroll_info.step;
855 else
856 s->offset += lcd_remote_scroll_info.step;
857
858 pf = font_get(current_vp->font);
859 xpos = s->startx;
860 ypos = current_vp->ymargin + s->y * pf->height;
861
862 if (s->bidir) { /* scroll bidirectional */
863 if (s->offset <= 0) {
864 /* at beginning of line */
865 s->offset = 0;
866 s->backward = false;
867 s->start_tick = current_tick + lcd_remote_scroll_info.delay*2;
868 }
869 if (s->offset >= s->width - (current_vp->width - xpos)) {
870 /* at end of line */
871 s->offset = s->width - (current_vp->width - xpos);
872 s->backward = true;
873 s->start_tick = current_tick + lcd_remote_scroll_info.delay*2;
874 }
875 }
876 else {
877 /* scroll forward the whole time */
878 if (s->offset >= s->width)
879 s->offset %= s->width;
880 }
881
882 lastmode = current_vp->drawmode;
883 current_vp->drawmode = (s->style&STYLE_INVERT) ?
884 (DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID;
885 lcd_remote_putsxyofs(xpos, ypos, s->offset, s->line);
886 current_vp->drawmode = lastmode;
887 lcd_remote_update_viewport_rect(xpos, ypos,
888 current_vp->width - xpos, pf->height);
889 }
890
891 lcd_remote_set_viewport(old_vp);
892}
893
894/* LCD init */
895void lcd_remote_init(void)
896{
897#ifndef SIMULATOR
898 /* Call device specific init */
899 lcd_remote_init_device();
900#endif
901}