1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2004 by Linus Nielsen Feltzing
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.
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
18 ****************************************************************************/
31 #include "rbunicode.h"
33 #include "scroll_engine.h"
37 fb_data lcd_framebuffer
[LCD_FBHEIGHT
][LCD_FBWIDTH
] IBSS_ATTR
;
39 const unsigned char lcd_dibits
[16] ICONST_ATTR
= {
40 0x00, 0x03, 0x0C, 0x0F, 0x30, 0x33, 0x3C, 0x3F,
41 0xC0, 0xC3, 0xCC, 0xCF, 0xF0, 0xF3, 0xFC, 0xFF
44 static const unsigned char pixmask
[4] ICONST_ATTR
= {
45 0x03, 0x0C, 0x30, 0xC0
48 static fb_data
* lcd_backdrop
= NULL
;
49 static long lcd_backdrop_offset IDATA_ATTR
= 0;
51 static unsigned fg_pattern IDATA_ATTR
= 0xFF; /* initially black */
52 static unsigned bg_pattern IDATA_ATTR
= 0x00; /* initially white */
53 static int drawmode
= DRMODE_SOLID
;
54 static int xmargin
= 0;
55 static int ymargin
= 0;
56 static int curfont
= FONT_SYSFIXED
;
62 /* Call device specific init */
67 /*** parameter handling ***/
69 void lcd_set_drawmode(int mode
)
71 drawmode
= mode
& (DRMODE_SOLID
|DRMODE_INVERSEVID
);
74 int lcd_get_drawmode(void)
79 void lcd_set_foreground(unsigned brightness
)
81 fg_pattern
= 0x55 * (~brightness
& 3);
84 unsigned lcd_get_foreground(void)
86 return ~fg_pattern
& 3;
89 void lcd_set_background(unsigned brightness
)
91 bg_pattern
= 0x55 * (~brightness
& 3);
94 unsigned lcd_get_background(void)
96 return ~bg_pattern
& 3;
99 void lcd_set_drawinfo(int mode
, unsigned fg_brightness
, unsigned bg_brightness
)
101 lcd_set_drawmode(mode
);
102 lcd_set_foreground(fg_brightness
);
103 lcd_set_background(bg_brightness
);
106 void lcd_setmargins(int x
, int y
)
112 int lcd_getxmargin(void)
117 int lcd_getymargin(void)
122 void lcd_setfont(int newfont
)
127 int lcd_getstringsize(const unsigned char *str
, int *w
, int *h
)
129 return font_getstringsize(str
, w
, h
, curfont
);
132 /*** low-level drawing functions ***/
134 static void setpixel(int x
, int y
)
136 unsigned mask
= pixmask
[y
& 3];
137 fb_data
*address
= &lcd_framebuffer
[y
>>2][x
];
138 unsigned data
= *address
;
140 *address
= data
^ ((data
^ fg_pattern
) & mask
);
143 static void clearpixel(int x
, int y
)
145 unsigned mask
= pixmask
[y
& 3];
146 fb_data
*address
= &lcd_framebuffer
[y
>>2][x
];
147 unsigned data
= *address
;
149 *address
= data
^ ((data
^ bg_pattern
) & mask
);
152 static void clearimgpixel(int x
, int y
)
154 unsigned mask
= pixmask
[y
& 3];
155 fb_data
*address
= &lcd_framebuffer
[y
>>2][x
];
156 unsigned data
= *address
;
158 *address
= data
^ ((data
^ *(address
+ lcd_backdrop_offset
)) & mask
);
161 static void flippixel(int x
, int y
)
163 unsigned mask
= pixmask
[y
& 3];
164 fb_data
*address
= &lcd_framebuffer
[y
>>2][x
];
169 static void nopixel(int x
, int y
)
175 lcd_pixelfunc_type
* const lcd_pixelfuncs_bgcolor
[8] = {
176 flippixel
, nopixel
, setpixel
, setpixel
,
177 nopixel
, clearpixel
, nopixel
, clearpixel
180 lcd_pixelfunc_type
* const lcd_pixelfuncs_backdrop
[8] = {
181 flippixel
, nopixel
, setpixel
, setpixel
,
182 nopixel
, clearimgpixel
, nopixel
, clearimgpixel
186 lcd_pixelfunc_type
* const * lcd_pixelfuncs
= lcd_pixelfuncs_bgcolor
;
188 /* 'mask' and 'bits' contain 2 bits per pixel */
189 static void flipblock(fb_data
*address
, unsigned mask
, unsigned bits
)
191 static void flipblock(fb_data
*address
, unsigned mask
, unsigned bits
)
193 *address
^= bits
& mask
;
196 static void bgblock(fb_data
*address
, unsigned mask
, unsigned bits
)
198 static void bgblock(fb_data
*address
, unsigned mask
, unsigned bits
)
200 unsigned data
= *address
;
202 *address
= data
^ ((data
^ bg_pattern
) & mask
& ~bits
);
205 static void bgimgblock(fb_data
*address
, unsigned mask
, unsigned bits
)
207 static void bgimgblock(fb_data
*address
, unsigned mask
, unsigned bits
)
209 unsigned data
= *address
;
211 *address
= data
^ ((data
^ *(address
+ lcd_backdrop_offset
)) & mask
& ~bits
);
214 static void fgblock(fb_data
*address
, unsigned mask
, unsigned bits
)
216 static void fgblock(fb_data
*address
, unsigned mask
, unsigned bits
)
218 unsigned data
= *address
;
220 *address
= data
^ ((data
^ fg_pattern
) & mask
& bits
);
223 static void solidblock(fb_data
*address
, unsigned mask
, unsigned bits
)
225 static void solidblock(fb_data
*address
, unsigned mask
, unsigned bits
)
227 unsigned data
= *address
;
228 unsigned bgp
= bg_pattern
;
230 bits
= bgp
^ ((bgp
^ fg_pattern
) & bits
);
231 *address
= data
^ ((data
^ bits
) & mask
);
234 static void solidimgblock(fb_data
*address
, unsigned mask
, unsigned bits
)
236 static void solidimgblock(fb_data
*address
, unsigned mask
, unsigned bits
)
238 unsigned data
= *address
;
239 unsigned bgp
= *(address
+ lcd_backdrop_offset
);
241 bits
= bgp
^ ((bgp
^ fg_pattern
) & bits
);
242 *address
= data
^ ((data
^ bits
) & mask
);
245 static void flipinvblock(fb_data
*address
, unsigned mask
, unsigned bits
)
247 static void flipinvblock(fb_data
*address
, unsigned mask
, unsigned bits
)
249 *address
^= ~bits
& mask
;
252 static void bginvblock(fb_data
*address
, unsigned mask
, unsigned bits
)
254 static void bginvblock(fb_data
*address
, unsigned mask
, unsigned bits
)
256 unsigned data
= *address
;
258 *address
= data
^ ((data
^ bg_pattern
) & mask
& bits
);
261 static void bgimginvblock(fb_data
*address
, unsigned mask
, unsigned bits
)
263 static void bgimginvblock(fb_data
*address
, unsigned mask
, unsigned bits
)
265 unsigned data
= *address
;
267 *address
= data
^ ((data
^ *(address
+ lcd_backdrop_offset
)) & mask
& bits
);
270 static void fginvblock(fb_data
*address
, unsigned mask
, unsigned bits
)
272 static void fginvblock(fb_data
*address
, unsigned mask
, unsigned bits
)
274 unsigned data
= *address
;
276 *address
= data
^ ((data
^ fg_pattern
) & mask
& ~bits
);
279 static void solidinvblock(fb_data
*address
, unsigned mask
, unsigned bits
)
281 static void solidinvblock(fb_data
*address
, unsigned mask
, unsigned bits
)
283 unsigned data
= *address
;
284 unsigned fgp
= fg_pattern
;
286 bits
= fgp
^ ((fgp
^ bg_pattern
) & bits
);
287 *address
= data
^ ((data
^ bits
) & mask
);
290 static void solidimginvblock(fb_data
*address
, unsigned mask
, unsigned bits
)
292 static void solidimginvblock(fb_data
*address
, unsigned mask
, unsigned bits
)
294 unsigned data
= *address
;
295 unsigned fgp
= fg_pattern
;
297 bits
= fgp
^ ((fgp
^ *(address
+ lcd_backdrop_offset
)) & bits
);
298 *address
= data
^ ((data
^ bits
) & mask
);
301 lcd_blockfunc_type
* const lcd_blockfuncs_bgcolor
[8] = {
302 flipblock
, bgblock
, fgblock
, solidblock
,
303 flipinvblock
, bginvblock
, fginvblock
, solidinvblock
306 lcd_blockfunc_type
* const lcd_blockfuncs_backdrop
[8] = {
307 flipblock
, bgimgblock
, fgblock
, solidimgblock
,
308 flipinvblock
, bgimginvblock
, fginvblock
, solidimginvblock
311 lcd_blockfunc_type
* const * lcd_blockfuncs
= lcd_blockfuncs_bgcolor
;
314 void lcd_set_backdrop(fb_data
* backdrop
)
316 lcd_backdrop
= backdrop
;
319 lcd_backdrop_offset
= (long)backdrop
- (long)lcd_framebuffer
;
320 lcd_pixelfuncs
= lcd_pixelfuncs_backdrop
;
321 lcd_blockfuncs
= lcd_blockfuncs_backdrop
;
325 lcd_backdrop_offset
= 0;
326 lcd_pixelfuncs
= lcd_pixelfuncs_bgcolor
;
327 lcd_blockfuncs
= lcd_blockfuncs_bgcolor
;
331 fb_data
* lcd_get_backdrop(void)
337 static inline void setblock(fb_data
*address
, unsigned mask
, unsigned bits
)
339 unsigned data
= *address
;
342 *address
= data
^ (bits
& mask
);
345 /*** drawing functions ***/
347 /* Clear the whole display */
348 void lcd_clear_display(void)
350 if (drawmode
& DRMODE_INVERSEVID
)
352 memset(lcd_framebuffer
, fg_pattern
, sizeof lcd_framebuffer
);
357 memcpy(lcd_framebuffer
, lcd_backdrop
, sizeof lcd_framebuffer
);
359 memset(lcd_framebuffer
, bg_pattern
, sizeof lcd_framebuffer
);
362 lcd_scroll_info
.lines
= 0;
365 /* Set a single pixel */
366 void lcd_drawpixel(int x
, int y
)
368 if (((unsigned)x
< LCD_WIDTH
) && ((unsigned)y
< LCD_HEIGHT
))
369 lcd_pixelfuncs
[drawmode
](x
, y
);
373 void lcd_drawline(int x1
, int y1
, int x2
, int y2
)
381 lcd_pixelfunc_type
*pfunc
= lcd_pixelfuncs
[drawmode
];
383 deltax
= abs(x2
- x1
);
384 deltay
= abs(y2
- y1
);
388 if (deltax
>= deltay
)
391 d
= 2 * deltay
- deltax
;
393 dinc2
= (deltay
- deltax
) * 2;
400 d
= 2 * deltax
- deltay
;
402 dinc2
= (deltax
- deltay
) * 2;
406 numpixels
++; /* include endpoints */
423 for (i
= 0; i
< numpixels
; i
++)
425 if (((unsigned)x
< LCD_WIDTH
) && ((unsigned)y
< LCD_HEIGHT
))
443 /* Draw a horizontal line (optimised) */
444 void lcd_hline(int x1
, int x2
, int y
)
447 fb_data
*dst
, *dst_end
;
449 lcd_blockfunc_type
*bfunc
;
459 /* nothing to draw? */
460 if (((unsigned)y
>= LCD_HEIGHT
) || (x1
>= LCD_WIDTH
) || (x2
< 0))
469 bfunc
= lcd_blockfuncs
[drawmode
];
470 dst
= &lcd_framebuffer
[y
>>2][x1
];
471 mask
= pixmask
[y
& 3];
473 dst_end
= dst
+ x2
- x1
;
475 bfunc(dst
++, mask
, 0xFFu
);
476 while (dst
<= dst_end
);
479 /* Draw a vertical line (optimised) */
480 void lcd_vline(int x
, int y1
, int y2
)
484 unsigned mask
, mask_bottom
;
485 lcd_blockfunc_type
*bfunc
;
495 /* nothing to draw? */
496 if (((unsigned)x
>= LCD_WIDTH
) || (y1
>= LCD_HEIGHT
) || (y2
< 0))
502 if (y2
>= LCD_HEIGHT
)
505 bfunc
= lcd_blockfuncs
[drawmode
];
506 dst
= &lcd_framebuffer
[y1
>>2][x
];
508 mask
= 0xFFu
<< (2 * (y1
& 3));
509 mask_bottom
= 0xFFu
>> (2 * (~ny
& 3));
511 for (; ny
>= 4; ny
-= 4)
513 bfunc(dst
, mask
, 0xFFu
);
518 bfunc(dst
, mask
, 0xFFu
);
521 /* Draw a rectangular box */
522 void lcd_drawrect(int x
, int y
, int width
, int height
)
524 if ((width
<= 0) || (height
<= 0))
527 int x2
= x
+ width
- 1;
528 int y2
= y
+ height
- 1;
531 lcd_vline(x2
, y
, y2
);
533 lcd_hline(x
, x2
, y2
);
536 /* Fill a rectangular area */
537 void lcd_fillrect(int x
, int y
, int width
, int height
)
540 fb_data
*dst
, *dst_end
;
541 unsigned mask
, mask_bottom
;
543 lcd_blockfunc_type
*bfunc
;
544 bool fillopt
= false;
546 /* nothing to draw? */
547 if ((width
<= 0) || (height
<= 0) || (x
>= LCD_WIDTH
) || (y
>= LCD_HEIGHT
)
548 || (x
+ width
<= 0) || (y
+ height
<= 0))
562 if (x
+ width
> LCD_WIDTH
)
563 width
= LCD_WIDTH
- x
;
564 if (y
+ height
> LCD_HEIGHT
)
565 height
= LCD_HEIGHT
- y
;
567 if (drawmode
& DRMODE_INVERSEVID
)
569 if ((drawmode
& DRMODE_BG
) && !lcd_backdrop
)
577 if (drawmode
& DRMODE_FG
)
583 bfunc
= lcd_blockfuncs
[drawmode
];
584 dst
= &lcd_framebuffer
[y
>>2][x
];
585 ny
= height
- 1 + (y
& 3);
586 mask
= 0xFFu
<< (2 * (y
& 3));
587 mask_bottom
= 0xFFu
>> (2 * (~ny
& 3));
589 for (; ny
>= 4; ny
-= 4)
591 if (fillopt
&& (mask
== 0xFFu
))
592 memset(dst
, bits
, width
);
595 fb_data
*dst_row
= dst
;
597 dst_end
= dst_row
+ width
;
599 bfunc(dst_row
++, mask
, 0xFFu
);
600 while (dst_row
< dst_end
);
608 if (fillopt
&& (mask
== 0xFFu
))
609 memset(dst
, bits
, width
);
612 dst_end
= dst
+ width
;
614 bfunc(dst
++, mask
, 0xFFu
);
615 while (dst
< dst_end
);
619 /* About Rockbox' internal monochrome bitmap format:
621 * A bitmap contains one bit for every pixel that defines if that pixel is
622 * black (1) or white (0). Bits within a byte are arranged vertically, LSB
624 * The bytes are stored in row-major order, with byte 0 being top left,
625 * byte 1 2nd from left etc. The first row of bytes defines pixel rows
626 * 0..7, the second row defines pixel row 8..15 etc.
628 * This is similar to the internal lcd hw format. */
630 /* Draw a partial monochrome bitmap */
631 void lcd_mono_bitmap_part(const unsigned char *src
, int src_x
, int src_y
,
632 int stride
, int x
, int y
, int width
, int height
)
634 void lcd_mono_bitmap_part(const unsigned char *src
, int src_x
, int src_y
,
635 int stride
, int x
, int y
, int width
, int height
)
638 fb_data
*dst
, *dst_end
;
639 unsigned mask
, mask_bottom
;
640 lcd_blockfunc_type
*bfunc
;
642 /* nothing to draw? */
643 if ((width
<= 0) || (height
<= 0) || (x
>= LCD_WIDTH
) || (y
>= LCD_HEIGHT
)
644 || (x
+ width
<= 0) || (y
+ height
<= 0))
660 if (x
+ width
> LCD_WIDTH
)
661 width
= LCD_WIDTH
- x
;
662 if (y
+ height
> LCD_HEIGHT
)
663 height
= LCD_HEIGHT
- y
;
665 src
+= stride
* (src_y
>> 3) + src_x
; /* move starting point */
668 dst
= &lcd_framebuffer
[y
>>2][x
];
670 ny
= height
- 1 + shift
+ src_y
;
672 bfunc
= lcd_blockfuncs
[drawmode
];
673 mask
= 0xFFu
<< (shift
+ src_y
);
674 mask_bottom
= 0xFFu
>> (~ny
& 7);
678 unsigned dmask1
, dmask2
, data
;
680 for (; ny
>= 8; ny
-= 8)
682 const unsigned char *src_row
= src
;
683 fb_data
*dst_row
= dst
+ LCD_WIDTH
;
685 dmask1
= lcd_dibits
[mask
&0x0F];
686 dmask2
= lcd_dibits
[(mask
>>4)&0x0F];
687 dst_end
= dst_row
+ width
;
694 bfunc(dst_row
- LCD_WIDTH
, dmask1
, lcd_dibits
[data
&0x0F]);
695 bfunc(dst_row
++, dmask2
, lcd_dibits
[(data
>>4)&0x0F]);
697 while (dst_row
< dst_end
);
702 bfunc(dst_row
++, dmask2
, lcd_dibits
[((*src_row
++)>>4)&0x0F]);
703 while (dst_row
< dst_end
);
710 dmask1
= lcd_dibits
[mask
&0x0F];
711 dmask2
= lcd_dibits
[(mask
>>4)&0x0F];
712 dst_end
= dst
+ width
;
721 bfunc(dst
, dmask1
, lcd_dibits
[data
&0x0F]);
722 bfunc((dst
++) + LCD_WIDTH
, dmask2
, lcd_dibits
[(data
>>4)&0x0F]);
724 while (dst
< dst_end
);
729 bfunc(dst
++, dmask1
, lcd_dibits
[(*src
++)&0x0F]);
730 while (dst
< dst_end
);
736 bfunc((dst
++) + LCD_WIDTH
, dmask2
, lcd_dibits
[((*src
++)>>4)&0x0F]);
737 while (dst
< dst_end
);
742 dst_end
= dst
+ width
;
745 const unsigned char *src_col
= src
++;
746 fb_data
*dst_col
= dst
++;
747 unsigned mask_col
= mask
;
750 for (y
= ny
; y
>= 8; y
-= 8)
752 data
|= *src_col
<< shift
;
754 if (mask_col
& 0xFFu
)
757 bfunc(dst_col
, lcd_dibits
[mask_col
&0x0F], lcd_dibits
[data
&0x0F]);
758 bfunc(dst_col
+ LCD_WIDTH
, lcd_dibits
[(mask_col
>>4)&0x0F],
759 lcd_dibits
[(data
>>4)&0x0F]);
766 dst_col
+= 2*LCD_WIDTH
;
769 data
|= *src_col
<< shift
;
770 mask_bottom
&= mask_col
;
771 if (mask_bottom
& 0x0F)
772 bfunc(dst_col
, lcd_dibits
[mask_bottom
&0x0F], lcd_dibits
[data
&0x0F]);
773 if (mask_bottom
& 0xF0)
774 bfunc(dst_col
+ LCD_WIDTH
, lcd_dibits
[(mask_bottom
&0xF0)>>4],
775 lcd_dibits
[(data
>>4)&0x0F]);
777 while (dst
< dst_end
);
781 /* Draw a full monochrome bitmap */
782 void lcd_mono_bitmap(const unsigned char *src
, int x
, int y
, int width
, int height
)
784 lcd_mono_bitmap_part(src
, 0, 0, width
, x
, y
, width
, height
);
787 /* About Rockbox' internal native bitmap format:
789 * A bitmap contains two bits for every pixel. 00 = white, 01 = light grey,
790 * 10 = dark grey, 11 = black. Bits within a byte are arranged vertically, LSB
792 * The bytes are stored in row-major order, with byte 0 being top left,
793 * byte 1 2nd from left etc. The first row of bytes defines pixel rows
794 * 0..3, the second row defines pixel row 4..7 etc.
796 * This is the same as the internal lcd hw format. */
798 /* Draw a partial native bitmap */
799 void lcd_bitmap_part(const fb_data
*src
, int src_x
, int src_y
,
800 int stride
, int x
, int y
, int width
, int height
)
802 void lcd_bitmap_part(const fb_data
*src
, int src_x
, int src_y
,
803 int stride
, int x
, int y
, int width
, int height
)
806 fb_data
*dst
, *dst_end
;
807 unsigned mask
, mask_bottom
;
809 /* nothing to draw? */
810 if ((width
<= 0) || (height
<= 0) || (x
>= LCD_WIDTH
) || (y
>= LCD_HEIGHT
)
811 || (x
+ width
<= 0) || (y
+ height
<= 0))
827 if (x
+ width
> LCD_WIDTH
)
828 width
= LCD_WIDTH
- x
;
829 if (y
+ height
> LCD_HEIGHT
)
830 height
= LCD_HEIGHT
- y
;
832 src
+= stride
* (src_y
>> 2) + src_x
; /* move starting point */
835 dst
= &lcd_framebuffer
[y
>>2][x
];
837 ny
= height
- 1 + shift
+ src_y
;
839 mask
= 0xFFu
<< (2 * (shift
+ src_y
));
840 mask_bottom
= 0xFFu
>> (2 * (~ny
& 3));
844 for (; ny
>= 4; ny
-= 4)
847 memcpy(dst
, src
, width
);
850 const fb_data
*src_row
= src
;
851 fb_data
*dst_row
= dst
;
853 dst_end
= dst_row
+ width
;
855 setblock(dst_row
++, mask
, *src_row
++);
856 while (dst_row
< dst_end
);
865 memcpy(dst
, src
, width
);
868 dst_end
= dst
+ width
;
870 setblock(dst
++, mask
, *src
++);
871 while (dst
< dst_end
);
877 dst_end
= dst
+ width
;
880 const fb_data
*src_col
= src
++;
881 fb_data
*dst_col
= dst
++;
882 unsigned mask_col
= mask
;
885 for (y
= ny
; y
>= 4; y
-= 4)
887 data
|= *src_col
<< shift
;
889 if (mask_col
& 0xFFu
)
891 setblock(dst_col
, mask_col
, data
);
898 dst_col
+= LCD_WIDTH
;
901 data
|= *src_col
<< shift
;
902 setblock(dst_col
, mask_col
& mask_bottom
, data
);
904 while (dst
< dst_end
);
908 /* Draw a full native bitmap */
909 void lcd_bitmap(const fb_data
*src
, int x
, int y
, int width
, int height
)
911 lcd_bitmap_part(src
, 0, 0, width
, x
, y
, width
, height
);
914 /* put a string at a given pixel position, skipping first ofs pixel columns */
915 static void lcd_putsxyofs(int x
, int y
, int ofs
, const unsigned char *str
)
919 struct font
* pf
= font_get(curfont
);
921 ucs
= bidi_l2v(str
, 1);
923 while ((ch
= *ucs
++) != 0 && x
< LCD_WIDTH
)
926 const unsigned char *bits
;
928 /* get proportional width and glyph bits */
929 width
= font_get_width(pf
,ch
);
937 bits
= font_get_bits(pf
, ch
);
939 lcd_mono_bitmap_part(bits
, ofs
, 0, width
, x
, y
, width
- ofs
,
947 /* put a string at a given pixel position */
948 void lcd_putsxy(int x
, int y
, const unsigned char *str
)
950 lcd_putsxyofs(x
, y
, 0, str
);
953 /*** line oriented text output ***/
955 /* put a string at a given char position */
956 void lcd_puts(int x
, int y
, const unsigned char *str
)
958 lcd_puts_style_offset(x
, y
, str
, STYLE_DEFAULT
, 0);
961 void lcd_puts_style(int x
, int y
, const unsigned char *str
, int style
)
963 lcd_puts_style_offset(x
, y
, str
, style
, 0);
966 void lcd_puts_offset(int x
, int y
, const unsigned char *str
, int offset
)
968 lcd_puts_style_offset(x
, y
, str
, STYLE_DEFAULT
, offset
);
971 /* put a string at a given char position, style, and pixel position,
972 * skipping first offset pixel columns */
973 void lcd_puts_style_offset(int x
, int y
, const unsigned char *str
,
974 int style
, int offset
)
976 int xpos
,ypos
,w
,h
,xrect
;
977 int lastmode
= drawmode
;
979 /* make sure scrolling is turned off on the line we are updating */
980 lcd_scroll_info
.lines
&= ~(1 << y
);
985 lcd_getstringsize(str
, &w
, &h
);
986 xpos
= xmargin
+ x
*w
/ utf8length((char *)str
);
987 ypos
= ymargin
+ y
*h
;
988 drawmode
= (style
& STYLE_INVERT
) ?
989 (DRMODE_SOLID
|DRMODE_INVERSEVID
) : DRMODE_SOLID
;
990 lcd_putsxyofs(xpos
, ypos
, offset
, str
);
991 drawmode
^= DRMODE_INVERSEVID
;
992 xrect
= xpos
+ MAX(w
- offset
, 0);
993 lcd_fillrect(xrect
, ypos
, LCD_WIDTH
- xrect
, h
);
999 void lcd_puts_scroll(int x
, int y
, const unsigned char *string
)
1001 lcd_puts_scroll_style(x
, y
, string
, STYLE_DEFAULT
);
1004 void lcd_puts_scroll_style(int x
, int y
, const unsigned char *string
, int style
)
1006 lcd_puts_scroll_style_offset(x
, y
, string
, style
, 0);
1009 void lcd_puts_scroll_offset(int x
, int y
, const unsigned char *string
, int offset
)
1011 lcd_puts_scroll_style_offset(x
, y
, string
, STYLE_DEFAULT
, offset
);
1014 void lcd_puts_scroll_style_offset(int x
, int y
, const unsigned char *string
,
1015 int style
, int offset
)
1017 struct scrollinfo
* s
;
1020 if(y
>=LCD_SCROLLABLE_LINES
) return;
1022 s
= &lcd_scroll_info
.scroll
[y
];
1024 s
->start_tick
= current_tick
+ lcd_scroll_info
.delay
;
1026 if (style
& STYLE_INVERT
) {
1027 lcd_puts_style_offset(x
,y
,string
,STYLE_INVERT
,offset
);
1030 lcd_puts_offset(x
,y
,string
,offset
);
1032 lcd_getstringsize(string
, &w
, &h
);
1034 if (LCD_WIDTH
- x
* 8 - xmargin
< w
) {
1035 /* prepare scroll line */
1038 memset(s
->line
, 0, sizeof s
->line
);
1039 strcpy(s
->line
, (char *)string
);
1042 s
->width
= lcd_getstringsize((unsigned char *)s
->line
, &w
, &h
);
1044 /* scroll bidirectional or forward only depending on the string
1046 if ( lcd_scroll_info
.bidir_limit
) {
1047 s
->bidir
= s
->width
< (LCD_WIDTH
- xmargin
) *
1048 (100 + lcd_scroll_info
.bidir_limit
) / 100;
1053 if (!s
->bidir
) { /* add spaces if scrolling in the round */
1054 strcat(s
->line
, " ");
1055 /* get new width incl. spaces */
1056 s
->width
= lcd_getstringsize((unsigned char *)s
->line
, &w
, &h
);
1059 end
= strchr(s
->line
, '\0');
1060 strncpy(end
, (char *)string
, LCD_WIDTH
/2);
1062 s
->len
= utf8length((char *)string
);
1064 s
->startx
= xmargin
+ x
* s
->width
/ s
->len
;
1065 s
->backward
= false;
1066 lcd_scroll_info
.lines
|= (1<<y
);
1069 /* force a bit switch-off since it doesn't scroll */
1070 lcd_scroll_info
.lines
&= ~(1<<y
);
1073 void lcd_scroll_fn(void)
1076 struct scrollinfo
* s
;
1081 for ( index
= 0; index
< LCD_SCROLLABLE_LINES
; index
++ ) {
1082 /* really scroll? */
1083 if ((lcd_scroll_info
.lines
& (1 << index
)) == 0)
1086 s
= &lcd_scroll_info
.scroll
[index
];
1089 if (TIME_BEFORE(current_tick
, s
->start_tick
))
1093 s
->offset
-= lcd_scroll_info
.step
;
1095 s
->offset
+= lcd_scroll_info
.step
;
1097 pf
= font_get(curfont
);
1099 ypos
= ymargin
+ index
* pf
->height
;
1101 if (s
->bidir
) { /* scroll bidirectional */
1102 if (s
->offset
<= 0) {
1103 /* at beginning of line */
1105 s
->backward
= false;
1106 s
->start_tick
= current_tick
+ lcd_scroll_info
.delay
* 2;
1108 if (s
->offset
>= s
->width
- (LCD_WIDTH
- xpos
)) {
1109 /* at end of line */
1110 s
->offset
= s
->width
- (LCD_WIDTH
- xpos
);
1112 s
->start_tick
= current_tick
+ lcd_scroll_info
.delay
* 2;
1116 /* scroll forward the whole time */
1117 if (s
->offset
>= s
->width
)
1118 s
->offset
%= s
->width
;
1121 lastmode
= drawmode
;
1122 drawmode
= (s
->style
&STYLE_INVERT
) ?
1123 (DRMODE_SOLID
|DRMODE_INVERSEVID
) : DRMODE_SOLID
;
1124 lcd_putsxyofs(xpos
, ypos
, s
->offset
, s
->line
);
1125 drawmode
= lastmode
;
1126 lcd_update_rect(xpos
, ypos
, LCD_WIDTH
- xpos
, pf
->height
);