1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * LCD driver for horizontally-packed 2bpp greyscale display
12 * Based on code from the rockbox lcd's driver
14 * Copyright (c) 2006 Seven Le Mesle (sevlm@free.fr)
16 * All files in this archive are subject to the GNU General Public License.
17 * See the file COPYING in the source tree root for full license agreement.
19 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20 * KIND, either express or implied.
22 ****************************************************************************/
34 #include "rbunicode.h"
36 #include "scroll_engine.h"
40 unsigned char lcd_framebuffer
[LCD_FBHEIGHT
][LCD_FBWIDTH
] IBSS_ATTR
;
42 static const unsigned char pixmask
[4] ICONST_ATTR
= {
43 0xC0, 0x30, 0x0C, 0x03
46 static fb_data
* lcd_backdrop
= NULL
;
47 static long lcd_backdrop_offset IDATA_ATTR
= 0;
49 static struct viewport default_vp
=
55 .font
= FONT_SYSFIXED
,
56 .drawmode
= DRMODE_SOLID
,
59 .fg_pattern
= LCD_DEFAULT_FG
,
60 .bg_pattern
= LCD_DEFAULT_BG
63 static struct viewport
* current_vp IBSS_ATTR
;
64 static unsigned fg_pattern IBSS_ATTR
;
65 static unsigned bg_pattern IBSS_ATTR
;
70 /* Initialise the viewport */
71 lcd_set_viewport(NULL
);
74 /* Call device specific init */
81 void lcd_set_viewport(struct viewport
* vp
)
84 current_vp
= &default_vp
;
88 fg_pattern
= 0x55 * (~current_vp
->fg_pattern
& 3);
89 bg_pattern
= 0x55 * (~current_vp
->bg_pattern
& 3);
92 void lcd_update_viewport(void)
94 lcd_update_rect(current_vp
->x
, current_vp
->y
,
95 current_vp
->width
, current_vp
->height
);
98 void lcd_update_viewport_rect(int x
, int y
, int width
, int height
)
100 lcd_update_rect(current_vp
->x
+ x
, current_vp
->y
+ y
, width
, height
);
103 /*** parameter handling ***/
105 void lcd_set_drawmode(int mode
)
107 current_vp
->drawmode
= mode
& (DRMODE_SOLID
|DRMODE_INVERSEVID
);
110 int lcd_get_drawmode(void)
112 return current_vp
->drawmode
;
115 void lcd_set_foreground(unsigned brightness
)
117 current_vp
->fg_pattern
= brightness
;
118 fg_pattern
= 0x55 * (~brightness
& 3);
121 unsigned lcd_get_foreground(void)
123 return current_vp
->fg_pattern
;
126 void lcd_set_background(unsigned brightness
)
128 current_vp
->bg_pattern
= brightness
;
129 bg_pattern
= 0x55 * (~brightness
& 3);
132 unsigned lcd_get_background(void)
134 return current_vp
->bg_pattern
;
137 void lcd_set_drawinfo(int mode
, unsigned fg_brightness
, unsigned bg_brightness
)
139 lcd_set_drawmode(mode
);
140 lcd_set_foreground(fg_brightness
);
141 lcd_set_background(bg_brightness
);
144 void lcd_setmargins(int x
, int y
)
146 current_vp
->xmargin
= x
;
147 current_vp
->ymargin
= y
;
150 int lcd_getxmargin(void)
152 return current_vp
->xmargin
;
155 int lcd_getymargin(void)
157 return current_vp
->ymargin
;
160 int lcd_getwidth(void)
162 return current_vp
->width
;
165 int lcd_getheight(void)
167 return current_vp
->height
;
170 void lcd_setfont(int newfont
)
172 current_vp
->font
= newfont
;
175 int lcd_getfont(void)
177 return current_vp
->font
;
180 int lcd_getstringsize(const unsigned char *str
, int *w
, int *h
)
182 return font_getstringsize(str
, w
, h
, current_vp
->font
);
185 /*** low-level drawing functions ***/
187 static void setpixel(int x
, int y
)
189 unsigned mask
= pixmask
[x
& 3];
190 fb_data
*address
= &lcd_framebuffer
[y
][x
>>2];
191 unsigned data
= *address
;
193 *address
= data
^ ((data
^ fg_pattern
) & mask
);
196 static void clearpixel(int x
, int y
)
198 unsigned mask
= pixmask
[x
& 3];
199 fb_data
*address
= &lcd_framebuffer
[y
][x
>>2];
200 unsigned data
= *address
;
202 *address
= data
^ ((data
^ bg_pattern
) & mask
);
205 static void clearimgpixel(int x
, int y
)
207 unsigned mask
= pixmask
[x
& 3];
208 fb_data
*address
= &lcd_framebuffer
[y
][x
>>2];
209 unsigned data
= *address
;
211 *address
= data
^ ((data
^ *(address
+ lcd_backdrop_offset
)) & mask
);
214 static void flippixel(int x
, int y
)
216 unsigned mask
= pixmask
[x
& 3];
217 fb_data
*address
= &lcd_framebuffer
[y
][x
>>2];
222 static void nopixel(int x
, int y
)
228 lcd_pixelfunc_type
* const lcd_pixelfuncs_bgcolor
[8] = {
229 flippixel
, nopixel
, setpixel
, setpixel
,
230 nopixel
, clearpixel
, nopixel
, clearpixel
233 lcd_pixelfunc_type
* const lcd_pixelfuncs_backdrop
[8] = {
234 flippixel
, nopixel
, setpixel
, setpixel
,
235 nopixel
, clearimgpixel
, nopixel
, clearimgpixel
238 lcd_pixelfunc_type
* const * lcd_pixelfuncs
= lcd_pixelfuncs_bgcolor
;
241 /* 'mask' and 'bits' contain 2 bits per pixel */
242 static void flipblock(fb_data
*address
, unsigned mask
, unsigned bits
)
244 static void flipblock(fb_data
*address
, unsigned mask
, unsigned bits
)
246 *address
^= bits
& mask
;
249 static void bgblock(fb_data
*address
, unsigned mask
, unsigned bits
)
251 static void bgblock(fb_data
*address
, unsigned mask
, unsigned bits
)
253 unsigned data
= *address
;
255 *address
= data
^ ((data
^ bg_pattern
) & mask
& ~bits
);
258 static void bgimgblock(fb_data
*address
, unsigned mask
, unsigned bits
)
260 static void bgimgblock(fb_data
*address
, unsigned mask
, unsigned bits
)
262 unsigned data
= *address
;
264 *address
= data
^ ((data
^ *(address
+ lcd_backdrop_offset
)) & mask
& ~bits
);
267 static void fgblock(fb_data
*address
, unsigned mask
, unsigned bits
)
269 static void fgblock(fb_data
*address
, unsigned mask
, unsigned bits
)
271 unsigned data
= *address
;
273 *address
= data
^ ((data
^ fg_pattern
) & mask
& bits
);
276 static void solidblock(fb_data
*address
, unsigned mask
, unsigned bits
)
278 static void solidblock(fb_data
*address
, unsigned mask
, unsigned bits
)
280 unsigned data
= *address
;
281 unsigned bgp
= bg_pattern
;
283 bits
= bgp
^ ((bgp
^ fg_pattern
) & bits
);
284 *address
= data
^ ((data
^ bits
) & mask
);
287 static void solidimgblock(fb_data
*address
, unsigned mask
, unsigned bits
)
289 static void solidimgblock(fb_data
*address
, unsigned mask
, unsigned bits
)
291 unsigned data
= *address
;
292 unsigned bgp
= *(address
+ lcd_backdrop_offset
);
294 bits
= bgp
^ ((bgp
^ fg_pattern
) & bits
);
295 *address
= data
^ ((data
^ bits
) & mask
);
298 static void flipinvblock(fb_data
*address
, unsigned mask
, unsigned bits
)
300 static void flipinvblock(fb_data
*address
, unsigned mask
, unsigned bits
)
302 *address
^= ~bits
& mask
;
305 static void bginvblock(fb_data
*address
, unsigned mask
, unsigned bits
)
307 static void bginvblock(fb_data
*address
, unsigned mask
, unsigned bits
)
309 unsigned data
= *address
;
311 *address
= data
^ ((data
^ bg_pattern
) & mask
& bits
);
314 static void bgimginvblock(fb_data
*address
, unsigned mask
, unsigned bits
)
316 static void bgimginvblock(fb_data
*address
, unsigned mask
, unsigned bits
)
318 unsigned data
= *address
;
320 *address
= data
^ ((data
^ *(address
+ lcd_backdrop_offset
)) & mask
& bits
);
323 static void fginvblock(fb_data
*address
, unsigned mask
, unsigned bits
)
325 static void fginvblock(fb_data
*address
, unsigned mask
, unsigned bits
)
327 unsigned data
= *address
;
329 *address
= data
^ ((data
^ fg_pattern
) & mask
& ~bits
);
332 static void solidinvblock(fb_data
*address
, unsigned mask
, unsigned bits
)
334 static void solidinvblock(fb_data
*address
, unsigned mask
, unsigned bits
)
336 unsigned data
= *address
;
337 unsigned fgp
= fg_pattern
;
339 bits
= fgp
^ ((fgp
^ bg_pattern
) & bits
);
340 *address
= data
^ ((data
^ bits
) & mask
);
343 static void solidimginvblock(fb_data
*address
, unsigned mask
, unsigned bits
)
345 static void solidimginvblock(fb_data
*address
, unsigned mask
, unsigned bits
)
347 unsigned data
= *address
;
348 unsigned fgp
= fg_pattern
;
350 bits
= fgp
^ ((fgp
^ *(address
+ lcd_backdrop_offset
)) & bits
);
351 *address
= data
^ ((data
^ bits
) & mask
);
354 lcd_blockfunc_type
* const lcd_blockfuncs_bgcolor
[8] = {
355 flipblock
, bgblock
, fgblock
, solidblock
,
356 flipinvblock
, bginvblock
, fginvblock
, solidinvblock
359 lcd_blockfunc_type
* const lcd_blockfuncs_backdrop
[8] = {
360 flipblock
, bgimgblock
, fgblock
, solidimgblock
,
361 flipinvblock
, bgimginvblock
, fginvblock
, solidimginvblock
364 lcd_blockfunc_type
* const * lcd_blockfuncs
= lcd_blockfuncs_bgcolor
;
367 void lcd_set_backdrop(fb_data
* backdrop
)
369 lcd_backdrop
= backdrop
;
372 lcd_backdrop_offset
= (long)backdrop
- (long)lcd_framebuffer
;
373 lcd_pixelfuncs
= lcd_pixelfuncs_backdrop
;
374 lcd_blockfuncs
= lcd_blockfuncs_backdrop
;
378 lcd_backdrop_offset
= 0;
379 lcd_pixelfuncs
= lcd_pixelfuncs_bgcolor
;
380 lcd_blockfuncs
= lcd_blockfuncs_bgcolor
;
384 fb_data
* lcd_get_backdrop(void)
390 static inline void setblock(fb_data
*address
, unsigned mask
, unsigned bits
)
392 unsigned data
= *address
;
395 *address
= data
^ (bits
& mask
);
398 /*** drawing functions ***/
400 /* Clear the whole display */
401 void lcd_clear_display(void)
403 if (current_vp
->drawmode
& DRMODE_INVERSEVID
)
405 memset(lcd_framebuffer
, fg_pattern
, sizeof lcd_framebuffer
);
410 memcpy(lcd_framebuffer
, lcd_backdrop
, sizeof lcd_framebuffer
);
412 memset(lcd_framebuffer
, bg_pattern
, sizeof lcd_framebuffer
);
415 lcd_scroll_info
.lines
= 0;
418 /* Clear the current viewport */
419 void lcd_clear_viewport(void)
423 if (current_vp
== &default_vp
)
429 lastmode
= current_vp
->drawmode
;
431 /* Invert the INVERSEVID bit and set basic mode to SOLID */
432 current_vp
->drawmode
= (~lastmode
& DRMODE_INVERSEVID
) |
435 lcd_fillrect(0, 0, current_vp
->width
, current_vp
->height
);
437 current_vp
->drawmode
= lastmode
;
439 lcd_scroll_stop(current_vp
);
443 /* Set a single pixel */
444 void lcd_drawpixel(int x
, int y
)
446 if (((unsigned)x
< (unsigned)current_vp
->width
) &&
447 ((unsigned)y
< (unsigned)current_vp
->height
))
448 lcd_pixelfuncs
[current_vp
->drawmode
](current_vp
->x
+ x
, current_vp
->y
+ y
);
452 void lcd_drawline(int x1
, int y1
, int x2
, int y2
)
460 lcd_pixelfunc_type
*pfunc
= lcd_pixelfuncs
[current_vp
->drawmode
];
462 deltax
= abs(x2
- x1
);
463 deltay
= abs(y2
- y1
);
467 if (deltax
>= deltay
)
470 d
= 2 * deltay
- deltax
;
472 dinc2
= (deltay
- deltax
) * 2;
479 d
= 2 * deltax
- deltay
;
481 dinc2
= (deltax
- deltay
) * 2;
485 numpixels
++; /* include endpoints */
502 for (i
= 0; i
< numpixels
; i
++)
504 if (((unsigned)x
< (unsigned)current_vp
->width
) &&
505 ((unsigned)y
< (unsigned)current_vp
->height
))
506 pfunc(current_vp
->x
+ x
, current_vp
->y
+ y
);
523 /* Draw a horizontal line (optimised) */
524 void lcd_hline(int x1
, int x2
, int y
)
528 unsigned mask
, mask_right
;
529 lcd_blockfunc_type
*bfunc
;
539 /* nothing to draw? */
540 if (((unsigned)y
>= (unsigned)current_vp
->height
) || (x1
>= current_vp
->width
)
547 if (x2
>= current_vp
->width
)
548 x2
= current_vp
->width
-1;
550 /* adjust to viewport */
555 bfunc
= lcd_blockfuncs
[current_vp
->drawmode
];
556 dst
= &lcd_framebuffer
[y
][x1
>>2];
558 mask
= 0xFFu
>> (2 * (x1
& 3));
559 mask_right
= 0xFFu
<< (2 * (~nx
& 3));
561 for (; nx
>= 4; nx
-= 4)
563 bfunc(dst
++, mask
, 0xFFu
);
567 bfunc(dst
, mask
, 0xFFu
);
570 /* Draw a vertical line (optimised) */
571 void lcd_vline(int x
, int y1
, int y2
)
574 unsigned char *dst
, *dst_end
;
576 lcd_blockfunc_type
*bfunc
;
586 /* nothing to draw? */
587 if (((unsigned)x
>= (unsigned)current_vp
->width
) || (y1
>= current_vp
->height
)
594 if (y2
>= current_vp
->height
)
595 y2
= current_vp
->height
-1;
597 /* adjust for viewport */
602 bfunc
= lcd_blockfuncs
[current_vp
->drawmode
];
603 dst
= &lcd_framebuffer
[y1
][x
>>2];
604 mask
= pixmask
[x
& 3];
606 dst_end
= dst
+ (y2
- y1
) * LCD_FBWIDTH
;
609 bfunc(dst
, mask
, 0xFFu
);
612 while (dst
<= dst_end
);
615 /* Draw a rectangular box */
616 void lcd_drawrect(int x
, int y
, int width
, int height
)
618 if ((width
<= 0) || (height
<= 0))
621 int x2
= x
+ width
- 1;
622 int y2
= y
+ height
- 1;
625 lcd_vline(x2
, y
, y2
);
627 lcd_hline(x
, x2
, y2
);
630 /* Fill a rectangular area */
631 void lcd_fillrect(int x
, int y
, int width
, int height
)
634 unsigned char *dst
, *dst_end
;
635 unsigned mask
, mask_right
;
636 lcd_blockfunc_type
*bfunc
;
638 /* nothing to draw? */
639 if ((width
<= 0) || (height
<= 0) || (x
>= current_vp
->width
) || (y
>= current_vp
->height
)
640 || (x
+ width
<= 0) || (y
+ height
<= 0))
654 if (x
+ width
> current_vp
->width
)
655 width
= current_vp
->width
- x
;
656 if (y
+ height
> current_vp
->height
)
657 height
= current_vp
->height
- y
;
659 /* adjust for viewport */
663 bfunc
= lcd_blockfuncs
[current_vp
->drawmode
];
664 dst
= &lcd_framebuffer
[y
][x
>>2];
665 nx
= width
- 1 + (x
& 3);
666 mask
= 0xFFu
>> (2 * (x
& 3));
667 mask_right
= 0xFFu
<< (2 * (~nx
& 3));
669 for (; nx
>= 4; nx
-= 4)
671 unsigned char *dst_col
= dst
;
673 dst_end
= dst_col
+ height
* LCD_FBWIDTH
;
676 bfunc(dst_col
, mask
, 0xFFu
);
677 dst_col
+= LCD_FBWIDTH
;
679 while (dst_col
< dst_end
);
686 dst_end
= dst
+ height
* LCD_FBWIDTH
;
689 bfunc(dst
, mask
, 0xFFu
);
692 while (dst
< dst_end
);
695 /* About Rockbox' internal monochrome bitmap format:
697 * A bitmap contains one bit for every pixel that defines if that pixel is
698 * black (1) or white (0). Bits within a byte are arranged vertically, LSB
700 * The bytes are stored in row-major order, with byte 0 being top left,
701 * byte 1 2nd from left etc. The first row of bytes defines pixel rows
702 * 0..7, the second row defines pixel row 8..15 etc. */
704 /* Draw a partial monochrome bitmap */
705 void lcd_mono_bitmap_part(const unsigned char *src
, int src_x
, int src_y
,
706 int stride
, int x
, int y
, int width
, int height
)
708 void lcd_mono_bitmap_part(const unsigned char *src
, int src_x
, int src_y
,
709 int stride
, int x
, int y
, int width
, int height
)
712 const unsigned char * src_end
;
713 lcd_pixelfunc_type
* fgfunc
;
714 lcd_pixelfunc_type
* bgfunc
;
716 /* nothing to draw? */
717 if ((width
<= 0) || (height
<= 0) || (x
>= current_vp
->width
) ||
718 (y
>= current_vp
->height
) || (x
+ width
<= 0) || (y
+ height
<= 0))
734 if (x
+ width
> current_vp
->width
)
735 width
= current_vp
->width
- x
;
736 if (y
+ height
> current_vp
->height
)
737 height
= current_vp
->height
- y
;
739 /* adjust for viewport */
743 src
+= stride
* (src_y
>> 3) + src_x
; /* move starting point */
745 src_end
= src
+ width
;
747 fgfunc
= lcd_pixelfuncs
[current_vp
->drawmode
];
748 bgfunc
= lcd_pixelfuncs
[current_vp
->drawmode
^ DRMODE_INVERSEVID
];
752 const unsigned char *src_col
= src
++;
753 unsigned data
= *src_col
>> src_y
;
754 int numbits
= 8 - ((int)src_y
);
778 while (src
< src_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 horizontally,
792 * The bytes are stored in row-major order, with byte 0 being top left,
793 * byte 1 2nd from left etc. Each row of bytes defines one pixel row.
795 * This is the same as the internal lcd hw format. */
797 /* Draw a partial native bitmap */
798 void lcd_bitmap_part(const unsigned char *src
, int src_x
, int src_y
,
799 int stride
, int x
, int y
, int width
, int height
)
801 void lcd_bitmap_part(const unsigned char *src
, int src_x
, int src_y
,
802 int stride
, int x
, int y
, int width
, int height
)
805 unsigned char *dst
, *dst_end
;
806 unsigned mask
, mask_right
;
808 /* nothing to draw? */
809 if ((width
<= 0) || (height
<= 0) || (x
>= current_vp
->width
) ||
810 (y
>= current_vp
->height
) || (x
+ width
<= 0) || (y
+ height
<= 0))
826 if (x
+ width
> current_vp
->width
)
827 width
= current_vp
->width
- x
;
828 if (y
+ height
> current_vp
->height
)
829 height
= current_vp
->height
- y
;
831 /* adjust for viewport */
835 stride
= (stride
+ 3) >> 2; /* convert to no. of bytes */
837 src
+= stride
* src_y
+ (src_x
>> 2); /* move starting point */
840 dst
= &lcd_framebuffer
[y
][x
>>2];
842 nx
= width
- 1 + shift
+ src_x
;
844 mask
= 0xFF00u
>> (2 * (shift
+ src_x
));
845 mask_right
= 0xFFu
<< (2 * (~nx
& 3));
848 dst_end
= dst
+ height
* LCD_FBWIDTH
;
851 const unsigned char *src_row
= src
;
852 unsigned char *dst_row
= dst
;
853 unsigned mask_row
= mask
>> 8;
856 for (x
= nx
; x
>= 4; x
-= 4)
858 data
= (data
<< 8) | *src_row
++;
862 setblock(dst_row
, mask_row
, data
>> shift
);
870 data
= (data
<< 8) | *src_row
;
871 setblock(dst_row
, mask_row
& mask_right
, data
>> shift
);
876 while (dst
< dst_end
);
879 /* Draw a full native bitmap */
880 void lcd_bitmap(const unsigned char *src
, int x
, int y
, int width
, int height
)
882 lcd_bitmap_part(src
, 0, 0, width
, x
, y
, width
, height
);
885 /* put a string at a given pixel position, skipping first ofs pixel columns */
886 static void lcd_putsxyofs(int x
, int y
, int ofs
, const unsigned char *str
)
890 struct font
* pf
= font_get(current_vp
->font
);
892 ucs
= bidi_l2v(str
, 1);
894 while ((ch
= *ucs
++) != 0 && x
< current_vp
->width
)
897 const unsigned char *bits
;
899 /* get proportional width and glyph bits */
900 width
= font_get_width(pf
,ch
);
908 bits
= font_get_bits(pf
, ch
);
910 lcd_mono_bitmap_part(bits
, ofs
, 0, width
, x
, y
, width
- ofs
,
918 /* put a string at a given pixel position */
919 void lcd_putsxy(int x
, int y
, const unsigned char *str
)
921 lcd_putsxyofs(x
, y
, 0, str
);
924 /*** line oriented text output ***/
926 /* put a string at a given char position */
927 void lcd_puts(int x
, int y
, const unsigned char *str
)
929 lcd_puts_style_offset(x
, y
, str
, STYLE_DEFAULT
, 0);
932 void lcd_puts_style(int x
, int y
, const unsigned char *str
, int style
)
934 lcd_puts_style_offset(x
, y
, str
, style
, 0);
937 void lcd_puts_offset(int x
, int y
, const unsigned char *str
, int offset
)
939 lcd_puts_style_offset(x
, y
, str
, STYLE_DEFAULT
, offset
);
942 /* put a string at a given char position, style, and pixel position,
943 * skipping first offset pixel columns */
944 void lcd_puts_style_offset(int x
, int y
, const unsigned char *str
,
945 int style
, int offset
)
947 int xpos
,ypos
,w
,h
,xrect
;
948 int lastmode
= current_vp
->drawmode
;
950 /* make sure scrolling is turned off on the line we are updating */
951 lcd_scroll_stop_line(current_vp
, y
);
956 lcd_getstringsize(str
, &w
, &h
);
957 xpos
= current_vp
->xmargin
+ x
*w
/ utf8length((char *)str
);
958 ypos
= current_vp
->ymargin
+ y
*h
;
959 current_vp
->drawmode
= (style
& STYLE_INVERT
) ?
960 (DRMODE_SOLID
|DRMODE_INVERSEVID
) : DRMODE_SOLID
;
961 lcd_putsxyofs(xpos
, ypos
, offset
, str
);
962 current_vp
->drawmode
^= DRMODE_INVERSEVID
;
963 xrect
= xpos
+ MAX(w
- offset
, 0);
964 lcd_fillrect(xrect
, ypos
, current_vp
->width
- xrect
, h
);
965 current_vp
->drawmode
= lastmode
;
969 void lcd_puts_scroll(int x
, int y
, const unsigned char *string
)
971 lcd_puts_scroll_style(x
, y
, string
, STYLE_DEFAULT
);
974 void lcd_puts_scroll_style(int x
, int y
, const unsigned char *string
, int style
)
976 lcd_puts_scroll_style_offset(x
, y
, string
, style
, 0);
979 void lcd_puts_scroll_offset(int x
, int y
, const unsigned char *string
, int offset
)
981 lcd_puts_scroll_style_offset(x
, y
, string
, STYLE_DEFAULT
, offset
);
984 void lcd_puts_scroll_style_offset(int x
, int y
, const unsigned char *string
,
985 int style
, int offset
)
987 struct scrollinfo
* s
;
990 if ((unsigned)y
>= (unsigned)current_vp
->height
)
993 /* remove any previously scrolling line at the same location */
994 lcd_scroll_stop_line(current_vp
, y
);
996 if (lcd_scroll_info
.lines
>= LCD_SCROLLABLE_LINES
) return;
998 s
= &lcd_scroll_info
.scroll
[lcd_scroll_info
.lines
];
1000 s
->start_tick
= current_tick
+ lcd_scroll_info
.delay
;
1002 if (style
& STYLE_INVERT
) {
1003 lcd_puts_style_offset(x
,y
,string
,STYLE_INVERT
,offset
);
1006 lcd_puts_offset(x
,y
,string
,offset
);
1008 lcd_getstringsize(string
, &w
, &h
);
1010 if (current_vp
->width
- x
* 8 - current_vp
->xmargin
< w
) {
1011 /* prepare scroll line */
1014 memset(s
->line
, 0, sizeof s
->line
);
1015 strcpy(s
->line
, (char *)string
);
1018 s
->width
= lcd_getstringsize((unsigned char *)s
->line
, &w
, &h
);
1020 /* scroll bidirectional or forward only depending on the string
1022 if ( lcd_scroll_info
.bidir_limit
) {
1023 s
->bidir
= s
->width
< (current_vp
->width
- current_vp
->xmargin
) *
1024 (100 + lcd_scroll_info
.bidir_limit
) / 100;
1029 if (!s
->bidir
) { /* add spaces if scrolling in the round */
1030 strcat(s
->line
, " ");
1031 /* get new width incl. spaces */
1032 s
->width
= lcd_getstringsize((unsigned char *)s
->line
, &w
, &h
);
1035 end
= strchr(s
->line
, '\0');
1036 strncpy(end
, (char *)string
, current_vp
->width
/2);
1040 s
->len
= utf8length((char *)string
);
1042 s
->startx
= current_vp
->xmargin
+ x
* s
->width
/ s
->len
;;
1043 s
->backward
= false;
1044 lcd_scroll_info
.lines
++;
1048 void lcd_scroll_fn(void)
1051 struct scrollinfo
* s
;
1055 struct viewport
* old_vp
= current_vp
;
1057 for ( index
= 0; index
< lcd_scroll_info
.lines
; index
++ ) {
1058 s
= &lcd_scroll_info
.scroll
[index
];
1061 if (TIME_BEFORE(current_tick
, s
->start_tick
))
1064 lcd_set_viewport(s
->vp
);
1067 s
->offset
-= lcd_scroll_info
.step
;
1069 s
->offset
+= lcd_scroll_info
.step
;
1071 pf
= font_get(current_vp
->font
);
1073 ypos
= current_vp
->ymargin
+ s
->y
* pf
->height
;
1075 if (s
->bidir
) { /* scroll bidirectional */
1076 if (s
->offset
<= 0) {
1077 /* at beginning of line */
1079 s
->backward
= false;
1080 s
->start_tick
= current_tick
+ lcd_scroll_info
.delay
* 2;
1082 if (s
->offset
>= s
->width
- (current_vp
->width
- xpos
)) {
1083 /* at end of line */
1084 s
->offset
= s
->width
- (current_vp
->width
- xpos
);
1086 s
->start_tick
= current_tick
+ lcd_scroll_info
.delay
* 2;
1090 /* scroll forward the whole time */
1091 if (s
->offset
>= s
->width
)
1092 s
->offset
%= s
->width
;
1095 lastmode
= current_vp
->drawmode
;
1096 current_vp
->drawmode
= (s
->style
&STYLE_INVERT
) ?
1097 (DRMODE_SOLID
|DRMODE_INVERSEVID
) : DRMODE_SOLID
;
1098 lcd_putsxyofs(xpos
, ypos
, s
->offset
, s
->line
);
1099 current_vp
->drawmode
= lastmode
;
1100 lcd_update_viewport_rect(xpos
, ypos
, current_vp
->width
- xpos
, pf
->height
);
1103 lcd_set_viewport(old_vp
);