diff options
Diffstat (limited to 'firmware/drivers/lcd-bitmap-common.c')
-rw-r--r-- | firmware/drivers/lcd-bitmap-common.c | 329 |
1 files changed, 329 insertions, 0 deletions
diff --git a/firmware/drivers/lcd-bitmap-common.c b/firmware/drivers/lcd-bitmap-common.c new file mode 100644 index 0000000000..c1efd9097e --- /dev/null +++ b/firmware/drivers/lcd-bitmap-common.c | |||
@@ -0,0 +1,329 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2005 Dave Chapman | ||
11 | * Text rendering | ||
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 | ||
18 | * | ||
19 | * Rockbox common bitmap LCD functions | ||
20 | * | ||
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. | ||
25 | * | ||
26 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
27 | * KIND, either express or implied. | ||
28 | * | ||
29 | ****************************************************************************/ | ||
30 | |||
31 | #ifndef LCDFN /* Not compiling for remote - define macros for main LCD. */ | ||
32 | #define LCDFN(fn) lcd_ ## fn | ||
33 | #define FBFN(fn) fb_ ## fn | ||
34 | #define LCDM(ma) LCD_ ## ma | ||
35 | #define LCDNAME "lcd_" | ||
36 | #define MAIN_LCD | ||
37 | #endif | ||
38 | |||
39 | #if defined(MAIN_LCD) && defined(HAVE_LCD_COLOR) | ||
40 | /* Fill a rectangle with a gradient */ | ||
41 | static void lcd_gradient_rect(int x1, int x2, int y, unsigned h, | ||
42 | int num_lines, int cur_line) | ||
43 | { | ||
44 | int old_pattern = current_vp->fg_pattern; | ||
45 | int step_mul; | ||
46 | if (h == 0) return; | ||
47 | |||
48 | num_lines *= h; | ||
49 | cur_line *= h; | ||
50 | step_mul = (1 << 16) / (num_lines); | ||
51 | int h_r = RGB_UNPACK_RED(current_vp->lss_pattern); | ||
52 | int h_g = RGB_UNPACK_GREEN(current_vp->lss_pattern); | ||
53 | int h_b = RGB_UNPACK_BLUE(current_vp->lss_pattern); | ||
54 | int rstep = (h_r - RGB_UNPACK_RED(current_vp->lse_pattern)) * step_mul; | ||
55 | int gstep = (h_g - RGB_UNPACK_GREEN(current_vp->lse_pattern)) * step_mul; | ||
56 | int bstep = (h_b - RGB_UNPACK_BLUE(current_vp->lse_pattern)) * step_mul; | ||
57 | h_r = (h_r << 16) + (1 << 15); | ||
58 | h_g = (h_g << 16) + (1 << 15); | ||
59 | h_b = (h_b << 16) + (1 << 15); | ||
60 | if (cur_line) | ||
61 | { | ||
62 | h_r -= cur_line * rstep; | ||
63 | h_g -= cur_line * gstep; | ||
64 | h_b -= cur_line * bstep; | ||
65 | } | ||
66 | unsigned count; | ||
67 | |||
68 | for(count = 0; count < h; count++) { | ||
69 | current_vp->fg_pattern = LCD_RGBPACK(h_r >> 16, h_g >> 16, h_b >> 16); | ||
70 | lcd_hline(x1, x2, y + count); | ||
71 | h_r -= rstep; | ||
72 | h_g -= gstep; | ||
73 | h_b -= bstep; | ||
74 | } | ||
75 | |||
76 | current_vp->fg_pattern = old_pattern; | ||
77 | } | ||
78 | #endif | ||
79 | |||
80 | /* put a string at a given pixel position, skipping first ofs pixel columns */ | ||
81 | static void LCDFN(putsxyofs)(int x, int y, int ofs, const unsigned char *str) | ||
82 | { | ||
83 | unsigned short ch; | ||
84 | unsigned short *ucs; | ||
85 | struct font* pf = font_get(current_vp->font); | ||
86 | |||
87 | ucs = bidi_l2v(str, 1); | ||
88 | |||
89 | while ((ch = *ucs++) != 0 && x < current_vp->width) | ||
90 | { | ||
91 | int width; | ||
92 | const unsigned char *bits; | ||
93 | |||
94 | /* get proportional width and glyph bits */ | ||
95 | width = font_get_width(pf, ch); | ||
96 | |||
97 | if (ofs > width) | ||
98 | { | ||
99 | ofs -= width; | ||
100 | continue; | ||
101 | } | ||
102 | |||
103 | bits = font_get_bits(pf, ch); | ||
104 | |||
105 | LCDFN(mono_bitmap_part)(bits, ofs, 0, width, x, y, width - ofs, | ||
106 | pf->height); | ||
107 | |||
108 | x += width - ofs; | ||
109 | ofs = 0; | ||
110 | } | ||
111 | } | ||
112 | /* put a string at a given pixel position */ | ||
113 | void LCDFN(putsxy)(int x, int y, const unsigned char *str) | ||
114 | { | ||
115 | LCDFN(putsxyofs)(x, y, 0, str); | ||
116 | } | ||
117 | |||
118 | static void LCDFN(putsxyofs_style)(int xpos, int ypos, | ||
119 | const unsigned char *str, int style, | ||
120 | int w, int h, int offset) | ||
121 | { | ||
122 | int lastmode = current_vp->drawmode; | ||
123 | int xrect = xpos + MAX(w - offset, 0); | ||
124 | #if defined(MAIN_LCD) && defined(HAVE_LCD_COLOR) | ||
125 | int oldfgcolor = current_vp->fg_pattern; | ||
126 | int oldbgcolor = current_vp->bg_pattern; | ||
127 | current_vp->drawmode = DRMODE_SOLID | ((style & STYLE_INVERT) ? | ||
128 | DRMODE_INVERSEVID : 0); | ||
129 | if (style & STYLE_COLORED) { | ||
130 | if (current_vp->drawmode == DRMODE_SOLID) | ||
131 | current_vp->fg_pattern = style & STYLE_COLOR_MASK; | ||
132 | else | ||
133 | current_vp->bg_pattern = style & STYLE_COLOR_MASK; | ||
134 | } | ||
135 | current_vp->drawmode ^= DRMODE_INVERSEVID; | ||
136 | if (style & STYLE_GRADIENT) { | ||
137 | current_vp->drawmode = DRMODE_FG; | ||
138 | lcd_gradient_rect(xpos, current_vp->width, ypos, h, | ||
139 | NUMLN_UNPACK(style), CURLN_UNPACK(style)); | ||
140 | current_vp->fg_pattern = current_vp->lst_pattern; | ||
141 | } | ||
142 | else if (style & STYLE_COLORBAR) { | ||
143 | current_vp->drawmode = DRMODE_FG; | ||
144 | current_vp->fg_pattern = current_vp->lss_pattern; | ||
145 | lcd_fillrect(xpos, ypos, current_vp->width - xpos, h); | ||
146 | current_vp->fg_pattern = current_vp->lst_pattern; | ||
147 | } | ||
148 | else { | ||
149 | lcd_fillrect(xrect, ypos, current_vp->width - xrect, h); | ||
150 | current_vp->drawmode = (style & STYLE_INVERT) ? | ||
151 | (DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID; | ||
152 | } | ||
153 | lcd_putsxyofs(xpos, ypos, offset, str); | ||
154 | current_vp->fg_pattern = oldfgcolor; | ||
155 | current_vp->bg_pattern = oldbgcolor; | ||
156 | #else | ||
157 | current_vp->drawmode = DRMODE_SOLID | ((style & STYLE_INVERT) ? | ||
158 | 0 : DRMODE_INVERSEVID); | ||
159 | LCDFN(fillrect)(xrect, ypos, current_vp->width - xrect, h); | ||
160 | current_vp->drawmode ^= DRMODE_INVERSEVID; | ||
161 | LCDFN(putsxyofs)(xpos, ypos, offset, str); | ||
162 | #endif | ||
163 | current_vp->drawmode = lastmode; | ||
164 | } | ||
165 | |||
166 | /*** Line oriented text output ***/ | ||
167 | |||
168 | /* put a string at a given char position */ | ||
169 | void LCDFN(puts_style_offset)(int x, int y, const unsigned char *str, | ||
170 | int style, int offset) | ||
171 | { | ||
172 | int xpos, ypos, w, h; | ||
173 | LCDFN(scroll_stop_line)(current_vp, y); | ||
174 | if(!str || !str[0]) | ||
175 | return; | ||
176 | LCDFN(getstringsize)(str, &w, &h); | ||
177 | xpos = x * w / utf8length((char *)str); | ||
178 | ypos = y * h; | ||
179 | LCDFN(putsxyofs_style)(xpos, ypos, str, style, w, h, offset); | ||
180 | } | ||
181 | |||
182 | void LCDFN(puts)(int x, int y, const unsigned char *str) | ||
183 | { | ||
184 | LCDFN(puts_style_offset)(x, y, str, STYLE_DEFAULT, 0); | ||
185 | } | ||
186 | |||
187 | void LCDFN(puts_style)(int x, int y, const unsigned char *str, int style) | ||
188 | { | ||
189 | LCDFN(puts_style_offset)(x, y, str, style, 0); | ||
190 | } | ||
191 | |||
192 | void LCDFN(puts_offset)(int x, int y, const unsigned char *str, int offset) | ||
193 | { | ||
194 | LCDFN(puts_style_offset)(x, y, str, STYLE_DEFAULT, offset); | ||
195 | } | ||
196 | |||
197 | /*** scrolling ***/ | ||
198 | |||
199 | void LCDFN(puts_scroll_style_offset)(int x, int y, const unsigned char *string, | ||
200 | int style, int offset) | ||
201 | { | ||
202 | int w, h; | ||
203 | |||
204 | if ((unsigned)y >= (unsigned)current_vp->height) | ||
205 | return; | ||
206 | |||
207 | /* remove any previously scrolling line at the same location */ | ||
208 | lcd_scroll_stop_line(current_vp, y); | ||
209 | |||
210 | if (LCDFN(scroll_info.lines) >= LCDM(SCROLLABLE_LINES)) return; | ||
211 | if (!string) | ||
212 | return; | ||
213 | LCDFN(puts_style_offset)(x, y, string, style, offset); | ||
214 | |||
215 | LCDFN(getstringsize)(string, &w, &h); | ||
216 | |||
217 | if (current_vp->width - x * 8 < w) { | ||
218 | /* prepare scroll line */ | ||
219 | struct scrollinfo* s; | ||
220 | s = &LCDFN(scroll_info).scroll[LCDFN(scroll_info).lines]; | ||
221 | s->start_tick = current_tick + LCDFN(scroll_info).delay; | ||
222 | s->style = style; | ||
223 | |||
224 | char *end; | ||
225 | |||
226 | memset(s->line, 0, sizeof s->line); | ||
227 | strcpy(s->line, string); | ||
228 | |||
229 | /* get width */ | ||
230 | s->width = LCDFN(getstringsize)(s->line, &w, &h); | ||
231 | |||
232 | /* scroll bidirectional or forward only depending on the string | ||
233 | width */ | ||
234 | if ( LCDFN(scroll_info).bidir_limit ) { | ||
235 | s->bidir = s->width < (current_vp->width) * | ||
236 | (100 + LCDFN(scroll_info).bidir_limit) / 100; | ||
237 | } | ||
238 | else | ||
239 | s->bidir = false; | ||
240 | |||
241 | if (!s->bidir) { /* add spaces if scrolling in the round */ | ||
242 | strcat(s->line, " "); | ||
243 | /* get new width incl. spaces */ | ||
244 | s->width = LCDFN(getstringsize)(s->line, &w, &h); | ||
245 | } | ||
246 | |||
247 | end = strchr(s->line, '\0'); | ||
248 | strlcpy(end, string, current_vp->width/2); | ||
249 | |||
250 | s->vp = current_vp; | ||
251 | s->y = y; | ||
252 | s->len = utf8length(string); | ||
253 | s->offset = offset; | ||
254 | s->startx = x * s->width / s->len; | ||
255 | s->backward = false; | ||
256 | |||
257 | LCDFN(scroll_info).lines++; | ||
258 | } | ||
259 | } | ||
260 | |||
261 | void LCDFN(puts_scroll)(int x, int y, const unsigned char *string) | ||
262 | { | ||
263 | LCDFN(puts_scroll_style)(x, y, string, STYLE_DEFAULT); | ||
264 | } | ||
265 | |||
266 | void LCDFN(puts_scroll_style)(int x, int y, const unsigned char *string, | ||
267 | int style) | ||
268 | { | ||
269 | LCDFN(puts_scroll_style_offset)(x, y, string, style, 0); | ||
270 | } | ||
271 | |||
272 | void LCDFN(puts_scroll_offset)(int x, int y, const unsigned char *string, | ||
273 | int offset) | ||
274 | { | ||
275 | LCDFN(puts_scroll_style_offset)(x, y, string, STYLE_DEFAULT, offset); | ||
276 | } | ||
277 | |||
278 | void LCDFN(scroll_fn)(void) | ||
279 | { | ||
280 | struct font* pf; | ||
281 | struct scrollinfo* s; | ||
282 | int index; | ||
283 | int xpos, ypos; | ||
284 | struct viewport* old_vp = current_vp; | ||
285 | |||
286 | for ( index = 0; index < LCDFN(scroll_info).lines; index++ ) { | ||
287 | s = &LCDFN(scroll_info).scroll[index]; | ||
288 | |||
289 | /* check pause */ | ||
290 | if (TIME_BEFORE(current_tick, s->start_tick)) | ||
291 | continue; | ||
292 | |||
293 | LCDFN(set_viewport)(s->vp); | ||
294 | |||
295 | if (s->backward) | ||
296 | s->offset -= LCDFN(scroll_info).step; | ||
297 | else | ||
298 | s->offset += LCDFN(scroll_info).step; | ||
299 | |||
300 | pf = font_get(current_vp->font); | ||
301 | xpos = s->startx; | ||
302 | ypos = s->y * pf->height; | ||
303 | |||
304 | if (s->bidir) { /* scroll bidirectional */ | ||
305 | if (s->offset <= 0) { | ||
306 | /* at beginning of line */ | ||
307 | s->offset = 0; | ||
308 | s->backward = false; | ||
309 | s->start_tick = current_tick + LCDFN(scroll_info).delay * 2; | ||
310 | } | ||
311 | if (s->offset >= s->width - (current_vp->width - xpos)) { | ||
312 | /* at end of line */ | ||
313 | s->offset = s->width - (current_vp->width - xpos); | ||
314 | s->backward = true; | ||
315 | s->start_tick = current_tick + LCDFN(scroll_info).delay * 2; | ||
316 | } | ||
317 | } | ||
318 | else { | ||
319 | /* scroll forward the whole time */ | ||
320 | if (s->offset >= s->width) | ||
321 | s->offset %= s->width; | ||
322 | } | ||
323 | LCDFN(putsxyofs_style)(xpos, ypos, s->line, s->style, s->width, | ||
324 | pf->height, s->offset); | ||
325 | LCDFN(update_viewport_rect)(xpos, ypos, current_vp->width - xpos, | ||
326 | pf->height); | ||
327 | } | ||
328 | LCDFN(set_viewport)(old_vp); | ||
329 | } | ||