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 ****************************************************************************/
32 #include "diacritic.h"
34 #ifndef LCDFN /* Not compiling for remote - define macros for main LCD. */
35 #define LCDFN(fn) lcd_ ## fn
36 #define FBFN(fn) fb_ ## fn
37 #define LCDM(ma) LCD_ ## ma
38 #define LCDNAME "lcd_"
42 #if defined(MAIN_LCD) && defined(HAVE_LCD_COLOR)
43 /* Fill a rectangle with a gradient */
44 static void lcd_gradient_rect(int x1
, int x2
, int y
, unsigned h
,
45 int num_lines
, int cur_line
)
47 int old_pattern
= current_vp
->fg_pattern
;
53 step_mul
= (1 << 16) / (num_lines
);
54 int h_r
= RGB_UNPACK_RED(current_vp
->lss_pattern
);
55 int h_g
= RGB_UNPACK_GREEN(current_vp
->lss_pattern
);
56 int h_b
= RGB_UNPACK_BLUE(current_vp
->lss_pattern
);
57 int rstep
= (h_r
- RGB_UNPACK_RED(current_vp
->lse_pattern
)) * step_mul
;
58 int gstep
= (h_g
- RGB_UNPACK_GREEN(current_vp
->lse_pattern
)) * step_mul
;
59 int bstep
= (h_b
- RGB_UNPACK_BLUE(current_vp
->lse_pattern
)) * step_mul
;
60 h_r
= (h_r
<< 16) + (1 << 15);
61 h_g
= (h_g
<< 16) + (1 << 15);
62 h_b
= (h_b
<< 16) + (1 << 15);
65 h_r
-= cur_line
* rstep
;
66 h_g
-= cur_line
* gstep
;
67 h_b
-= cur_line
* bstep
;
71 for(count
= 0; count
< h
; count
++) {
72 current_vp
->fg_pattern
= LCD_RGBPACK(h_r
>> 16, h_g
>> 16, h_b
>> 16);
73 lcd_hline(x1
, x2
, y
+ count
);
79 current_vp
->fg_pattern
= old_pattern
;
83 struct lcd_bitmap_char
88 unsigned char base_width
;
91 /* put a string at a given pixel position, skipping first ofs pixel columns */
92 static void LCDFN(putsxyofs
)(int x
, int y
, int ofs
, const unsigned char *str
)
95 struct font
* pf
= font_get(current_vp
->font
);
96 int vp_flags
= current_vp
->flags
;
98 static struct lcd_bitmap_char chars
[SCROLL_LINE_SIZE
];
100 if ((vp_flags
& VP_FLAG_ALIGNMENT_MASK
) != 0)
104 LCDFN(getstringsize
)(str
, &w
, NULL
);
105 /* center takes precedence */
106 if (vp_flags
& VP_FLAG_ALIGN_CENTER
)
108 x
= ((current_vp
->width
- w
)/ 2) + x
;
114 x
= current_vp
->width
- w
- x
;
120 ucs
= bidi_l2v(str
, 1);
121 /* Mark diacritic and rtl flags for each character */
122 for (i
= 0; i
< SCROLL_LINE_SIZE
&& ucs
[i
]; i
++)
125 chars
[i
].is_diacritic
= is_diacritic(ucs
[i
], &is_rtl
);
126 chars
[i
].is_rtl
=is_rtl
;
130 /* Get proportional width and glyph bits */
131 for (i
= 0; i
< len
; i
++)
132 chars
[i
].width
= font_get_width(pf
, ucs
[i
]);
134 /* Calculate base width for each character */
135 for (i
= 0; i
< len
; i
++)
139 /* Forward-seek the next non-diacritic character for base width */
140 if (chars
[i
].is_diacritic
)
144 /* Jump to next non-diacritic character, and calc its width */
145 for (j
= i
; j
< len
&& chars
[j
].is_diacritic
; j
++);
147 /* Set all related diacritic char's base-width accordingly */
149 chars
[i
].base_width
= chars
[j
].width
;
153 chars
[i
].base_width
= chars
[i
].width
;
158 static int last_non_diacritic_width
= 0;
160 if (!chars
[i
].is_diacritic
)
161 last_non_diacritic_width
= chars
[i
].width
;
163 chars
[i
].base_width
= last_non_diacritic_width
;
167 for (i
= 0; i
< len
; i
++)
169 const unsigned char *bits
;
170 unsigned short ch
= ucs
[i
];
171 int width
= chars
[i
].width
;
172 int drawmode
= 0, base_ofs
= 0;
173 bool next_is_diacritic
;
175 if (x
>= current_vp
->width
)
184 if (chars
[i
].is_diacritic
)
186 drawmode
= current_vp
->drawmode
;
187 current_vp
->drawmode
= DRMODE_FG
;
189 base_ofs
= (chars
[i
].base_width
- width
) / 2;
192 bits
= font_get_bits(pf
, ch
);
193 LCDFN(mono_bitmap_part
)(bits
, ofs
, 0, width
,
194 x
+ base_ofs
, y
, width
- ofs
, pf
->height
);
196 if (chars
[i
].is_diacritic
)
198 current_vp
->drawmode
= drawmode
;
201 /* Increment if next char is not diacritic (non-rtl),
202 * or current char is non-diacritic and next char is diacritic (rtl)*/
203 next_is_diacritic
= (ucs
[i
+ 1] && chars
[i
+ 1].is_diacritic
);
206 ((chars
[i
].is_rtl
&& !chars
[i
].is_diacritic
) ||
207 (!chars
[i
].is_rtl
&& (chars
[i
+ 1].is_rtl
|| !chars
[i
+ 1].is_diacritic
))))
209 x
+= chars
[i
].base_width
- ofs
;
214 /* put a string at a given pixel position */
215 void LCDFN(putsxy
)(int x
, int y
, const unsigned char *str
)
217 LCDFN(putsxyofs
)(x
, y
, 0, str
);
220 static void LCDFN(putsxyofs_style
)(int xpos
, int ypos
,
221 const unsigned char *str
, int style
,
222 int w
, int h
, int offset
)
224 int lastmode
= current_vp
->drawmode
;
225 int xrect
= xpos
+ MAX(w
- offset
, 0);
226 int x
= VP_IS_RTL(current_vp
) ? xpos
: xrect
;
227 #if defined(MAIN_LCD) && defined(HAVE_LCD_COLOR)
228 int oldfgcolor
= current_vp
->fg_pattern
;
229 int oldbgcolor
= current_vp
->bg_pattern
;
230 current_vp
->drawmode
= DRMODE_SOLID
| ((style
& STYLE_INVERT
) ?
231 DRMODE_INVERSEVID
: 0);
232 if (style
& STYLE_COLORED
) {
233 if (current_vp
->drawmode
== DRMODE_SOLID
)
234 current_vp
->fg_pattern
= style
& STYLE_COLOR_MASK
;
236 current_vp
->bg_pattern
= style
& STYLE_COLOR_MASK
;
238 current_vp
->drawmode
^= DRMODE_INVERSEVID
;
239 if (style
& STYLE_GRADIENT
) {
240 current_vp
->drawmode
= DRMODE_FG
;
241 lcd_gradient_rect(xpos
, current_vp
->width
, ypos
, h
,
242 NUMLN_UNPACK(style
), CURLN_UNPACK(style
));
243 current_vp
->fg_pattern
= current_vp
->lst_pattern
;
245 else if (style
& STYLE_COLORBAR
) {
246 current_vp
->drawmode
= DRMODE_FG
;
247 current_vp
->fg_pattern
= current_vp
->lss_pattern
;
248 lcd_fillrect(xpos
, ypos
, current_vp
->width
- xpos
, h
);
249 current_vp
->fg_pattern
= current_vp
->lst_pattern
;
252 lcd_fillrect(x
, ypos
, current_vp
->width
- xrect
, h
);
253 current_vp
->drawmode
= (style
& STYLE_INVERT
) ?
254 (DRMODE_SOLID
|DRMODE_INVERSEVID
) : DRMODE_SOLID
;
256 lcd_putsxyofs(xpos
, ypos
, offset
, str
);
257 current_vp
->fg_pattern
= oldfgcolor
;
258 current_vp
->bg_pattern
= oldbgcolor
;
260 current_vp
->drawmode
= DRMODE_SOLID
| ((style
& STYLE_INVERT
) ?
261 0 : DRMODE_INVERSEVID
);
262 LCDFN(fillrect
)(x
, ypos
, current_vp
->width
- xrect
, h
);
263 current_vp
->drawmode
^= DRMODE_INVERSEVID
;
264 LCDFN(putsxyofs
)(xpos
, ypos
, offset
, str
);
266 current_vp
->drawmode
= lastmode
;
269 /*** Line oriented text output ***/
271 /* put a string at a given char position */
272 void LCDFN(puts_style_offset
)(int x
, int y
, const unsigned char *str
,
273 int style
, int offset
)
275 int xpos
, ypos
, w
, h
;
276 LCDFN(scroll_stop_line
)(current_vp
, y
);
280 LCDFN(getstringsize
)(str
, &w
, &h
);
281 xpos
= x
* LCDFN(getstringsize
)(" ", NULL
, NULL
);
283 LCDFN(putsxyofs_style
)(xpos
, ypos
, str
, style
, w
, h
, offset
);
286 void LCDFN(puts
)(int x
, int y
, const unsigned char *str
)
288 LCDFN(puts_style_offset
)(x
, y
, str
, STYLE_DEFAULT
, 0);
291 /* Formatting version of LCDFN(puts) */
292 void LCDFN(putsf
)(int x
, int y
, const unsigned char *fmt
, ...)
297 vsnprintf(buf
, sizeof (buf
), fmt
, ap
);
299 LCDFN(puts
)(x
, y
, buf
);
302 void LCDFN(puts_style
)(int x
, int y
, const unsigned char *str
, int style
)
304 LCDFN(puts_style_offset
)(x
, y
, str
, style
, 0);
307 void LCDFN(puts_offset
)(int x
, int y
, const unsigned char *str
, int offset
)
309 LCDFN(puts_style_offset
)(x
, y
, str
, STYLE_DEFAULT
, offset
);
314 void LCDFN(puts_scroll_style_offset
)(int x
, int y
, const unsigned char *string
,
315 int style
, int offset
)
317 struct scrollinfo
* s
;
321 if ((unsigned)y
>= (unsigned)current_vp
->height
)
324 /* remove any previously scrolling line at the same location */
325 lcd_scroll_stop_line(current_vp
, y
);
327 if (LCDFN(scroll_info
).lines
>= LCDM(SCROLLABLE_LINES
)) return;
330 LCDFN(puts_style_offset
)(x
, y
, string
, style
, offset
);
332 LCDFN(getstringsize
)(string
, &w
, &h
);
334 if (current_vp
->width
- x
* 8 >= w
)
337 /* prepare scroll line */
338 s
= &LCDFN(scroll_info
).scroll
[LCDFN(scroll_info
).lines
];
339 s
->start_tick
= current_tick
+ LCDFN(scroll_info
).delay
;
342 strlcpy(s
->line
, string
, sizeof s
->line
);
345 s
->width
= LCDFN(getstringsize
)(s
->line
, &w
, &h
);
347 /* scroll bidirectional or forward only depending on the string
349 if ( LCDFN(scroll_info
).bidir_limit
) {
350 s
->bidir
= s
->width
< (current_vp
->width
) *
351 (100 + LCDFN(scroll_info
).bidir_limit
) / 100;
356 if (!s
->bidir
) { /* add spaces if scrolling in the round */
357 strcat(s
->line
, " ");
358 /* get new width incl. spaces */
359 s
->width
= LCDFN(getstringsize
)(s
->line
, &w
, &h
);
362 end
= strchr(s
->line
, '\0');
363 strlcpy(end
, string
, current_vp
->width
/2);
367 s
->len
= utf8length(string
);
369 s
->startx
= x
* LCDFN(getstringsize
)(" ", NULL
, NULL
);
372 LCDFN(scroll_info
).lines
++;
375 void LCDFN(puts_scroll
)(int x
, int y
, const unsigned char *string
)
377 LCDFN(puts_scroll_style
)(x
, y
, string
, STYLE_DEFAULT
);
380 void LCDFN(puts_scroll_style
)(int x
, int y
, const unsigned char *string
,
383 LCDFN(puts_scroll_style_offset
)(x
, y
, string
, style
, 0);
386 void LCDFN(puts_scroll_offset
)(int x
, int y
, const unsigned char *string
,
389 LCDFN(puts_scroll_style_offset
)(x
, y
, string
, STYLE_DEFAULT
, offset
);
392 void LCDFN(scroll_fn
)(void)
395 struct scrollinfo
* s
;
398 struct viewport
* old_vp
= current_vp
;
400 for ( index
= 0; index
< LCDFN(scroll_info
).lines
; index
++ ) {
401 s
= &LCDFN(scroll_info
).scroll
[index
];
404 if (TIME_BEFORE(current_tick
, s
->start_tick
))
407 LCDFN(set_viewport
)(s
->vp
);
410 s
->offset
-= LCDFN(scroll_info
).step
;
412 s
->offset
+= LCDFN(scroll_info
).step
;
414 pf
= font_get(current_vp
->font
);
416 ypos
= s
->y
* pf
->height
;
418 if (s
->bidir
) { /* scroll bidirectional */
419 if (s
->offset
<= 0) {
420 /* at beginning of line */
423 s
->start_tick
= current_tick
+ LCDFN(scroll_info
).delay
* 2;
425 if (s
->offset
>= s
->width
- (current_vp
->width
- xpos
)) {
427 s
->offset
= s
->width
- (current_vp
->width
- xpos
);
429 s
->start_tick
= current_tick
+ LCDFN(scroll_info
).delay
* 2;
433 /* scroll forward the whole time */
434 if (s
->offset
>= s
->width
)
435 s
->offset
%= s
->width
;
437 LCDFN(putsxyofs_style
)(xpos
, ypos
, s
->line
, s
->style
, s
->width
,
438 pf
->height
, s
->offset
);
439 LCDFN(update_viewport_rect
)(xpos
, ypos
, current_vp
->width
- xpos
,
442 LCDFN(set_viewport
)(old_vp
);