1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2005 Dave Chapman
12 * Copyright (C) 2006 Shachar Liberman
13 * Offset text, scrolling
14 * Copyright (C) 2007 Nicolas Pennequin, Tom Ross, Ken Fazzone, Akio Idehara
15 * Color gradient background
16 * Copyright (C) 2009 Andrew Mahone
17 * Merged common LCD bitmap code
19 * Rockbox common bitmap LCD functions
21 * This program is free software; you can redistribute it and/or
22 * modify it under the terms of the GNU General Public License
23 * as published by the Free Software Foundation; either version 2
24 * of the License, or (at your option) any later version.
26 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
27 * KIND, either express or implied.
29 ****************************************************************************/
30 #ifndef LCDFN /* Not compiling for remote - define macros for main LCD. */
31 #define LCDFN(fn) lcd_ ## fn
32 #define FBFN(fn) fb_ ## fn
33 #define LCDM(ma) LCD_ ## ma
34 #define LCDNAME "lcd_"
38 #if defined(MAIN_LCD) && defined(HAVE_LCD_COLOR)
39 /* Fill a rectangle with a gradient */
40 static void lcd_gradient_rect(int x1
, int x2
, int y
, unsigned h
,
41 int num_lines
, int cur_line
)
43 int old_pattern
= current_vp
->fg_pattern
;
49 step_mul
= (1 << 16) / (num_lines
);
50 int h_r
= RGB_UNPACK_RED(current_vp
->lss_pattern
);
51 int h_g
= RGB_UNPACK_GREEN(current_vp
->lss_pattern
);
52 int h_b
= RGB_UNPACK_BLUE(current_vp
->lss_pattern
);
53 int rstep
= (h_r
- RGB_UNPACK_RED(current_vp
->lse_pattern
)) * step_mul
;
54 int gstep
= (h_g
- RGB_UNPACK_GREEN(current_vp
->lse_pattern
)) * step_mul
;
55 int bstep
= (h_b
- RGB_UNPACK_BLUE(current_vp
->lse_pattern
)) * step_mul
;
56 h_r
= (h_r
<< 16) + (1 << 15);
57 h_g
= (h_g
<< 16) + (1 << 15);
58 h_b
= (h_b
<< 16) + (1 << 15);
61 h_r
-= cur_line
* rstep
;
62 h_g
-= cur_line
* gstep
;
63 h_b
-= cur_line
* bstep
;
67 for(count
= 0; count
< h
; count
++) {
68 current_vp
->fg_pattern
= LCD_RGBPACK(h_r
>> 16, h_g
>> 16, h_b
>> 16);
69 lcd_hline(x1
, x2
, y
+ count
);
75 current_vp
->fg_pattern
= old_pattern
;
79 /* put a string at a given pixel position, skipping first ofs pixel columns */
80 static void LCDFN(putsxyofs
)(int x
, int y
, int ofs
, const unsigned char *str
)
84 struct font
* pf
= font_get(current_vp
->font
);
86 ucs
= bidi_l2v(str
, 1);
88 if (VP_IS_RTL(current_vp
))
92 LCDFN(getstringsize
)(str
, &w
, NULL
);
93 x
= current_vp
->width
- w
- x
;
96 while ((ch
= *ucs
++) != 0 && x
< current_vp
->width
)
99 const unsigned char *bits
;
101 /* get proportional width and glyph bits */
102 width
= font_get_width(pf
, ch
);
110 bits
= font_get_bits(pf
, ch
);
112 LCDFN(mono_bitmap_part
)(bits
, ofs
, 0, width
, x
, y
, width
- ofs
,
119 /* put a string at a given pixel position */
120 void LCDFN(putsxy
)(int x
, int y
, const unsigned char *str
)
122 LCDFN(putsxyofs
)(x
, y
, 0, str
);
125 static void LCDFN(putsxyofs_style
)(int xpos
, int ypos
,
126 const unsigned char *str
, int style
,
127 int w
, int h
, int offset
)
129 int lastmode
= current_vp
->drawmode
;
130 int xrect
= xpos
+ MAX(w
- offset
, 0);
131 #if defined(MAIN_LCD) && defined(HAVE_LCD_COLOR)
132 int oldfgcolor
= current_vp
->fg_pattern
;
133 int oldbgcolor
= current_vp
->bg_pattern
;
134 current_vp
->drawmode
= DRMODE_SOLID
| ((style
& STYLE_INVERT
) ?
135 DRMODE_INVERSEVID
: 0);
136 if (style
& STYLE_COLORED
) {
137 if (current_vp
->drawmode
== DRMODE_SOLID
)
138 current_vp
->fg_pattern
= style
& STYLE_COLOR_MASK
;
140 current_vp
->bg_pattern
= style
& STYLE_COLOR_MASK
;
142 current_vp
->drawmode
^= DRMODE_INVERSEVID
;
143 if (style
& STYLE_GRADIENT
) {
144 current_vp
->drawmode
= DRMODE_FG
;
145 lcd_gradient_rect(xpos
, current_vp
->width
, ypos
, h
,
146 NUMLN_UNPACK(style
), CURLN_UNPACK(style
));
147 current_vp
->fg_pattern
= current_vp
->lst_pattern
;
149 else if (style
& STYLE_COLORBAR
) {
150 current_vp
->drawmode
= DRMODE_FG
;
151 current_vp
->fg_pattern
= current_vp
->lss_pattern
;
152 lcd_fillrect(xpos
, ypos
, current_vp
->width
- xpos
, h
);
153 current_vp
->fg_pattern
= current_vp
->lst_pattern
;
156 lcd_fillrect(xrect
, ypos
, current_vp
->width
- xrect
, h
);
157 current_vp
->drawmode
= (style
& STYLE_INVERT
) ?
158 (DRMODE_SOLID
|DRMODE_INVERSEVID
) : DRMODE_SOLID
;
160 lcd_putsxyofs(xpos
, ypos
, offset
, str
);
161 current_vp
->fg_pattern
= oldfgcolor
;
162 current_vp
->bg_pattern
= oldbgcolor
;
164 current_vp
->drawmode
= DRMODE_SOLID
| ((style
& STYLE_INVERT
) ?
165 0 : DRMODE_INVERSEVID
);
166 LCDFN(fillrect
)(xrect
, ypos
, current_vp
->width
- xrect
, h
);
167 current_vp
->drawmode
^= DRMODE_INVERSEVID
;
168 LCDFN(putsxyofs
)(xpos
, ypos
, offset
, str
);
170 current_vp
->drawmode
= lastmode
;
173 /*** Line oriented text output ***/
175 /* put a string at a given char position */
176 void LCDFN(puts_style_offset
)(int x
, int y
, const unsigned char *str
,
177 int style
, int offset
)
179 int xpos
, ypos
, w
, h
;
180 unsigned long chars_in_str
;
181 LCDFN(scroll_stop_line
)(current_vp
, y
);
185 chars_in_str
= utf8length((char *)str
);
186 LCDFN(getstringsize
)(str
, &w
, &h
);
187 xpos
= x
* w
/ chars_in_str
;
189 LCDFN(putsxyofs_style
)(xpos
, ypos
, str
, style
, w
, h
, offset
);
192 void LCDFN(puts
)(int x
, int y
, const unsigned char *str
)
194 LCDFN(puts_style_offset
)(x
, y
, str
, STYLE_DEFAULT
, 0);
197 void LCDFN(puts_style
)(int x
, int y
, const unsigned char *str
, int style
)
199 LCDFN(puts_style_offset
)(x
, y
, str
, style
, 0);
202 void LCDFN(puts_offset
)(int x
, int y
, const unsigned char *str
, int offset
)
204 LCDFN(puts_style_offset
)(x
, y
, str
, STYLE_DEFAULT
, offset
);
209 void LCDFN(puts_scroll_style_offset
)(int x
, int y
, const unsigned char *string
,
210 int style
, int offset
)
214 if ((unsigned)y
>= (unsigned)current_vp
->height
)
217 /* remove any previously scrolling line at the same location */
218 lcd_scroll_stop_line(current_vp
, y
);
220 if (LCDFN(scroll_info
.lines
) >= LCDM(SCROLLABLE_LINES
)) return;
223 LCDFN(puts_style_offset
)(x
, y
, string
, style
, offset
);
225 LCDFN(getstringsize
)(string
, &w
, &h
);
227 if (current_vp
->width
- x
* 8 < w
) {
228 /* prepare scroll line */
229 struct scrollinfo
* s
;
230 s
= &LCDFN(scroll_info
).scroll
[LCDFN(scroll_info
).lines
];
231 s
->start_tick
= current_tick
+ LCDFN(scroll_info
).delay
;
236 memset(s
->line
, 0, sizeof s
->line
);
237 strcpy(s
->line
, string
);
240 s
->width
= LCDFN(getstringsize
)(s
->line
, &w
, &h
);
242 /* scroll bidirectional or forward only depending on the string
244 if ( LCDFN(scroll_info
).bidir_limit
) {
245 s
->bidir
= s
->width
< (current_vp
->width
) *
246 (100 + LCDFN(scroll_info
).bidir_limit
) / 100;
251 if (!s
->bidir
) { /* add spaces if scrolling in the round */
252 strcat(s
->line
, " ");
253 /* get new width incl. spaces */
254 s
->width
= LCDFN(getstringsize
)(s
->line
, &w
, &h
);
257 end
= strchr(s
->line
, '\0');
258 strlcpy(end
, string
, current_vp
->width
/2);
262 s
->len
= utf8length(string
);
264 s
->startx
= x
* s
->width
/ s
->len
;
267 LCDFN(scroll_info
).lines
++;
271 void LCDFN(puts_scroll
)(int x
, int y
, const unsigned char *string
)
273 LCDFN(puts_scroll_style
)(x
, y
, string
, STYLE_DEFAULT
);
276 void LCDFN(puts_scroll_style
)(int x
, int y
, const unsigned char *string
,
279 LCDFN(puts_scroll_style_offset
)(x
, y
, string
, style
, 0);
282 void LCDFN(puts_scroll_offset
)(int x
, int y
, const unsigned char *string
,
285 LCDFN(puts_scroll_style_offset
)(x
, y
, string
, STYLE_DEFAULT
, offset
);
288 void LCDFN(scroll_fn
)(void)
291 struct scrollinfo
* s
;
294 struct viewport
* old_vp
= current_vp
;
296 for ( index
= 0; index
< LCDFN(scroll_info
).lines
; index
++ ) {
297 s
= &LCDFN(scroll_info
).scroll
[index
];
300 if (TIME_BEFORE(current_tick
, s
->start_tick
))
303 LCDFN(set_viewport
)(s
->vp
);
305 if (s
->backward
^ VP_IS_RTL(current_vp
))
306 /* contrary to LTR, this is "forward" in RTL */
307 s
->offset
-= LCDFN(scroll_info
).step
;
309 s
->offset
+= LCDFN(scroll_info
).step
;
311 pf
= font_get(current_vp
->font
);
313 ypos
= s
->y
* pf
->height
;
315 if (s
->bidir
) { /* scroll bidirectional */
316 if (abs(s
->offset
) <= 0) {
317 /* at beginning of line */
320 s
->start_tick
= current_tick
+ LCDFN(scroll_info
).delay
* 2;
322 if (abs(s
->offset
) >= s
->width
- (current_vp
->width
- xpos
)) {
325 s
->start_tick
= current_tick
+ LCDFN(scroll_info
).delay
* 2;
329 /* scroll forward the whole time */
330 if (abs(s
->offset
) >= s
->width
)
331 s
->offset
%= s
->width
;
333 LCDFN(putsxyofs_style
)(xpos
, ypos
, s
->line
, s
->style
, s
->width
,
334 pf
->height
, s
->offset
);
335 LCDFN(update_viewport_rect
)(xpos
, ypos
, current_vp
->width
- xpos
,
338 LCDFN(set_viewport
)(old_vp
);