summaryrefslogtreecommitdiff
path: root/firmware/drivers/lcd-1bit-vert.c
diff options
context:
space:
mode:
authorJens Arnold <amiconn@rockbox.org>2006-11-12 13:22:59 +0000
committerJens Arnold <amiconn@rockbox.org>2006-11-12 13:22:59 +0000
commit6bdf3ee6f28097e25770ae43e28dd4b59054e88f (patch)
treefb95473e5753cb801c643e31b1b30033a33bafe6 /firmware/drivers/lcd-1bit-vert.c
parent3875b5766769a5f75d460614c0279aaad72e0922 (diff)
downloadrockbox-6bdf3ee6f28097e25770ae43e28dd4b59054e88f.tar.gz
rockbox-6bdf3ee6f28097e25770ae43e28dd4b59054e88f.zip
Split 1 bit LCD code and move appropriate parts to target tree. Only archos code is tested.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@11517 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware/drivers/lcd-1bit-vert.c')
-rwxr-xr-xfirmware/drivers/lcd-1bit-vert.c860
1 files changed, 860 insertions, 0 deletions
diff --git a/firmware/drivers/lcd-1bit-vert.c b/firmware/drivers/lcd-1bit-vert.c
new file mode 100755
index 0000000000..6ae92af72b
--- /dev/null
+++ b/firmware/drivers/lcd-1bit-vert.c
@@ -0,0 +1,860 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2002 by Alan Korr
11 *
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
19#include "config.h"
20
21#include "lcd.h"
22#include "kernel.h"
23#include "thread.h"
24#include <string.h>
25#include <stdlib.h>
26#include "file.h"
27#include "debug.h"
28#include "system.h"
29#include "font.h"
30#include "hwcompat.h"
31#include "rbunicode.h"
32#include "bidi.h"
33
34/*** definitions ***/
35
36#define SCROLLABLE_LINES ((LCD_HEIGHT+4)/5 < 32 ? (LCD_HEIGHT+4)/5 : 32)
37
38/*** globals ***/
39
40unsigned char lcd_framebuffer[LCD_HEIGHT/8][LCD_WIDTH];
41
42static int drawmode = DRMODE_SOLID;
43static int xmargin = 0;
44static int ymargin = 0;
45static int curfont = FONT_SYSFIXED;
46
47/* scrolling */
48static volatile int scrolling_lines=0; /* Bitpattern of which lines are scrolling */
49static void scroll_thread(void);
50static char scroll_stack[DEFAULT_STACK_SIZE];
51static const char scroll_name[] = "scroll";
52static int scroll_ticks = 12; /* # of ticks between updates*/
53static int scroll_delay = HZ/2; /* ticks delay before start */
54static int scroll_step = 6; /* pixels per scroll step */
55static int bidir_limit = 50; /* percent */
56static struct scrollinfo scroll[SCROLLABLE_LINES];
57
58static const char scroll_tick_table[16] = {
59 /* Hz values:
60 1, 1.25, 1.55, 2, 2.5, 3.12, 4, 5, 6.25, 8.33, 10, 12.5, 16.7, 20, 25, 33 */
61 100, 80, 64, 50, 40, 32, 25, 20, 16, 12, 10, 8, 6, 5, 4, 3
62};
63
64/* LCD init */
65void lcd_init(void)
66{
67 lcd_clear_display();
68 /* Call device specific init */
69 lcd_init_device();
70 create_thread(scroll_thread, scroll_stack,
71 sizeof(scroll_stack), scroll_name IF_PRIO(, PRIORITY_USER_INTERFACE));
72}
73
74/*** parameter handling ***/
75
76void lcd_set_drawmode(int mode)
77{
78 drawmode = mode & (DRMODE_SOLID|DRMODE_INVERSEVID);
79}
80
81int lcd_get_drawmode(void)
82{
83 return drawmode;
84}
85
86void lcd_setmargins(int x, int y)
87{
88 xmargin = x;
89 ymargin = y;
90}
91
92int lcd_getxmargin(void)
93{
94 return xmargin;
95}
96
97int lcd_getymargin(void)
98{
99 return ymargin;
100}
101
102void lcd_setfont(int newfont)
103{
104 curfont = newfont;
105}
106
107int lcd_getstringsize(const unsigned char *str, int *w, int *h)
108{
109 return font_getstringsize(str, w, h, curfont);
110}
111
112/*** low-level drawing functions ***/
113
114static void setpixel(int x, int y)
115{
116 lcd_framebuffer[y>>3][x] |= 1 << (y & 7);
117}
118
119static void clearpixel(int x, int y)
120{
121 lcd_framebuffer[y>>3][x] &= ~(1 << (y & 7));
122}
123
124static void flippixel(int x, int y)
125{
126 lcd_framebuffer[y>>3][x] ^= 1 << (y & 7);
127}
128
129static void nopixel(int x, int y)
130{
131 (void)x;
132 (void)y;
133}
134
135lcd_pixelfunc_type* const lcd_pixelfuncs[8] = {
136 flippixel, nopixel, setpixel, setpixel,
137 nopixel, clearpixel, nopixel, clearpixel
138};
139
140static void flipblock(unsigned char *address, unsigned mask, unsigned bits)
141 ICODE_ATTR;
142static void flipblock(unsigned char *address, unsigned mask, unsigned bits)
143{
144 *address ^= bits & mask;
145}
146
147static void bgblock(unsigned char *address, unsigned mask, unsigned bits)
148 ICODE_ATTR;
149static void bgblock(unsigned char *address, unsigned mask, unsigned bits)
150{
151 *address &= bits | ~mask;
152}
153
154static void fgblock(unsigned char *address, unsigned mask, unsigned bits)
155 ICODE_ATTR;
156static void fgblock(unsigned char *address, unsigned mask, unsigned bits)
157{
158 *address |= bits & mask;
159}
160
161static void solidblock(unsigned char *address, unsigned mask, unsigned bits)
162 ICODE_ATTR;
163static void solidblock(unsigned char *address, unsigned mask, unsigned bits)
164{
165 unsigned data = *(char*)address;
166
167 bits ^= data;
168 *address = data ^ (bits & mask);
169}
170
171static void flipinvblock(unsigned char *address, unsigned mask, unsigned bits)
172 ICODE_ATTR;
173static void flipinvblock(unsigned char *address, unsigned mask, unsigned bits)
174{
175 *address ^= ~bits & mask;
176}
177
178static void bginvblock(unsigned char *address, unsigned mask, unsigned bits)
179 ICODE_ATTR;
180static void bginvblock(unsigned char *address, unsigned mask, unsigned bits)
181{
182 *address &= ~(bits & mask);
183}
184
185static void fginvblock(unsigned char *address, unsigned mask, unsigned bits)
186 ICODE_ATTR;
187static void fginvblock(unsigned char *address, unsigned mask, unsigned bits)
188{
189 *address |= ~bits & mask;
190}
191
192static void solidinvblock(unsigned char *address, unsigned mask, unsigned bits)
193 ICODE_ATTR;
194static void solidinvblock(unsigned char *address, unsigned mask, unsigned bits)
195{
196 unsigned data = *(char *)address;
197
198 bits = ~bits ^ data;
199 *address = data ^ (bits & mask);
200}
201
202lcd_blockfunc_type* const lcd_blockfuncs[8] = {
203 flipblock, bgblock, fgblock, solidblock,
204 flipinvblock, bginvblock, fginvblock, solidinvblock
205};
206
207/*** drawing functions ***/
208
209/* Clear the whole display */
210void lcd_clear_display(void)
211{
212 unsigned bits = (drawmode & DRMODE_INVERSEVID) ? 0xFFu : 0;
213
214 memset(lcd_framebuffer, bits, sizeof lcd_framebuffer);
215 scrolling_lines = 0;
216}
217
218/* Set a single pixel */
219void lcd_drawpixel(int x, int y)
220{
221 if (((unsigned)x < LCD_WIDTH) && ((unsigned)y < LCD_HEIGHT))
222 lcd_pixelfuncs[drawmode](x, y);
223}
224
225/* Draw a line */
226void lcd_drawline(int x1, int y1, int x2, int y2)
227{
228 int numpixels;
229 int i;
230 int deltax, deltay;
231 int d, dinc1, dinc2;
232 int x, xinc1, xinc2;
233 int y, yinc1, yinc2;
234 lcd_pixelfunc_type *pfunc = lcd_pixelfuncs[drawmode];
235
236 deltax = abs(x2 - x1);
237 deltay = abs(y2 - y1);
238 xinc2 = 1;
239 yinc2 = 1;
240
241 if (deltax >= deltay)
242 {
243 numpixels = deltax;
244 d = 2 * deltay - deltax;
245 dinc1 = deltay * 2;
246 dinc2 = (deltay - deltax) * 2;
247 xinc1 = 1;
248 yinc1 = 0;
249 }
250 else
251 {
252 numpixels = deltay;
253 d = 2 * deltax - deltay;
254 dinc1 = deltax * 2;
255 dinc2 = (deltax - deltay) * 2;
256 xinc1 = 0;
257 yinc1 = 1;
258 }
259 numpixels++; /* include endpoints */
260
261 if (x1 > x2)
262 {
263 xinc1 = -xinc1;
264 xinc2 = -xinc2;
265 }
266
267 if (y1 > y2)
268 {
269 yinc1 = -yinc1;
270 yinc2 = -yinc2;
271 }
272
273 x = x1;
274 y = y1;
275
276 for (i = 0; i < numpixels; i++)
277 {
278 if (((unsigned)x < LCD_WIDTH) && ((unsigned)y < LCD_HEIGHT))
279 pfunc(x, y);
280
281 if (d < 0)
282 {
283 d += dinc1;
284 x += xinc1;
285 y += yinc1;
286 }
287 else
288 {
289 d += dinc2;
290 x += xinc2;
291 y += yinc2;
292 }
293 }
294}
295
296/* Draw a horizontal line (optimised) */
297void lcd_hline(int x1, int x2, int y)
298{
299 int x;
300 unsigned char *dst, *dst_end;
301 unsigned mask;
302 lcd_blockfunc_type *bfunc;
303
304 /* direction flip */
305 if (x2 < x1)
306 {
307 x = x1;
308 x1 = x2;
309 x2 = x;
310 }
311
312 /* nothing to draw? */
313 if (((unsigned)y >= LCD_HEIGHT) || (x1 >= LCD_WIDTH) || (x2 < 0))
314 return;
315
316 /* clipping */
317 if (x1 < 0)
318 x1 = 0;
319 if (x2 >= LCD_WIDTH)
320 x2 = LCD_WIDTH-1;
321
322 bfunc = lcd_blockfuncs[drawmode];
323 dst = &lcd_framebuffer[y>>3][x1];
324 mask = 1 << (y & 7);
325
326 dst_end = dst + x2 - x1;
327 do
328 bfunc(dst++, mask, 0xFFu);
329 while (dst <= dst_end);
330}
331
332/* Draw a vertical line (optimised) */
333void lcd_vline(int x, int y1, int y2)
334{
335 int ny;
336 unsigned char *dst;
337 unsigned mask, mask_bottom;
338 lcd_blockfunc_type *bfunc;
339
340 /* direction flip */
341 if (y2 < y1)
342 {
343 ny = y1;
344 y1 = y2;
345 y2 = ny;
346 }
347
348 /* nothing to draw? */
349 if (((unsigned)x >= LCD_WIDTH) || (y1 >= LCD_HEIGHT) || (y2 < 0))
350 return;
351
352 /* clipping */
353 if (y1 < 0)
354 y1 = 0;
355 if (y2 >= LCD_HEIGHT)
356 y2 = LCD_HEIGHT-1;
357
358 bfunc = lcd_blockfuncs[drawmode];
359 dst = &lcd_framebuffer[y1>>3][x];
360 ny = y2 - (y1 & ~7);
361 mask = 0xFFu << (y1 & 7);
362 mask_bottom = 0xFFu >> (~ny & 7);
363
364 for (; ny >= 8; ny -= 8)
365 {
366 bfunc(dst, mask, 0xFFu);
367 dst += LCD_WIDTH;
368 mask = 0xFFu;
369 }
370 mask &= mask_bottom;
371 bfunc(dst, mask, 0xFFu);
372}
373
374/* Draw a rectangular box */
375void lcd_drawrect(int x, int y, int width, int height)
376{
377 if ((width <= 0) || (height <= 0))
378 return;
379
380 int x2 = x + width - 1;
381 int y2 = y + height - 1;
382
383 lcd_vline(x, y, y2);
384 lcd_vline(x2, y, y2);
385 lcd_hline(x, x2, y);
386 lcd_hline(x, x2, y2);
387}
388
389/* Fill a rectangular area */
390void lcd_fillrect(int x, int y, int width, int height)
391{
392 int ny;
393 unsigned char *dst, *dst_end;
394 unsigned mask, mask_bottom;
395 unsigned bits = 0;
396 lcd_blockfunc_type *bfunc;
397 bool fillopt = false;
398
399 /* nothing to draw? */
400 if ((width <= 0) || (height <= 0) || (x >= LCD_WIDTH) || (y >= LCD_HEIGHT)
401 || (x + width <= 0) || (y + height <= 0))
402 return;
403
404 /* clipping */
405 if (x < 0)
406 {
407 width += x;
408 x = 0;
409 }
410 if (y < 0)
411 {
412 height += y;
413 y = 0;
414 }
415 if (x + width > LCD_WIDTH)
416 width = LCD_WIDTH - x;
417 if (y + height > LCD_HEIGHT)
418 height = LCD_HEIGHT - y;
419
420 if (drawmode & DRMODE_INVERSEVID)
421 {
422 if (drawmode & DRMODE_BG)
423 {
424 fillopt = true;
425 }
426 }
427 else
428 {
429 if (drawmode & DRMODE_FG)
430 {
431 fillopt = true;
432 bits = 0xFFu;
433 }
434 }
435 bfunc = lcd_blockfuncs[drawmode];
436 dst = &lcd_framebuffer[y>>3][x];
437 ny = height - 1 + (y & 7);
438 mask = 0xFFu << (y & 7);
439 mask_bottom = 0xFFu >> (~ny & 7);
440
441 for (; ny >= 8; ny -= 8)
442 {
443 if (fillopt && (mask == 0xFFu))
444 memset(dst, bits, width);
445 else
446 {
447 unsigned char *dst_row = dst;
448
449 dst_end = dst_row + width;
450 do
451 bfunc(dst_row++, mask, 0xFFu);
452 while (dst_row < dst_end);
453 }
454
455 dst += LCD_WIDTH;
456 mask = 0xFFu;
457 }
458 mask &= mask_bottom;
459
460 if (fillopt && (mask == 0xFFu))
461 memset(dst, bits, width);
462 else
463 {
464 dst_end = dst + width;
465 do
466 bfunc(dst++, mask, 0xFFu);
467 while (dst < dst_end);
468 }
469}
470
471/* About Rockbox' internal bitmap format:
472 *
473 * A bitmap contains one bit for every pixel that defines if that pixel is
474 * black (1) or white (0). Bits within a byte are arranged vertically, LSB
475 * at top.
476 * The bytes are stored in row-major order, with byte 0 being top left,
477 * byte 1 2nd from left etc. The first row of bytes defines pixel rows
478 * 0..7, the second row defines pixel row 8..15 etc.
479 *
480 * This is the same as the internal lcd hw format. */
481
482/* Draw a partial bitmap */
483void lcd_bitmap_part(const unsigned char *src, int src_x, int src_y,
484 int stride, int x, int y, int width, int height)
485 ICODE_ATTR;
486void lcd_bitmap_part(const unsigned char *src, int src_x, int src_y,
487 int stride, int x, int y, int width, int height)
488{
489 int shift, ny;
490 unsigned char *dst, *dst_end;
491 unsigned mask, mask_bottom;
492 lcd_blockfunc_type *bfunc;
493
494 /* nothing to draw? */
495 if ((width <= 0) || (height <= 0) || (x >= LCD_WIDTH) || (y >= LCD_HEIGHT)
496 || (x + width <= 0) || (y + height <= 0))
497 return;
498
499 /* clipping */
500 if (x < 0)
501 {
502 width += x;
503 src_x -= x;
504 x = 0;
505 }
506 if (y < 0)
507 {
508 height += y;
509 src_y -= y;
510 y = 0;
511 }
512 if (x + width > LCD_WIDTH)
513 width = LCD_WIDTH - x;
514 if (y + height > LCD_HEIGHT)
515 height = LCD_HEIGHT - y;
516
517 src += stride * (src_y >> 3) + src_x; /* move starting point */
518 src_y &= 7;
519 y -= src_y;
520 dst = &lcd_framebuffer[y>>3][x];
521 shift = y & 7;
522 ny = height - 1 + shift + src_y;
523
524 bfunc = lcd_blockfuncs[drawmode];
525 mask = 0xFFu << (shift + src_y);
526 mask_bottom = 0xFFu >> (~ny & 7);
527
528 if (shift == 0)
529 {
530 bool copyopt = (drawmode == DRMODE_SOLID);
531
532 for (; ny >= 8; ny -= 8)
533 {
534 if (copyopt && (mask == 0xFFu))
535 memcpy(dst, src, width);
536 else
537 {
538 const unsigned char *src_row = src;
539 unsigned char *dst_row = dst;
540
541 dst_end = dst_row + width;
542 do
543 bfunc(dst_row++, mask, *src_row++);
544 while (dst_row < dst_end);
545 }
546
547 src += stride;
548 dst += LCD_WIDTH;
549 mask = 0xFFu;
550 }
551 mask &= mask_bottom;
552
553 if (copyopt && (mask == 0xFFu))
554 memcpy(dst, src, width);
555 else
556 {
557 dst_end = dst + width;
558 do
559 bfunc(dst++, mask, *src++);
560 while (dst < dst_end);
561 }
562 }
563 else
564 {
565 dst_end = dst + width;
566 do
567 {
568 const unsigned char *src_col = src++;
569 unsigned char *dst_col = dst++;
570 unsigned mask_col = mask;
571 unsigned data = 0;
572
573 for (y = ny; y >= 8; y -= 8)
574 {
575 data |= *src_col << shift;
576
577 if (mask_col & 0xFFu)
578 {
579 bfunc(dst_col, mask_col, data);
580 mask_col = 0xFFu;
581 }
582 else
583 mask_col >>= 8;
584
585 src_col += stride;
586 dst_col += LCD_WIDTH;
587 data >>= 8;
588 }
589 data |= *src_col << shift;
590 bfunc(dst_col, mask_col & mask_bottom, data);
591 }
592 while (dst < dst_end);
593 }
594}
595
596/* Draw a full bitmap */
597void lcd_bitmap(const unsigned char *src, int x, int y, int width, int height)
598{
599 lcd_bitmap_part(src, 0, 0, width, x, y, width, height);
600}
601
602/* put a string at a given pixel position, skipping first ofs pixel columns */
603static void lcd_putsxyofs(int x, int y, int ofs, const unsigned char *str)
604{
605 unsigned short ch;
606 unsigned short *ucs;
607 struct font* pf = font_get(curfont);
608
609 ucs = bidi_l2v(str, 1);
610
611 while ((ch = *ucs++) != 0 && x < LCD_WIDTH)
612 {
613 int width;
614 const unsigned char *bits;
615
616 /* get proportional width and glyph bits */
617 width = font_get_width(pf,ch);
618
619 if (ofs > width)
620 {
621 ofs -= width;
622 continue;
623 }
624
625 bits = font_get_bits(pf, ch);
626
627 lcd_mono_bitmap_part(bits, ofs, 0, width, x, y, width - ofs,
628 pf->height);
629
630 x += width - ofs;
631 ofs = 0;
632 }
633}
634/* put a string at a given pixel position */
635void lcd_putsxy(int x, int y, const unsigned char *str)
636{
637 lcd_putsxyofs(x, y, 0, str);
638}
639
640/*** Line oriented text output ***/
641
642/* put a string at a given char position */
643void lcd_puts(int x, int y, const unsigned char *str)
644{
645 lcd_puts_style_offset(x, y, str, STYLE_DEFAULT, 0);
646}
647
648void lcd_puts_style(int x, int y, const unsigned char *str, int style)
649{
650 lcd_puts_style_offset(x, y, str, style, 0);
651}
652
653void lcd_puts_offset(int x, int y, const unsigned char *str, int offset)
654{
655 lcd_puts_style_offset(x, y, str, STYLE_DEFAULT, offset);
656}
657
658/* put a string at a given char position, style, and pixel position,
659 * skipping first offset pixel columns */
660void lcd_puts_style_offset(int x, int y, const unsigned char *str,
661 int style, int offset)
662{
663 int xpos,ypos,w,h,xrect;
664 int lastmode = drawmode;
665
666 /* make sure scrolling is turned off on the line we are updating */
667 scrolling_lines &= ~(1 << y);
668
669 if(!str || !str[0])
670 return;
671
672 lcd_getstringsize(str, &w, &h);
673 xpos = xmargin + x*w / utf8length(str);
674 ypos = ymargin + y*h;
675 drawmode = (style & STYLE_INVERT) ?
676 (DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID;
677 lcd_putsxyofs(xpos, ypos, offset, str);
678 drawmode ^= DRMODE_INVERSEVID;
679 xrect = xpos + MAX(w - offset, 0);
680 lcd_fillrect(xrect, ypos, LCD_WIDTH - xrect, h);
681 drawmode = lastmode;
682}
683
684/*** scrolling ***/
685
686/* Reverse the invert setting of the scrolling line (if any) at given char
687 position. Setting will go into affect next time line scrolls. */
688void lcd_invertscroll(int x, int y)
689{
690 struct scrollinfo* s;
691
692 (void)x;
693
694 s = &scroll[y];
695 s->invert = !s->invert;
696}
697
698void lcd_stop_scroll(void)
699{
700 scrolling_lines=0;
701}
702
703void lcd_scroll_speed(int speed)
704{
705 scroll_ticks = scroll_tick_table[speed];
706}
707
708void lcd_scroll_step(int step)
709{
710 scroll_step = step;
711}
712
713void lcd_scroll_delay(int ms)
714{
715 scroll_delay = ms / (HZ / 10);
716}
717
718void lcd_bidir_scroll(int percent)
719{
720 bidir_limit = percent;
721}
722
723void lcd_puts_scroll(int x, int y, const unsigned char *string)
724{
725 lcd_puts_scroll_style(x, y, string, STYLE_DEFAULT);
726}
727
728void lcd_puts_scroll_style(int x, int y, const unsigned char *string, int style)
729{
730 lcd_puts_scroll_style_offset(x, y, string, style, 0);
731}
732
733void lcd_puts_scroll_offset(int x, int y, const unsigned char *string,
734 int offset)
735{
736 lcd_puts_scroll_style_offset(x, y, string, STYLE_DEFAULT, offset);
737}
738
739void lcd_puts_scroll_style_offset(int x, int y, const unsigned char *string,
740 int style, int offset)
741{
742 struct scrollinfo* s;
743 int w, h;
744
745 s = &scroll[y];
746
747 s->start_tick = current_tick + scroll_delay;
748 s->invert = false;
749 if (style & STYLE_INVERT) {
750 s->invert = true;
751 lcd_puts_style_offset(x,y,string,STYLE_INVERT,offset);
752 }
753 else
754 lcd_puts_offset(x,y,string,offset);
755
756 lcd_getstringsize(string, &w, &h);
757
758 if (LCD_WIDTH - x * 8 - xmargin < w) {
759 /* prepare scroll line */
760 char *end;
761
762 memset(s->line, 0, sizeof s->line);
763 strcpy(s->line, string);
764
765 /* get width */
766 s->width = lcd_getstringsize(s->line, &w, &h);
767
768 /* scroll bidirectional or forward only depending on the string
769 width */
770 if ( bidir_limit ) {
771 s->bidir = s->width < (LCD_WIDTH - xmargin) *
772 (100 + bidir_limit) / 100;
773 }
774 else
775 s->bidir = false;
776
777 if (!s->bidir) { /* add spaces if scrolling in the round */
778 strcat(s->line, " ");
779 /* get new width incl. spaces */
780 s->width = lcd_getstringsize(s->line, &w, &h);
781 }
782
783 end = strchr(s->line, '\0');
784 strncpy(end, string, LCD_WIDTH/2);
785
786 s->len = utf8length(string);
787 s->offset = offset;
788 s->startx = xmargin + x * s->width / s->len;;
789 s->backward = false;
790 scrolling_lines |= (1<<y);
791 }
792 else
793 /* force a bit switch-off since it doesn't scroll */
794 scrolling_lines &= ~(1<<y);
795}
796
797static void scroll_thread(void)
798{
799 struct font* pf;
800 struct scrollinfo* s;
801 int index;
802 int xpos, ypos;
803 int lastmode;
804
805 /* initialize scroll struct array */
806 scrolling_lines = 0;
807
808 while ( 1 ) {
809 for ( index = 0; index < SCROLLABLE_LINES; index++ ) {
810 /* really scroll? */
811 if ( !(scrolling_lines&(1<<index)) )
812 continue;
813
814 s = &scroll[index];
815
816 /* check pause */
817 if (TIME_BEFORE(current_tick, s->start_tick))
818 continue;
819
820 if (s->backward)
821 s->offset -= scroll_step;
822 else
823 s->offset += scroll_step;
824
825 pf = font_get(curfont);
826 xpos = s->startx;
827 ypos = ymargin + index * pf->height;
828
829 if (s->bidir) { /* scroll bidirectional */
830 if (s->offset <= 0) {
831 /* at beginning of line */
832 s->offset = 0;
833 s->backward = false;
834 s->start_tick = current_tick + scroll_delay * 2;
835 }
836 if (s->offset >= s->width - (LCD_WIDTH - xpos)) {
837 /* at end of line */
838 s->offset = s->width - (LCD_WIDTH - xpos);
839 s->backward = true;
840 s->start_tick = current_tick + scroll_delay * 2;
841 }
842 }
843 else {
844 /* scroll forward the whole time */
845 if (s->offset >= s->width)
846 s->offset %= s->width;
847 }
848
849 lastmode = drawmode;
850 drawmode = s->invert ?
851 (DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID;
852 lcd_putsxyofs(xpos, ypos, s->offset, s->line);
853 drawmode = lastmode;
854 lcd_update_rect(xpos, ypos, LCD_WIDTH - xpos, pf->height);
855 }
856
857 sleep(scroll_ticks);
858 }
859}
860