1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2005 by Dave Chapman
12 * Rockbox driver for 16-bit colour LCDs
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
19 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20 * KIND, either express or implied.
22 ****************************************************************************/
36 #include "rbunicode.h"
38 #include "scroll_engine.h"
47 fb_data lcd_framebuffer
[LCD_FBHEIGHT
][LCD_FBWIDTH
]
48 IRAM_LCDFRAMEBUFFER
CACHEALIGN_AT_LEAST_ATTR(16);
51 static fb_data
* lcd_backdrop
= NULL
;
52 static long lcd_backdrop_offset IDATA_ATTR
= 0;
54 static struct viewport default_vp
=
60 .font
= FONT_SYSFIXED
,
61 .drawmode
= DRMODE_SOLID
,
62 .fg_pattern
= LCD_DEFAULT_FG
,
63 .bg_pattern
= LCD_DEFAULT_BG
,
64 .lss_pattern
= LCD_DEFAULT_BG
,
65 .lse_pattern
= LCD_DEFAULT_BG
,
66 .lst_pattern
= LCD_DEFAULT_BG
,
69 /* The Gigabeat target build requires access to the current fg_pattern
71 #if (!defined(TOSHIBA_GIGABEAT_F)&& !defined(TOSHIBA_GIGABEAT_S)) || defined(SIMULATOR)
72 static struct viewport
* current_vp IDATA_ATTR
= &default_vp
;
74 struct viewport
* current_vp IDATA_ATTR
= &default_vp
;
78 /*** Helpers - consolidate optional code ***/
79 #if defined(HAVE_LCD_ENABLE) || defined(HAVE_LCD_SLEEP)
80 static void (*lcd_activation_hook
)(void) = NULL
;
82 void lcd_activation_set_hook(void (*func
)(void))
84 lcd_activation_hook
= func
;
87 /* To be called by target driver after enabling display and refreshing it */
88 void lcd_activation_call_hook(void)
90 void (*func
)(void) = lcd_activation_hook
;
103 /* Call device specific init */
109 void lcd_set_viewport(struct viewport
* vp
)
112 current_vp
= &default_vp
;
117 void lcd_update_viewport(void)
119 lcd_update_rect(current_vp
->x
, current_vp
->y
,
120 current_vp
->width
, current_vp
->height
);
123 void lcd_update_viewport_rect(int x
, int y
, int width
, int height
)
125 lcd_update_rect(current_vp
->x
+ x
, current_vp
->y
+ y
, width
, height
);
128 /*** parameter handling ***/
130 void lcd_set_drawmode(int mode
)
132 current_vp
->drawmode
= mode
& (DRMODE_SOLID
|DRMODE_INVERSEVID
);
135 int lcd_get_drawmode(void)
137 return current_vp
->drawmode
;
140 void lcd_set_foreground(unsigned color
)
142 current_vp
->fg_pattern
= color
;
145 unsigned lcd_get_foreground(void)
147 return current_vp
->fg_pattern
;
150 void lcd_set_background(unsigned color
)
152 current_vp
->bg_pattern
= color
;
155 unsigned lcd_get_background(void)
157 return current_vp
->bg_pattern
;
160 void lcd_set_selector_start(unsigned color
)
162 current_vp
->lss_pattern
= color
;
165 void lcd_set_selector_end(unsigned color
)
167 current_vp
->lse_pattern
= color
;
170 void lcd_set_selector_text(unsigned color
)
172 current_vp
->lst_pattern
= color
;
175 void lcd_set_drawinfo(int mode
, unsigned fg_color
, unsigned bg_color
)
177 lcd_set_drawmode(mode
);
178 current_vp
->fg_pattern
= fg_color
;
179 current_vp
->bg_pattern
= bg_color
;
182 int lcd_getwidth(void)
184 return current_vp
->width
;
187 int lcd_getheight(void)
189 return current_vp
->height
;
192 void lcd_setfont(int newfont
)
194 current_vp
->font
= newfont
;
197 int lcd_getfont(void)
199 return current_vp
->font
;
202 int lcd_getstringsize(const unsigned char *str
, int *w
, int *h
)
204 return font_getstringsize(str
, w
, h
, current_vp
->font
);
207 /*** low-level drawing functions ***/
209 #define LCDADDR(x, y) (&lcd_framebuffer[(y)][(x)])
211 static void ICODE_ATTR
setpixel(fb_data
*address
)
213 *address
= current_vp
->fg_pattern
;
216 static void ICODE_ATTR
clearpixel(fb_data
*address
)
218 *address
= current_vp
->bg_pattern
;
221 static void ICODE_ATTR
clearimgpixel(fb_data
*address
)
223 *address
= *(fb_data
*)((long)address
+ lcd_backdrop_offset
);
226 static void ICODE_ATTR
flippixel(fb_data
*address
)
228 *address
= ~(*address
);
231 static void ICODE_ATTR
nopixel(fb_data
*address
)
236 lcd_fastpixelfunc_type
* const lcd_fastpixelfuncs_bgcolor
[8] = {
237 flippixel
, nopixel
, setpixel
, setpixel
,
238 nopixel
, clearpixel
, nopixel
, clearpixel
241 lcd_fastpixelfunc_type
* const lcd_fastpixelfuncs_backdrop
[8] = {
242 flippixel
, nopixel
, setpixel
, setpixel
,
243 nopixel
, clearimgpixel
, nopixel
, clearimgpixel
246 lcd_fastpixelfunc_type
* const * lcd_fastpixelfuncs
= lcd_fastpixelfuncs_bgcolor
;
248 void lcd_set_backdrop(fb_data
* backdrop
)
250 lcd_backdrop
= backdrop
;
253 lcd_backdrop_offset
= (long)backdrop
- (long)&lcd_framebuffer
[0][0];
254 lcd_fastpixelfuncs
= lcd_fastpixelfuncs_backdrop
;
258 lcd_backdrop_offset
= 0;
259 lcd_fastpixelfuncs
= lcd_fastpixelfuncs_bgcolor
;
263 fb_data
* lcd_get_backdrop(void)
268 /*** drawing functions ***/
270 /* Clear the current viewport */
271 void lcd_clear_viewport(void)
273 fb_data
*dst
, *dst_end
;
275 dst
= LCDADDR(current_vp
->x
, current_vp
->y
);
276 dst_end
= dst
+ current_vp
->height
* LCD_WIDTH
;
278 if (current_vp
->drawmode
& DRMODE_INVERSEVID
)
282 memset16(dst
, current_vp
->fg_pattern
, current_vp
->width
);
285 while (dst
< dst_end
);
293 memset16(dst
, current_vp
->bg_pattern
, current_vp
->width
);
296 while (dst
< dst_end
);
302 memcpy(dst
, (void *)((long)dst
+ lcd_backdrop_offset
),
303 current_vp
->width
* sizeof(fb_data
));
306 while (dst
< dst_end
);
310 if (current_vp
== &default_vp
)
312 lcd_scroll_info
.lines
= 0;
316 lcd_scroll_stop(current_vp
);
320 /* Clear the whole display */
321 void lcd_clear_display(void)
323 struct viewport
* old_vp
= current_vp
;
325 current_vp
= &default_vp
;
327 lcd_clear_viewport();
332 /* Set a single pixel */
333 void lcd_drawpixel(int x
, int y
)
335 if (((unsigned)x
< (unsigned)current_vp
->width
) &&
336 ((unsigned)y
< (unsigned)current_vp
->height
))
337 lcd_fastpixelfuncs
[current_vp
->drawmode
](LCDADDR(current_vp
->x
+x
, current_vp
->y
+y
));
341 void lcd_drawline(int x1
, int y1
, int x2
, int y2
)
349 lcd_fastpixelfunc_type
*pfunc
= lcd_fastpixelfuncs
[current_vp
->drawmode
];
351 deltay
= abs(y2
- y1
);
354 DEBUGF("lcd_drawline() called for horizontal line - optimisation.\n");
355 lcd_hline(x1
, x2
, y1
);
358 deltax
= abs(x2
- x1
);
361 DEBUGF("lcd_drawline() called for vertical line - optimisation.\n");
362 lcd_vline(x1
, y1
, y2
);
368 if (deltax
>= deltay
)
371 d
= 2 * deltay
- deltax
;
373 dinc2
= (deltay
- deltax
) * 2;
380 d
= 2 * deltax
- deltay
;
382 dinc2
= (deltax
- deltay
) * 2;
386 numpixels
++; /* include endpoints */
403 for (i
= 0; i
< numpixels
; i
++)
405 if (((unsigned)x
< (unsigned)current_vp
->width
) && ((unsigned)y
< (unsigned)current_vp
->height
))
406 pfunc(LCDADDR(x
+ current_vp
->x
, y
+ current_vp
->y
));
423 /* Draw a horizontal line (optimised) */
424 void lcd_hline(int x1
, int x2
, int y
)
428 enum fill_opt fillopt
= OPT_NONE
;
429 fb_data
*dst
, *dst_end
;
439 /* nothing to draw? */
440 if (((unsigned)y
>= (unsigned)current_vp
->height
) ||
441 (x1
>= current_vp
->width
) ||
445 /* drawmode and optimisation */
446 if (current_vp
->drawmode
& DRMODE_INVERSEVID
)
448 if (current_vp
->drawmode
& DRMODE_BG
)
453 bits
= current_vp
->bg_pattern
;
461 if (current_vp
->drawmode
& DRMODE_FG
)
464 bits
= current_vp
->fg_pattern
;
467 if (fillopt
== OPT_NONE
&& current_vp
->drawmode
!= DRMODE_COMPLEMENT
)
473 if (x2
>= current_vp
->width
)
474 x2
= current_vp
->width
-1;
478 /* Adjust x1 and y to viewport */
482 dst
= LCDADDR(x1
, y
);
487 memset16(dst
, bits
, width
);
491 memcpy(dst
, (void *)((long)dst
+ lcd_backdrop_offset
),
492 width
* sizeof(fb_data
));
495 case OPT_NONE
: /* DRMODE_COMPLEMENT */
496 dst_end
= dst
+ width
;
499 while (++dst
< dst_end
);
504 /* Draw a vertical line (optimised) */
505 void lcd_vline(int x
, int y1
, int y2
)
508 fb_data
*dst
, *dst_end
;
509 lcd_fastpixelfunc_type
*pfunc
= lcd_fastpixelfuncs
[current_vp
->drawmode
];
519 /* nothing to draw? */
520 if (((unsigned)x
>= (unsigned)current_vp
->width
) ||
521 (y1
>= current_vp
->height
) ||
528 if (y2
>= current_vp
->height
)
529 y2
= current_vp
->height
-1;
531 dst
= LCDADDR(x
+ current_vp
->x
, y1
+ current_vp
->y
);
532 dst_end
= dst
+ (y2
- y1
) * LCD_WIDTH
;
539 while (dst
<= dst_end
);
542 /* Draw a rectangular box */
543 void lcd_drawrect(int x
, int y
, int width
, int height
)
545 if ((width
<= 0) || (height
<= 0))
548 int x2
= x
+ width
- 1;
549 int y2
= y
+ height
- 1;
552 lcd_vline(x2
, y
, y2
);
554 lcd_hline(x
, x2
, y2
);
557 /* Fill a rectangular area */
558 void lcd_fillrect(int x
, int y
, int width
, int height
)
561 enum fill_opt fillopt
= OPT_NONE
;
562 fb_data
*dst
, *dst_end
;
564 /* nothing to draw? */
565 if ((width
<= 0) || (height
<= 0) || (x
>= current_vp
->width
) ||
566 (y
>= current_vp
->height
) || (x
+ width
<= 0) || (y
+ height
<= 0))
569 /* drawmode and optimisation */
570 if (current_vp
->drawmode
& DRMODE_INVERSEVID
)
572 if (current_vp
->drawmode
& DRMODE_BG
)
577 bits
= current_vp
->bg_pattern
;
585 if (current_vp
->drawmode
& DRMODE_FG
)
588 bits
= current_vp
->fg_pattern
;
591 if (fillopt
== OPT_NONE
&& current_vp
->drawmode
!= DRMODE_COMPLEMENT
)
605 if (x
+ width
> current_vp
->width
)
606 width
= current_vp
->width
- x
;
607 if (y
+ height
> current_vp
->height
)
608 height
= current_vp
->height
- y
;
610 dst
= LCDADDR(current_vp
->x
+ x
, current_vp
->y
+ y
);
611 dst_end
= dst
+ height
* LCD_WIDTH
;
615 fb_data
*dst_row
, *row_end
;
620 memset16(dst
, bits
, width
);
624 memcpy(dst
, (void *)((long)dst
+ lcd_backdrop_offset
),
625 width
* sizeof(fb_data
));
628 case OPT_NONE
: /* DRMODE_COMPLEMENT */
630 row_end
= dst_row
+ width
;
632 *dst_row
= ~(*dst_row
);
633 while (++dst_row
< row_end
);
638 while (dst
< dst_end
);
641 /* Fill a rectangle with a gradient */
642 static void lcd_gradient_rect(int x1
, int x2
, int y
, int h
)
644 int old_pattern
= current_vp
->fg_pattern
;
648 int h_r
= RGB_UNPACK_RED(current_vp
->lss_pattern
) << 16;
649 int h_b
= RGB_UNPACK_BLUE(current_vp
->lss_pattern
) << 16;
650 int h_g
= RGB_UNPACK_GREEN(current_vp
->lss_pattern
) << 16;
651 int rstep
= (h_r
- ((signed)RGB_UNPACK_RED(current_vp
->lse_pattern
) << 16)) / h
;
652 int gstep
= (h_g
- ((signed)RGB_UNPACK_GREEN(current_vp
->lse_pattern
) << 16)) / h
;
653 int bstep
= (h_b
- ((signed)RGB_UNPACK_BLUE(current_vp
->lse_pattern
) << 16)) / h
;
656 current_vp
->fg_pattern
= current_vp
->lss_pattern
;
657 for(count
= 0; count
< h
; count
++) {
658 lcd_hline(x1
, x2
, y
+ count
);
662 current_vp
->fg_pattern
= LCD_RGBPACK(h_r
>> 16, h_g
>> 16, h_b
>> 16);
665 current_vp
->fg_pattern
= old_pattern
;
668 #define H_COLOR(lss, lse, cur_line, max_line) \
669 (((lse) - (lss)) * (cur_line) / (max_line) + (lss))
671 /* Fill a rectangle with a gradient for scrolling line. To draw a gradient that
672 covers several lines, we need to know how many lines will be covered
673 (the num_lines arg), and which one is the current line within the selection
674 (the cur_line arg). */
675 static void lcd_gradient_rect_scroll(int x1
, int x2
, int y
, int h
,
676 unsigned char num_lines
, unsigned char cur_line
)
678 if (h
== 0 || num_lines
== 0) return;
680 unsigned tmp_lss
= current_vp
->lss_pattern
;
681 unsigned tmp_lse
= current_vp
->lse_pattern
;
682 int lss_r
= (signed)RGB_UNPACK_RED(current_vp
->lss_pattern
);
683 int lss_b
= (signed)RGB_UNPACK_BLUE(current_vp
->lss_pattern
);
684 int lss_g
= (signed)RGB_UNPACK_GREEN(current_vp
->lss_pattern
);
685 int lse_r
= (signed)RGB_UNPACK_RED(current_vp
->lse_pattern
);
686 int lse_b
= (signed)RGB_UNPACK_BLUE(current_vp
->lse_pattern
);
687 int lse_g
= (signed)RGB_UNPACK_GREEN(current_vp
->lse_pattern
);
689 int h_r
= H_COLOR(lss_r
, lse_r
, cur_line
, num_lines
);
690 int h_g
= H_COLOR(lss_g
, lse_g
, cur_line
, num_lines
);
691 int h_b
= H_COLOR(lss_b
, lse_b
, cur_line
, num_lines
);
692 lcd_set_selector_start(LCD_RGBPACK(h_r
, h_g
, h_b
));
694 int l_r
= H_COLOR(lss_r
, lse_r
, cur_line
+1, num_lines
);
695 int l_g
= H_COLOR(lss_g
, lse_g
, cur_line
+1, num_lines
);
696 int l_b
= H_COLOR(lss_b
, lse_b
, cur_line
+1, num_lines
);
697 lcd_set_selector_end(LCD_RGBPACK(l_r
, l_g
, l_b
));
699 lcd_gradient_rect(x1
, x2
, y
, h
);
701 current_vp
->lss_pattern
= tmp_lss
;
702 current_vp
->lse_pattern
= tmp_lse
;
705 /* About Rockbox' internal monochrome bitmap format:
707 * A bitmap contains one bit for every pixel that defines if that pixel is
708 * black (1) or white (0). Bits within a byte are arranged vertically, LSB
710 * The bytes are stored in row-major order, with byte 0 being top left,
711 * byte 1 2nd from left etc. The first row of bytes defines pixel rows
712 * 0..7, the second row defines pixel row 8..15 etc.
714 * This is the mono bitmap format used on all other targets so far; the
715 * pixel packing doesn't really matter on a 8bit+ target. */
717 /* Draw a partial monochrome bitmap */
719 void ICODE_ATTR
lcd_mono_bitmap_part(const unsigned char *src
, int src_x
,
720 int src_y
, int stride
, int x
, int y
,
721 int width
, int height
)
723 const unsigned char *src_end
;
724 fb_data
*dst
, *dst_end
;
725 unsigned dmask
= 0x100; /* bit 8 == sentinel */
726 int drmode
= current_vp
->drawmode
;
728 /* nothing to draw? */
729 if ((width
<= 0) || (height
<= 0) || (x
>= current_vp
->width
) ||
730 (y
>= current_vp
->height
) || (x
+ width
<= 0) || (y
+ height
<= 0))
746 if (x
+ width
> current_vp
->width
)
747 width
= current_vp
->width
- x
;
748 if (y
+ height
> current_vp
->height
)
749 height
= current_vp
->height
- y
;
751 src
+= stride
* (src_y
>> 3) + src_x
; /* move starting point */
753 src_end
= src
+ width
;
754 dst
= LCDADDR(current_vp
->x
+ x
, current_vp
->y
+ y
);
756 if (drmode
& DRMODE_INVERSEVID
)
758 dmask
= 0x1ff; /* bit 8 == sentinel */
759 drmode
&= DRMODE_SOLID
; /* mask out inversevid */
764 const unsigned char *src_col
= src
++;
765 unsigned data
= (*src_col
^ dmask
) >> src_y
;
766 fb_data
*dst_col
= dst
++;
770 dst_end
= dst_col
+ height
* LCD_WIDTH
;
772 #define UPDATE_SRC do { \
774 if (data == 0x001) { \
776 data = *src_col ^ dmask; \
782 case DRMODE_COMPLEMENT
:
786 *dst_col
= ~(*dst_col
);
788 dst_col
+= LCD_WIDTH
;
791 while (dst_col
< dst_end
);
797 bo
= lcd_backdrop_offset
;
801 *dst_col
= *(fb_data
*)((long)dst_col
+ bo
);
803 dst_col
+= LCD_WIDTH
;
806 while (dst_col
< dst_end
);
810 bg
= current_vp
->bg_pattern
;
816 dst_col
+= LCD_WIDTH
;
819 while (dst_col
< dst_end
);
824 fg
= current_vp
->fg_pattern
;
830 dst_col
+= LCD_WIDTH
;
833 while (dst_col
< dst_end
);
837 fg
= current_vp
->fg_pattern
;
840 bo
= lcd_backdrop_offset
;
843 *dst_col
= (data
& 0x01) ? fg
844 : *(fb_data
*)((long)dst_col
+ bo
);
845 dst_col
+= LCD_WIDTH
;
848 while (dst_col
< dst_end
);
852 bg
= current_vp
->bg_pattern
;
855 *dst_col
= (data
& 0x01) ? fg
: bg
;
856 dst_col
+= LCD_WIDTH
;
859 while (dst_col
< dst_end
);
864 while (src
< src_end
);
866 /* Draw a full monochrome bitmap */
867 void lcd_mono_bitmap(const unsigned char *src
, int x
, int y
, int width
, int height
)
869 lcd_mono_bitmap_part(src
, 0, 0, width
, x
, y
, width
, height
);
872 /* Draw a partial native bitmap */
873 void ICODE_ATTR
lcd_bitmap_part(const fb_data
*src
, int src_x
, int src_y
,
874 int stride
, int x
, int y
, int width
,
877 fb_data
*dst
, *dst_end
;
879 /* nothing to draw? */
880 if ((width
<= 0) || (height
<= 0) || (x
>= current_vp
->width
) ||
881 (y
>= current_vp
->height
) || (x
+ width
<= 0) || (y
+ height
<= 0))
897 if (x
+ width
> current_vp
->width
)
898 width
= current_vp
->width
- x
;
899 if (y
+ height
> current_vp
->height
)
900 height
= current_vp
->height
- y
;
902 src
+= stride
* src_y
+ src_x
; /* move starting point */
903 dst
= LCDADDR(current_vp
->x
+ x
, current_vp
->y
+ y
);
904 dst_end
= dst
+ height
* LCD_WIDTH
;
908 memcpy(dst
, src
, width
* sizeof(fb_data
));
912 while (dst
< dst_end
);
915 /* Draw a full native bitmap */
916 void lcd_bitmap(const fb_data
*src
, int x
, int y
, int width
, int height
)
918 lcd_bitmap_part(src
, 0, 0, width
, x
, y
, width
, height
);
921 #if !defined(TOSHIBA_GIGABEAT_F) && !defined(TOSHIBA_GIGABEAT_S) \
922 || defined(SIMULATOR)
923 /* Draw a partial native bitmap */
924 void ICODE_ATTR
lcd_bitmap_transparent_part(const fb_data
*src
, int src_x
,
925 int src_y
, int stride
, int x
,
926 int y
, int width
, int height
)
928 fb_data
*dst
, *dst_end
;
930 /* nothing to draw? */
931 if ((width
<= 0) || (height
<= 0) || (x
>= current_vp
->width
) ||
932 (y
>= current_vp
->height
) || (x
+ width
<= 0) || (y
+ height
<= 0))
948 if (x
+ width
> current_vp
->width
)
949 width
= current_vp
->width
- x
;
950 if (y
+ height
> current_vp
->height
)
951 height
= current_vp
->height
- y
;
953 src
+= stride
* src_y
+ src_x
; /* move starting point */
954 dst
= LCDADDR(current_vp
->x
+ x
, current_vp
->y
+ y
);
955 dst_end
= dst
+ height
* LCD_WIDTH
;
960 for(i
= 0;i
< width
;i
++)
962 if (src
[i
] == REPLACEWITHFG_COLOR
)
963 dst
[i
] = current_vp
->fg_pattern
;
964 else if(src
[i
] != TRANSPARENT_COLOR
)
970 while (dst
< dst_end
);
972 #endif /* !defined(TOSHIBA_GIGABEAT_F) || defined(SIMULATOR) */
974 /* Draw a full native bitmap with a transparent color */
975 void lcd_bitmap_transparent(const fb_data
*src
, int x
, int y
,
976 int width
, int height
)
978 lcd_bitmap_transparent_part(src
, 0, 0, width
, x
, y
, width
, height
);
981 /* put a string at a given pixel position, skipping first ofs pixel columns */
982 static void lcd_putsxyofs(int x
, int y
, int ofs
, const unsigned char *str
)
986 struct font
* pf
= font_get(current_vp
->font
);
988 ucs
= bidi_l2v(str
, 1);
990 while ((ch
= *ucs
++) != 0 && x
< current_vp
->width
)
993 const unsigned char *bits
;
995 /* get proportional width and glyph bits */
996 width
= font_get_width(pf
,ch
);
1004 bits
= font_get_bits(pf
, ch
);
1006 lcd_mono_bitmap_part(bits
, ofs
, 0, width
, x
, y
, width
- ofs
, pf
->height
);
1013 /* put a string at a given pixel position */
1014 void lcd_putsxy(int x
, int y
, const unsigned char *str
)
1016 lcd_putsxyofs(x
, y
, 0, str
);
1019 /*** line oriented text output ***/
1021 /* put a string at a given char position */
1022 void lcd_puts(int x
, int y
, const unsigned char *str
)
1024 lcd_puts_style_offset(x
, y
, str
, STYLE_DEFAULT
, 0);
1027 void lcd_puts_style(int x
, int y
, const unsigned char *str
, int style
)
1029 lcd_puts_style_offset(x
, y
, str
, style
, 0);
1032 void lcd_puts_offset(int x
, int y
, const unsigned char *str
, int offset
)
1034 lcd_puts_style_offset(x
, y
, str
, STYLE_DEFAULT
, offset
);
1037 /* put a string at a given char position, style, and pixel position,
1038 * skipping first offset pixel columns */
1039 void lcd_puts_style_offset(int x
, int y
, const unsigned char *str
, int style
,
1042 int xpos
,ypos
,w
,h
,xrect
;
1043 int lastmode
= current_vp
->drawmode
;
1044 int oldfgcolor
= current_vp
->fg_pattern
;
1045 int oldbgcolor
= current_vp
->bg_pattern
;
1047 /* make sure scrolling is turned off on the line we are updating */
1048 lcd_scroll_stop_line(current_vp
, y
);
1053 lcd_getstringsize(str
, &w
, &h
);
1054 xpos
= x
*w
/ utf8length(str
);
1056 current_vp
->drawmode
= (style
& STYLE_INVERT
) ?
1057 (DRMODE_SOLID
|DRMODE_INVERSEVID
) : DRMODE_SOLID
;
1058 if (style
& STYLE_COLORED
) {
1059 if (current_vp
->drawmode
== DRMODE_SOLID
)
1060 current_vp
->fg_pattern
= style
& STYLE_COLOR_MASK
;
1062 current_vp
->bg_pattern
= style
& STYLE_COLOR_MASK
;
1064 current_vp
->drawmode
^= DRMODE_INVERSEVID
;
1065 xrect
= xpos
+ MAX(w
- offset
, 0);
1067 if (style
& STYLE_GRADIENT
) {
1068 current_vp
->drawmode
= DRMODE_FG
;
1069 if (CURLN_UNPACK(style
) == 0)
1070 lcd_gradient_rect(xpos
, current_vp
->width
, ypos
, h
*NUMLN_UNPACK(style
));
1071 current_vp
->fg_pattern
= current_vp
->lst_pattern
;
1073 else if (style
& STYLE_COLORBAR
) {
1074 current_vp
->drawmode
= DRMODE_FG
;
1075 current_vp
->fg_pattern
= current_vp
->lss_pattern
;
1076 lcd_fillrect(xpos
, ypos
, current_vp
->width
- xpos
, h
);
1077 current_vp
->fg_pattern
= current_vp
->lst_pattern
;
1080 lcd_fillrect(xrect
, ypos
, current_vp
->width
- xrect
, h
);
1081 current_vp
->drawmode
= (style
& STYLE_INVERT
) ?
1082 (DRMODE_SOLID
|DRMODE_INVERSEVID
) : DRMODE_SOLID
;
1084 lcd_putsxyofs(xpos
, ypos
, offset
, str
);
1085 current_vp
->drawmode
= lastmode
;
1086 current_vp
->fg_pattern
= oldfgcolor
;
1087 current_vp
->bg_pattern
= oldbgcolor
;
1091 void lcd_puts_scroll(int x
, int y
, const unsigned char *string
)
1093 lcd_puts_scroll_style(x
, y
, string
, STYLE_DEFAULT
);
1096 void lcd_puts_scroll_style(int x
, int y
, const unsigned char *string
, int style
)
1098 lcd_puts_scroll_style_offset(x
, y
, string
, style
, 0);
1101 void lcd_puts_scroll_offset(int x
, int y
, const unsigned char *string
, int offset
)
1103 lcd_puts_scroll_style_offset(x
, y
, string
, STYLE_DEFAULT
, offset
);
1106 /* Initialise a scrolling line at (x,y) in current viewport */
1108 void lcd_puts_scroll_style_offset(int x
, int y
, const unsigned char *string
,
1109 int style
, int offset
)
1111 struct scrollinfo
* s
;
1114 if ((unsigned)y
>= (unsigned)current_vp
->height
)
1117 /* remove any previously scrolling line at the same location */
1118 lcd_scroll_stop_line(current_vp
, y
);
1120 if (lcd_scroll_info
.lines
>= LCD_SCROLLABLE_LINES
) return;
1122 s
= &lcd_scroll_info
.scroll
[lcd_scroll_info
.lines
];
1124 s
->start_tick
= current_tick
+ lcd_scroll_info
.delay
;
1126 lcd_puts_style_offset(x
,y
,string
,style
,offset
);
1128 lcd_getstringsize(string
, &w
, &h
);
1130 if (current_vp
->width
- x
* 8 < w
) {
1131 /* prepare scroll line */
1134 memset(s
->line
, 0, sizeof s
->line
);
1135 strcpy(s
->line
, string
);
1138 s
->width
= lcd_getstringsize(s
->line
, &w
, &h
);
1140 /* scroll bidirectional or forward only depending on the string
1142 if ( lcd_scroll_info
.bidir_limit
) {
1143 s
->bidir
= s
->width
< (current_vp
->width
) *
1144 (100 + lcd_scroll_info
.bidir_limit
) / 100;
1149 if (!s
->bidir
) { /* add spaces if scrolling in the round */
1150 strcat(s
->line
, " ");
1151 /* get new width incl. spaces */
1152 s
->width
= lcd_getstringsize(s
->line
, &w
, &h
);
1155 end
= strchr(s
->line
, '\0');
1156 strncpy(end
, string
, current_vp
->width
/2);
1160 s
->len
= utf8length(string
);
1162 s
->startx
= x
* s
->width
/ s
->len
;
1163 s
->backward
= false;
1164 lcd_scroll_info
.lines
++;
1168 void lcd_scroll_fn(void)
1171 struct scrollinfo
* s
;
1175 unsigned old_fgcolor
;
1176 unsigned old_bgcolor
;
1177 struct viewport
* old_vp
= current_vp
;
1179 for ( index
= 0; index
< lcd_scroll_info
.lines
; index
++ ) {
1180 s
= &lcd_scroll_info
.scroll
[index
];
1183 if (TIME_BEFORE(current_tick
, s
->start_tick
))
1186 lcd_set_viewport(s
->vp
);
1187 old_fgcolor
= current_vp
->fg_pattern
;
1188 old_bgcolor
= current_vp
->bg_pattern
;
1190 if (s
->style
&STYLE_COLORED
) {
1191 if (s
->style
&STYLE_MODE_MASK
) {
1192 current_vp
->fg_pattern
= old_fgcolor
;
1193 current_vp
->bg_pattern
= s
->style
&STYLE_COLOR_MASK
;
1196 current_vp
->fg_pattern
= s
->style
&STYLE_COLOR_MASK
;
1197 current_vp
->bg_pattern
= old_bgcolor
;
1202 s
->offset
-= lcd_scroll_info
.step
;
1204 s
->offset
+= lcd_scroll_info
.step
;
1206 pf
= font_get(current_vp
->font
);
1208 ypos
= s
->y
* pf
->height
;
1210 if (s
->bidir
) { /* scroll bidirectional */
1211 if (s
->offset
<= 0) {
1212 /* at beginning of line */
1214 s
->backward
= false;
1215 s
->start_tick
= current_tick
+ lcd_scroll_info
.delay
* 2;
1217 if (s
->offset
>= s
->width
- (current_vp
->width
- xpos
)) {
1218 /* at end of line */
1219 s
->offset
= s
->width
- (current_vp
->width
- xpos
);
1221 s
->start_tick
= current_tick
+ lcd_scroll_info
.delay
* 2;
1225 /* scroll forward the whole time */
1226 if (s
->offset
>= s
->width
)
1227 s
->offset
%= s
->width
;
1230 lastmode
= current_vp
->drawmode
;
1231 switch (s
->style
&STYLE_MODE_MASK
) {
1233 current_vp
->drawmode
= DRMODE_SOLID
|DRMODE_INVERSEVID
;
1235 case STYLE_COLORBAR
:
1236 /* Solid colour line selector */
1237 current_vp
->drawmode
= DRMODE_FG
;
1238 current_vp
->fg_pattern
= current_vp
->lss_pattern
;
1239 lcd_fillrect(xpos
, ypos
, current_vp
->width
- xpos
, pf
->height
);
1240 current_vp
->fg_pattern
= current_vp
->lst_pattern
;
1242 case STYLE_GRADIENT
:
1243 /* Gradient line selector */
1244 current_vp
->drawmode
= DRMODE_FG
;
1245 lcd_gradient_rect_scroll(xpos
, current_vp
->width
, ypos
, (signed)pf
->height
,
1246 NUMLN_UNPACK(s
->style
),
1247 CURLN_UNPACK(s
->style
));
1248 current_vp
->fg_pattern
= current_vp
->lst_pattern
;
1251 current_vp
->drawmode
= DRMODE_SOLID
;
1254 lcd_putsxyofs(xpos
, ypos
, s
->offset
, s
->line
);
1255 current_vp
->drawmode
= lastmode
;
1256 current_vp
->fg_pattern
= old_fgcolor
;
1257 current_vp
->bg_pattern
= old_bgcolor
;
1258 lcd_update_viewport_rect(xpos
, ypos
, current_vp
->width
- xpos
, pf
->height
);
1261 lcd_set_viewport(old_vp
);