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 * All files in this archive are subject to the GNU General Public License.
15 * See the file COPYING in the source tree root for full license agreement.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
34 #include "rbunicode.h"
36 #include "scroll_engine.h"
45 fb_data lcd_framebuffer
[LCD_FBHEIGHT
][LCD_FBWIDTH
]
46 IRAM_LCDFRAMEBUFFER
CACHEALIGN_AT_LEAST_ATTR(16);
49 static fb_data
* lcd_backdrop
= NULL
;
50 static long lcd_backdrop_offset IDATA_ATTR
= 0;
52 static struct viewport default_vp
=
58 .font
= FONT_SYSFIXED
,
59 .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(SIMULATOR)
72 static struct viewport
* current_vp IDATA_ATTR
= &default_vp
;
74 struct viewport
* current_vp IDATA_ATTR
= &default_vp
;
82 /* Call device specific init */
89 void lcd_set_viewport(struct viewport
* vp
)
92 current_vp
= &default_vp
;
97 void lcd_update_viewport(void)
99 lcd_update_rect(current_vp
->x
, current_vp
->y
,
100 current_vp
->width
, current_vp
->height
);
103 void lcd_update_viewport_rect(int x
, int y
, int width
, int height
)
105 lcd_update_rect(current_vp
->x
+ x
, current_vp
->y
+ y
, width
, height
);
108 /*** parameter handling ***/
110 void lcd_set_drawmode(int mode
)
112 current_vp
->drawmode
= mode
& (DRMODE_SOLID
|DRMODE_INVERSEVID
);
115 int lcd_get_drawmode(void)
117 return current_vp
->drawmode
;
120 void lcd_set_foreground(unsigned color
)
122 current_vp
->fg_pattern
= color
;
125 unsigned lcd_get_foreground(void)
127 return current_vp
->fg_pattern
;
130 void lcd_set_background(unsigned color
)
132 current_vp
->bg_pattern
= color
;
135 unsigned lcd_get_background(void)
137 return current_vp
->bg_pattern
;
140 void lcd_set_selector_start(unsigned color
)
142 current_vp
->lss_pattern
= color
;
145 void lcd_set_selector_end(unsigned color
)
147 current_vp
->lse_pattern
= color
;
150 void lcd_set_selector_text(unsigned color
)
152 current_vp
->lst_pattern
= color
;
155 void lcd_set_drawinfo(int mode
, unsigned fg_color
, unsigned bg_color
)
157 lcd_set_drawmode(mode
);
158 current_vp
->fg_pattern
= fg_color
;
159 current_vp
->bg_pattern
= bg_color
;
162 void lcd_setmargins(int x
, int y
)
164 current_vp
->xmargin
= x
;
165 current_vp
->ymargin
= y
;
168 int lcd_getwidth(void)
170 return current_vp
->width
;
173 int lcd_getheight(void)
175 return current_vp
->height
;
178 int lcd_getxmargin(void)
180 return current_vp
->xmargin
;
183 int lcd_getymargin(void)
185 return current_vp
->ymargin
;
188 void lcd_setfont(int newfont
)
190 current_vp
->font
= newfont
;
193 int lcd_getfont(void)
195 return current_vp
->font
;
198 int lcd_getstringsize(const unsigned char *str
, int *w
, int *h
)
200 return font_getstringsize(str
, w
, h
, current_vp
->font
);
203 /*** low-level drawing functions ***/
205 #define LCDADDR(x, y) (&lcd_framebuffer[(y)][(x)])
207 static void setpixel(fb_data
*address
) ICODE_ATTR
;
208 static void setpixel(fb_data
*address
)
210 *address
= current_vp
->fg_pattern
;
213 static void clearpixel(fb_data
*address
) ICODE_ATTR
;
214 static void clearpixel(fb_data
*address
)
216 *address
= current_vp
->bg_pattern
;
219 static void clearimgpixel(fb_data
*address
) ICODE_ATTR
;
220 static void clearimgpixel(fb_data
*address
)
222 *address
= *(fb_data
*)((long)address
+ lcd_backdrop_offset
);
225 static void flippixel(fb_data
*address
) ICODE_ATTR
;
226 static void flippixel(fb_data
*address
)
228 *address
= ~(*address
);
231 static void nopixel(fb_data
*address
) ICODE_ATTR
;
232 static void nopixel(fb_data
*address
)
237 lcd_fastpixelfunc_type
* const lcd_fastpixelfuncs_bgcolor
[8] = {
238 flippixel
, nopixel
, setpixel
, setpixel
,
239 nopixel
, clearpixel
, nopixel
, clearpixel
242 lcd_fastpixelfunc_type
* const lcd_fastpixelfuncs_backdrop
[8] = {
243 flippixel
, nopixel
, setpixel
, setpixel
,
244 nopixel
, clearimgpixel
, nopixel
, clearimgpixel
247 lcd_fastpixelfunc_type
* const * lcd_fastpixelfuncs
= lcd_fastpixelfuncs_bgcolor
;
249 void lcd_set_backdrop(fb_data
* backdrop
)
251 lcd_backdrop
= backdrop
;
254 lcd_backdrop_offset
= (long)backdrop
- (long)&lcd_framebuffer
[0][0];
255 lcd_fastpixelfuncs
= lcd_fastpixelfuncs_backdrop
;
259 lcd_backdrop_offset
= 0;
260 lcd_fastpixelfuncs
= lcd_fastpixelfuncs_bgcolor
;
264 fb_data
* lcd_get_backdrop(void)
269 /*** drawing functions ***/
271 /* Clear the current viewport */
272 void lcd_clear_viewport(void)
274 fb_data
*dst
, *dst_end
;
276 dst
= LCDADDR(current_vp
->x
, current_vp
->y
);
277 dst_end
= dst
+ current_vp
->height
* LCD_WIDTH
;
279 if (current_vp
->drawmode
& DRMODE_INVERSEVID
)
283 memset16(dst
, current_vp
->fg_pattern
, current_vp
->width
);
286 while (dst
< dst_end
);
294 memset16(dst
, current_vp
->bg_pattern
, current_vp
->width
);
297 while (dst
< dst_end
);
303 memcpy(dst
, (void *)((long)dst
+ lcd_backdrop_offset
),
304 current_vp
->width
* sizeof(fb_data
));
307 while (dst
< dst_end
);
311 if (current_vp
== &default_vp
)
313 lcd_scroll_info
.lines
= 0;
317 lcd_scroll_stop(current_vp
);
321 /* Clear the whole display */
322 void lcd_clear_display(void)
324 struct viewport
* old_vp
= current_vp
;
326 current_vp
= &default_vp
;
328 lcd_clear_viewport();
333 /* Set a single pixel */
334 void lcd_drawpixel(int x
, int y
)
336 if (((unsigned)x
< (unsigned)current_vp
->width
) &&
337 ((unsigned)y
< (unsigned)current_vp
->height
))
338 lcd_fastpixelfuncs
[current_vp
->drawmode
](LCDADDR(current_vp
->x
+x
, current_vp
->y
+y
));
342 void lcd_drawline(int x1
, int y1
, int x2
, int y2
)
350 lcd_fastpixelfunc_type
*pfunc
= lcd_fastpixelfuncs
[current_vp
->drawmode
];
352 deltax
= abs(x2
- x1
);
353 deltay
= abs(y2
- y1
);
357 if (deltax
>= deltay
)
360 d
= 2 * deltay
- deltax
;
362 dinc2
= (deltay
- deltax
) * 2;
369 d
= 2 * deltax
- deltay
;
371 dinc2
= (deltax
- deltay
) * 2;
375 numpixels
++; /* include endpoints */
392 for (i
= 0; i
< numpixels
; i
++)
394 if (((unsigned)x
< (unsigned)current_vp
->width
) && ((unsigned)y
< (unsigned)current_vp
->height
))
395 pfunc(LCDADDR(x
+ current_vp
->x
, y
+ current_vp
->y
));
412 /* Draw a horizontal line (optimised) */
413 void lcd_hline(int x1
, int x2
, int y
)
417 enum fill_opt fillopt
= OPT_NONE
;
418 fb_data
*dst
, *dst_end
;
419 lcd_fastpixelfunc_type
*pfunc
= lcd_fastpixelfuncs
[current_vp
->drawmode
];
429 /* nothing to draw? */
430 if (((unsigned)y
>= (unsigned)current_vp
->height
) ||
431 (x1
>= current_vp
->width
) ||
438 if (x2
>= current_vp
->width
)
439 x2
= current_vp
->width
-1;
443 /* Adjust x1 and y to viewport */
447 if (current_vp
->drawmode
& DRMODE_INVERSEVID
)
449 if (current_vp
->drawmode
& DRMODE_BG
)
454 bits
= current_vp
->bg_pattern
;
462 if (current_vp
->drawmode
& DRMODE_FG
)
465 bits
= current_vp
->fg_pattern
;
468 dst
= LCDADDR(x1
, y
);
473 memset16(dst
, bits
, width
);
477 memcpy(dst
, (void *)((long)dst
+ lcd_backdrop_offset
),
478 width
* sizeof(fb_data
));
482 dst_end
= dst
+ width
;
485 while (dst
< dst_end
);
490 /* Draw a vertical line (optimised) */
491 void lcd_vline(int x
, int y1
, int y2
)
494 fb_data
*dst
, *dst_end
;
495 lcd_fastpixelfunc_type
*pfunc
= lcd_fastpixelfuncs
[current_vp
->drawmode
];
505 /* nothing to draw? */
506 if ((x
>= current_vp
->width
) ||
507 (y1
>= current_vp
->height
) ||
514 if (y2
>= current_vp
->height
)
515 y2
= current_vp
->height
-1;
517 dst
= LCDADDR(x
+ current_vp
->x
, y1
+ current_vp
->y
);
518 dst_end
= dst
+ (y2
- y1
) * LCD_WIDTH
;
525 while (dst
<= dst_end
);
528 /* Draw a rectangular box */
529 void lcd_drawrect(int x
, int y
, int width
, int height
)
531 if ((width
<= 0) || (height
<= 0))
534 int x2
= x
+ width
- 1;
535 int y2
= y
+ height
- 1;
538 lcd_vline(x2
, y
, y2
);
540 lcd_hline(x
, x2
, y2
);
543 /* Fill a rectangular area */
544 void lcd_fillrect(int x
, int y
, int width
, int height
)
547 enum fill_opt fillopt
= OPT_NONE
;
548 fb_data
*dst
, *dst_end
;
549 lcd_fastpixelfunc_type
*pfunc
= lcd_fastpixelfuncs
[current_vp
->drawmode
];
551 /* nothing to draw? */
552 if ((width
<= 0) || (height
<= 0) || (x
>= current_vp
->width
) ||
553 (y
>= current_vp
->height
) || (x
+ width
<= 0) || (y
+ height
<= 0))
567 if (x
+ width
> current_vp
->width
)
568 width
= current_vp
->width
- x
;
569 if (y
+ height
> current_vp
->height
)
570 height
= current_vp
->height
- y
;
572 if (current_vp
->drawmode
& DRMODE_INVERSEVID
)
574 if (current_vp
->drawmode
& DRMODE_BG
)
579 bits
= current_vp
->bg_pattern
;
587 if (current_vp
->drawmode
& DRMODE_FG
)
590 bits
= current_vp
->fg_pattern
;
593 dst
= LCDADDR(current_vp
->x
+ x
, current_vp
->y
+ y
);
594 dst_end
= dst
+ height
* LCD_WIDTH
;
598 fb_data
*dst_row
, *row_end
;
603 memset16(dst
, bits
, width
);
607 memcpy(dst
, (void *)((long)dst
+ lcd_backdrop_offset
),
608 width
* sizeof(fb_data
));
613 row_end
= dst_row
+ width
;
616 while (dst_row
< row_end
);
621 while (dst
< dst_end
);
624 /* Fill a rectangle with a gradient */
625 void lcd_gradient_rect(int x1
, int x2
, int y
, int h
)
627 int old_pattern
= current_vp
->fg_pattern
;
631 int h_r
= RGB_UNPACK_RED(current_vp
->lss_pattern
) << 16;
632 int h_b
= RGB_UNPACK_BLUE(current_vp
->lss_pattern
) << 16;
633 int h_g
= RGB_UNPACK_GREEN(current_vp
->lss_pattern
) << 16;
634 int rstep
= (h_r
- ((signed)RGB_UNPACK_RED(current_vp
->lse_pattern
) << 16)) / h
;
635 int gstep
= (h_g
- ((signed)RGB_UNPACK_GREEN(current_vp
->lse_pattern
) << 16)) / h
;
636 int bstep
= (h_b
- ((signed)RGB_UNPACK_BLUE(current_vp
->lse_pattern
) << 16)) / h
;
639 current_vp
->fg_pattern
= current_vp
->lss_pattern
;
640 for(count
= 0; count
< h
; count
++) {
641 lcd_hline(x1
, x2
, y
+ count
);
645 current_vp
->fg_pattern
= LCD_RGBPACK(h_r
>> 16, h_g
>> 16, h_b
>> 16);
648 current_vp
->fg_pattern
= old_pattern
;
651 #define H_COLOR(lss, lse, cur_line, max_line) \
652 (((lse) - (lss)) * (cur_line) / (max_line) + (lss))
654 /* Fill a rectangle with a gradient for scrolling line. To draw a gradient that
655 covers several lines, we need to know how many lines will be covered
656 (the num_lines arg), and which one is the current line within the selection
657 (the cur_line arg). */
658 void lcd_gradient_rect_scroll(int x1
, int x2
, int y
, int h
,
659 unsigned char num_lines
, unsigned char cur_line
)
661 if (h
== 0 || num_lines
== 0) return;
663 unsigned tmp_lss
= current_vp
->lss_pattern
;
664 unsigned tmp_lse
= current_vp
->lse_pattern
;
665 int lss_r
= (signed)RGB_UNPACK_RED(current_vp
->lss_pattern
);
666 int lss_b
= (signed)RGB_UNPACK_BLUE(current_vp
->lss_pattern
);
667 int lss_g
= (signed)RGB_UNPACK_GREEN(current_vp
->lss_pattern
);
668 int lse_r
= (signed)RGB_UNPACK_RED(current_vp
->lse_pattern
);
669 int lse_b
= (signed)RGB_UNPACK_BLUE(current_vp
->lse_pattern
);
670 int lse_g
= (signed)RGB_UNPACK_GREEN(current_vp
->lse_pattern
);
672 int h_r
= H_COLOR(lss_r
, lse_r
, cur_line
, num_lines
);
673 int h_g
= H_COLOR(lss_g
, lse_g
, cur_line
, num_lines
);
674 int h_b
= H_COLOR(lss_b
, lse_b
, cur_line
, num_lines
);
675 lcd_set_selector_start(LCD_RGBPACK(h_r
, h_g
, h_b
));
677 int l_r
= H_COLOR(lss_r
, lse_r
, cur_line
+1, num_lines
);
678 int l_g
= H_COLOR(lss_g
, lse_g
, cur_line
+1, num_lines
);
679 int l_b
= H_COLOR(lss_b
, lse_b
, cur_line
+1, num_lines
);
680 lcd_set_selector_end(LCD_RGBPACK(l_r
, l_g
, l_b
));
682 lcd_gradient_rect(x1
, x2
, y
, h
);
684 current_vp
->lss_pattern
= tmp_lss
;
685 current_vp
->lse_pattern
= tmp_lse
;
688 /* About Rockbox' internal monochrome bitmap format:
690 * A bitmap contains one bit for every pixel that defines if that pixel is
691 * black (1) or white (0). Bits within a byte are arranged vertically, LSB
693 * The bytes are stored in row-major order, with byte 0 being top left,
694 * byte 1 2nd from left etc. The first row of bytes defines pixel rows
695 * 0..7, the second row defines pixel row 8..15 etc.
697 * This is the mono bitmap format used on all other targets so far; the
698 * pixel packing doesn't really matter on a 8bit+ target. */
700 /* Draw a partial monochrome bitmap */
702 void lcd_mono_bitmap_part(const unsigned char *src
, int src_x
, int src_y
,
703 int stride
, int x
, int y
, int width
, int height
)
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 const unsigned char *src_end
;
710 fb_data
*dst
, *dst_end
, *backdrop
;
711 lcd_fastpixelfunc_type
*fgfunc
, *bgfunc
;
713 /* nothing to draw? */
714 if ((width
<= 0) || (height
<= 0) || (x
>= current_vp
->width
) ||
715 (y
>= current_vp
->height
) || (x
+ width
<= 0) || (y
+ height
<= 0))
731 if (x
+ width
> current_vp
->width
)
732 width
= current_vp
->width
- x
;
733 if (y
+ height
> current_vp
->height
)
734 height
= current_vp
->height
- y
;
736 src
+= stride
* (src_y
>> 3) + src_x
; /* move starting point */
738 src_end
= src
+ width
;
740 dst
= LCDADDR(current_vp
->x
+ x
, current_vp
->y
+ y
);
741 has_backdrop
= (lcd_backdrop
!= NULL
);
742 backdrop
= lcd_backdrop
+ (current_vp
->y
+ y
) * LCD_WIDTH
+ current_vp
->x
+ x
;
743 fgfunc
= lcd_fastpixelfuncs
[current_vp
->drawmode
];
744 bgfunc
= lcd_fastpixelfuncs
[current_vp
->drawmode
^ DRMODE_INVERSEVID
];
747 const unsigned char *src_col
= src
++;
748 unsigned data
= *src_col
>> src_y
;
749 fb_data
*dst_col
= dst
++;
750 int numbits
= 8 - src_y
;
751 fb_data
*backdrop_col
= backdrop
++;
752 dst_end
= dst_col
+ height
* LCD_WIDTH
;
755 switch (current_vp
->drawmode
)
759 *dst_col
= current_vp
->fg_pattern
;
761 *dst_col
= has_backdrop
? *backdrop_col
: current_vp
->bg_pattern
;
765 *dst_col
= current_vp
->fg_pattern
;
767 case (DRMODE_SOLID
|DRMODE_INVERSEVID
):
769 *dst_col
= has_backdrop
? *backdrop_col
: current_vp
->bg_pattern
;
771 *dst_col
= current_vp
->fg_pattern
;
780 dst_col
+= LCD_WIDTH
;
781 backdrop_col
+= LCD_WIDTH
;
790 while (dst_col
< dst_end
);
792 while (src
< src_end
);
794 /* Draw a full monochrome bitmap */
795 void lcd_mono_bitmap(const unsigned char *src
, int x
, int y
, int width
, int height
)
797 lcd_mono_bitmap_part(src
, 0, 0, width
, x
, y
, width
, height
);
800 /* Draw a partial native bitmap */
801 void lcd_bitmap_part(const fb_data
*src
, int src_x
, int src_y
,
802 int stride
, int x
, int y
, int width
, int height
)
804 void lcd_bitmap_part(const fb_data
*src
, int src_x
, int src_y
,
805 int stride
, int x
, int y
, int width
, int height
)
807 fb_data
*dst
, *dst_end
;
809 /* nothing to draw? */
810 if ((width
<= 0) || (height
<= 0) || (x
>= current_vp
->width
) ||
811 (y
>= current_vp
->height
) || (x
+ width
<= 0) || (y
+ height
<= 0))
827 if (x
+ width
> current_vp
->width
)
828 width
= current_vp
->width
- x
;
829 if (y
+ height
> current_vp
->height
)
830 height
= current_vp
->height
- y
;
832 src
+= stride
* src_y
+ src_x
; /* move starting point */
833 dst
= LCDADDR(current_vp
->x
+ x
, current_vp
->y
+ y
);
834 dst_end
= dst
+ height
* LCD_WIDTH
;
838 memcpy(dst
, src
, width
* sizeof(fb_data
));
842 while (dst
< dst_end
);
845 /* Draw a full native bitmap */
846 void lcd_bitmap(const fb_data
*src
, int x
, int y
, int width
, int height
)
848 lcd_bitmap_part(src
, 0, 0, width
, x
, y
, width
, height
);
851 #if !defined(TOSHIBA_GIGABEAT_F) && !defined(TOSHIBA_GIGABEAT_S) \
852 || defined(SIMULATOR)
853 /* Draw a partial native bitmap */
854 void lcd_bitmap_transparent_part(const fb_data
*src
, int src_x
, int src_y
,
855 int stride
, int x
, int y
, int width
,
856 int height
) ICODE_ATTR
;
857 void lcd_bitmap_transparent_part(const fb_data
*src
, int src_x
, int src_y
,
858 int stride
, int x
, int y
, int width
,
861 fb_data
*dst
, *dst_end
;
863 /* nothing to draw? */
864 if ((width
<= 0) || (height
<= 0) || (x
>= current_vp
->width
) ||
865 (y
>= current_vp
->height
) || (x
+ width
<= 0) || (y
+ height
<= 0))
881 if (x
+ width
> current_vp
->width
)
882 width
= current_vp
->width
- x
;
883 if (y
+ height
> current_vp
->height
)
884 height
= current_vp
->height
- y
;
886 src
+= stride
* src_y
+ src_x
; /* move starting point */
887 dst
= LCDADDR(current_vp
->x
+ x
, current_vp
->y
+ y
);
888 dst_end
= dst
+ height
* LCD_WIDTH
;
893 for(i
= 0;i
< width
;i
++)
895 if (src
[i
] == REPLACEWITHFG_COLOR
)
896 dst
[i
] = current_vp
->fg_pattern
;
897 else if(src
[i
] != TRANSPARENT_COLOR
)
903 while (dst
< dst_end
);
905 #endif /* !defined(TOSHIBA_GIGABEAT_F) || defined(SIMULATOR) */
907 /* Draw a full native bitmap with a transparent color */
908 void lcd_bitmap_transparent(const fb_data
*src
, int x
, int y
,
909 int width
, int height
)
911 lcd_bitmap_transparent_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(current_vp
->font
);
921 ucs
= bidi_l2v(str
, 1);
923 while ((ch
= *ucs
++) != 0 && x
< current_vp
->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
, pf
->height
);
946 /* put a string at a given pixel position */
947 void lcd_putsxy(int x
, int y
, const unsigned char *str
)
949 lcd_putsxyofs(x
, y
, 0, str
);
952 /*** line oriented text output ***/
954 /* put a string at a given char position */
955 void lcd_puts(int x
, int y
, const unsigned char *str
)
957 lcd_puts_style_offset(x
, y
, str
, STYLE_DEFAULT
, 0);
960 void lcd_puts_style(int x
, int y
, const unsigned char *str
, int style
)
962 lcd_puts_style_offset(x
, y
, str
, style
, 0);
965 void lcd_puts_offset(int x
, int y
, const unsigned char *str
, int offset
)
967 lcd_puts_style_offset(x
, y
, str
, STYLE_DEFAULT
, offset
);
970 /* put a string at a given char position, style, and pixel position,
971 * skipping first offset pixel columns */
972 void lcd_puts_style_offset(int x
, int y
, const unsigned char *str
, int style
,
975 int xpos
,ypos
,w
,h
,xrect
;
976 int lastmode
= current_vp
->drawmode
;
977 int oldfgcolor
= current_vp
->fg_pattern
;
978 int oldbgcolor
= current_vp
->bg_pattern
;
980 /* make sure scrolling is turned off on the line we are updating */
981 lcd_scroll_stop_line(current_vp
, y
);
986 lcd_getstringsize(str
, &w
, &h
);
987 xpos
= current_vp
->xmargin
+ x
*w
/ utf8length(str
);
988 ypos
= current_vp
->ymargin
+ y
*h
;
989 current_vp
->drawmode
= (style
& STYLE_INVERT
) ?
990 (DRMODE_SOLID
|DRMODE_INVERSEVID
) : DRMODE_SOLID
;
991 if (style
& STYLE_COLORED
) {
992 if (current_vp
->drawmode
== DRMODE_SOLID
)
993 current_vp
->fg_pattern
= style
& STYLE_COLOR_MASK
;
995 current_vp
->bg_pattern
= style
& STYLE_COLOR_MASK
;
997 current_vp
->drawmode
^= DRMODE_INVERSEVID
;
998 xrect
= xpos
+ MAX(w
- offset
, 0);
1000 if (style
& STYLE_GRADIENT
) {
1001 current_vp
->drawmode
= DRMODE_FG
;
1002 if (CURLN_UNPACK(style
) == 0)
1003 lcd_gradient_rect(xpos
, current_vp
->width
, ypos
, h
*NUMLN_UNPACK(style
));
1004 current_vp
->fg_pattern
= current_vp
->lst_pattern
;
1006 else if (style
& STYLE_COLORBAR
) {
1007 current_vp
->drawmode
= DRMODE_FG
;
1008 current_vp
->fg_pattern
= current_vp
->lss_pattern
;
1009 lcd_fillrect(xpos
, ypos
, current_vp
->width
- xpos
, h
);
1010 current_vp
->fg_pattern
= current_vp
->lst_pattern
;
1013 lcd_fillrect(xrect
, ypos
, current_vp
->width
- xrect
, h
);
1014 current_vp
->drawmode
= (style
& STYLE_INVERT
) ?
1015 (DRMODE_SOLID
|DRMODE_INVERSEVID
) : DRMODE_SOLID
;
1017 lcd_putsxyofs(xpos
, ypos
, offset
, str
);
1018 current_vp
->drawmode
= lastmode
;
1019 current_vp
->fg_pattern
= oldfgcolor
;
1020 current_vp
->bg_pattern
= oldbgcolor
;
1024 void lcd_puts_scroll(int x
, int y
, const unsigned char *string
)
1026 lcd_puts_scroll_style(x
, y
, string
, STYLE_DEFAULT
);
1029 void lcd_puts_scroll_style(int x
, int y
, const unsigned char *string
, int style
)
1031 lcd_puts_scroll_style_offset(x
, y
, string
, style
, 0);
1034 void lcd_puts_scroll_offset(int x
, int y
, const unsigned char *string
, int offset
)
1036 lcd_puts_scroll_style_offset(x
, y
, string
, STYLE_DEFAULT
, offset
);
1039 /* Initialise a scrolling line at (x,y) in current viewport */
1041 void lcd_puts_scroll_style_offset(int x
, int y
, const unsigned char *string
,
1042 int style
, int offset
)
1044 struct scrollinfo
* s
;
1047 if ((unsigned)y
>= (unsigned)current_vp
->height
)
1050 /* remove any previously scrolling line at the same location */
1051 lcd_scroll_stop_line(current_vp
, y
);
1053 if (lcd_scroll_info
.lines
>= LCD_SCROLLABLE_LINES
) return;
1055 s
= &lcd_scroll_info
.scroll
[lcd_scroll_info
.lines
];
1057 s
->start_tick
= current_tick
+ lcd_scroll_info
.delay
;
1059 lcd_puts_style_offset(x
,y
,string
,style
,offset
);
1061 lcd_getstringsize(string
, &w
, &h
);
1063 if (current_vp
->width
- x
* 8 - current_vp
->xmargin
< w
) {
1064 /* prepare scroll line */
1067 memset(s
->line
, 0, sizeof s
->line
);
1068 strcpy(s
->line
, string
);
1071 s
->width
= lcd_getstringsize(s
->line
, &w
, &h
);
1073 /* scroll bidirectional or forward only depending on the string
1075 if ( lcd_scroll_info
.bidir_limit
) {
1076 s
->bidir
= s
->width
< (current_vp
->width
- current_vp
->xmargin
) *
1077 (100 + lcd_scroll_info
.bidir_limit
) / 100;
1082 if (!s
->bidir
) { /* add spaces if scrolling in the round */
1083 strcat(s
->line
, " ");
1084 /* get new width incl. spaces */
1085 s
->width
= lcd_getstringsize(s
->line
, &w
, &h
);
1088 end
= strchr(s
->line
, '\0');
1089 strncpy(end
, string
, current_vp
->width
/2);
1093 s
->len
= utf8length(string
);
1095 s
->startx
= current_vp
->xmargin
+ x
* s
->width
/ s
->len
;
1096 s
->backward
= false;
1097 lcd_scroll_info
.lines
++;
1101 void lcd_scroll_fn(void)
1104 struct scrollinfo
* s
;
1108 unsigned old_fgcolor
;
1109 unsigned old_bgcolor
;
1110 struct viewport
* old_vp
= current_vp
;
1112 for ( index
= 0; index
< lcd_scroll_info
.lines
; index
++ ) {
1113 s
= &lcd_scroll_info
.scroll
[index
];
1116 if (TIME_BEFORE(current_tick
, s
->start_tick
))
1119 lcd_set_viewport(s
->vp
);
1120 old_fgcolor
= current_vp
->fg_pattern
;
1121 old_bgcolor
= current_vp
->bg_pattern
;
1123 if (s
->style
&STYLE_COLORED
) {
1124 if (s
->style
&STYLE_MODE_MASK
) {
1125 current_vp
->fg_pattern
= old_fgcolor
;
1126 current_vp
->bg_pattern
= s
->style
&STYLE_COLOR_MASK
;
1129 current_vp
->fg_pattern
= s
->style
&STYLE_COLOR_MASK
;
1130 current_vp
->bg_pattern
= old_bgcolor
;
1135 s
->offset
-= lcd_scroll_info
.step
;
1137 s
->offset
+= lcd_scroll_info
.step
;
1139 pf
= font_get(current_vp
->font
);
1141 ypos
= current_vp
->ymargin
+ s
->y
* pf
->height
;
1143 if (s
->bidir
) { /* scroll bidirectional */
1144 if (s
->offset
<= 0) {
1145 /* at beginning of line */
1147 s
->backward
= false;
1148 s
->start_tick
= current_tick
+ lcd_scroll_info
.delay
* 2;
1150 if (s
->offset
>= s
->width
- (current_vp
->width
- xpos
)) {
1151 /* at end of line */
1152 s
->offset
= s
->width
- (current_vp
->width
- xpos
);
1154 s
->start_tick
= current_tick
+ lcd_scroll_info
.delay
* 2;
1158 /* scroll forward the whole time */
1159 if (s
->offset
>= s
->width
)
1160 s
->offset
%= s
->width
;
1163 lastmode
= current_vp
->drawmode
;
1164 switch (s
->style
&STYLE_MODE_MASK
) {
1166 current_vp
->drawmode
= DRMODE_SOLID
|DRMODE_INVERSEVID
;
1168 case STYLE_COLORBAR
:
1169 /* Solid colour line selector */
1170 current_vp
->drawmode
= DRMODE_FG
;
1171 current_vp
->fg_pattern
= current_vp
->lss_pattern
;
1172 lcd_fillrect(xpos
, ypos
, current_vp
->width
- xpos
, pf
->height
);
1173 current_vp
->fg_pattern
= current_vp
->lst_pattern
;
1175 case STYLE_GRADIENT
:
1176 /* Gradient line selector */
1177 current_vp
->drawmode
= DRMODE_FG
;
1178 lcd_gradient_rect_scroll(xpos
, current_vp
->width
, ypos
, (signed)pf
->height
,
1179 NUMLN_UNPACK(s
->style
),
1180 CURLN_UNPACK(s
->style
));
1181 current_vp
->fg_pattern
= current_vp
->lst_pattern
;
1184 current_vp
->drawmode
= DRMODE_SOLID
;
1187 lcd_putsxyofs(xpos
, ypos
, s
->offset
, s
->line
);
1188 current_vp
->drawmode
= lastmode
;
1189 current_vp
->fg_pattern
= old_fgcolor
;
1190 current_vp
->bg_pattern
= old_bgcolor
;
1191 lcd_update_viewport_rect(xpos
, ypos
, current_vp
->width
- xpos
, pf
->height
);
1194 lcd_set_viewport(old_vp
);