summaryrefslogtreecommitdiff
path: root/apps
diff options
context:
space:
mode:
authorThomas Martitz <kugel@rockbox.org>2013-12-20 23:34:28 +0100
committerThomas Martitz <kugel@rockbox.org>2014-01-07 14:13:17 +0100
commit5d6974641b14ef81396e8deebcc65a87c07334e5 (patch)
treea3c12feecc5ae2007d71be2fb383ea7047c87f11 /apps
parent5752d029fd80e87fe522d7d5e952a56dc371d65e (diff)
downloadrockbox-5d6974641b14ef81396e8deebcc65a87c07334e5.tar.gz
rockbox-5d6974641b14ef81396e8deebcc65a87c07334e5.zip
Introduce put_line().
This function is a fully-fletched, high-level pixel-based line printer, that combines functionality of several firmware and list functions. It can draw spacing, icons and text in a single call, in any order and each multiple times. It can also apply line decorations at the same time. It features printf-like semantics by accepting a format string that contain format tags as well as inline text. It's accessible directly, but also through the multi-screen api for plugins. Change-Id: I70f5a77bbf4b0252521f2e47ead377b9d6d29b54
Diffstat (limited to 'apps')
-rw-r--r--apps/SOURCES1
-rw-r--r--apps/gui/line.c349
-rw-r--r--apps/gui/line.h117
-rw-r--r--apps/plugin.h1
-rw-r--r--apps/screen_access.c20
-rw-r--r--apps/screen_access.h2
6 files changed, 490 insertions, 0 deletions
diff --git a/apps/SOURCES b/apps/SOURCES
index b6bb82fa31..918ee1e4fc 100644
--- a/apps/SOURCES
+++ b/apps/SOURCES
@@ -77,6 +77,7 @@ gui/buttonbar.c
77gui/icon.c 77gui/icon.c
78#endif 78#endif
79gui/list.c 79gui/list.c
80gui/line.c
80#ifdef HAVE_LCD_BITMAP 81#ifdef HAVE_LCD_BITMAP
81gui/bitmap/list.c 82gui/bitmap/list.c
82gui/bitmap/list-skinned.c 83gui/bitmap/list-skinned.c
diff --git a/apps/gui/line.c b/apps/gui/line.c
new file mode 100644
index 0000000000..9374279b60
--- /dev/null
+++ b/apps/gui/line.c
@@ -0,0 +1,349 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2013 Thomas Martitz
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#include <ctype.h>
23#include <stdarg.h>
24#include <stdio.h>
25
26#include "scroll_engine.h"
27#include "system.h"
28#include "line.h"
29#include "gcc_extensions.h"
30#include "icon.h"
31#include "screens.h"
32#include "settings.h"
33#include "debug.h"
34
35#ifdef HAVE_REMOTE_LCD
36#define MAX_LINES (LCD_SCROLLABLE_LINES + LCD_REMOTE_SCROLLABLE_LINES)
37#else
38#define MAX_LINES LCD_SCROLLABLE_LINES
39#endif
40
41
42#ifdef HAVE_LCD_CHARCELLS
43#define style_line(d, x, y, l)
44#else
45static void style_line(struct screen *display, int x, int y, struct line_desc *line);
46#endif
47
48static void put_text(struct screen *display, int x, int y, struct line_desc *line,
49 const char *text, bool prevent_scroll, int text_skip_pixels);
50
51
52static struct line_desc *get_line_desc(void)
53{
54 static struct line_desc lines[MAX_LINES];
55 static unsigned line_index;
56 struct line_desc *ret;
57
58 ret = &lines[line_index++];
59 if (line_index >= ARRAYLEN(lines))
60 line_index = 0;
61
62 return ret;
63}
64
65static void scroller(struct scrollinfo *s, struct screen *display)
66{
67 /* style_line() expects the entire line rect, including padding, to
68 * draw selector properly across the text+padding. however struct scrollinfo
69 * has only the rect for the text itself, which is off depending on the
70 * line padding. this needs to be corrected for calling style_line().
71 * The alternative would be to really redraw only the text area,
72 * but that would complicate the code a lot */
73 struct line_desc *line = s->userdata;
74 style_line(display, s->x, s->y - (line->height/2 - display->getcharheight()/2), line);
75 put_text(display, s->x, s->y, line, s->line, true, s->offset);
76}
77
78static void scroller_main(struct scrollinfo *s)
79{
80 scroller(s, &screens[SCREEN_MAIN]);
81}
82
83#ifdef HAVE_REMOTE_LCD
84static void scroller_remote(struct scrollinfo *s)
85{
86 scroller(s, &screens[SCREEN_REMOTE]);
87}
88#endif
89
90static void (*scrollers[NB_SCREENS])(struct scrollinfo *s) = {
91 scroller_main,
92#ifdef HAVE_REMOTE_LCD
93 scroller_remote,
94#endif
95};
96
97static void put_icon(struct screen *display, int x, int y,
98 struct line_desc *line,
99 enum themable_icons icon)
100{
101 unsigned drmode = DRMODE_FG;
102 /* Need to change the drawmode:
103 * mono icons should behave like text, inverted on the selector bar
104 * native (colored) icons should be drawn as-is */
105 if (!get_icon_format(display->screen_type) == FORMAT_MONO && (line->style & STYLE_INVERT))
106 drmode = DRMODE_SOLID | DRMODE_INVERSEVID;
107
108 display->set_drawmode(drmode);
109 screen_put_iconxy(display, x, y, icon);
110}
111
112
113static void put_text(struct screen *display,
114 int x, int y, struct line_desc *line,
115 const char *text, bool prevent_scroll,
116 int text_skip_pixels)
117{
118 /* set drawmode because put_icon() might have changed it */
119 unsigned drmode = DRMODE_FG;
120 if (line->style & STYLE_INVERT)
121 drmode = DRMODE_SOLID | DRMODE_INVERSEVID;
122
123 display->set_drawmode(drmode);
124
125 if (line->scroll && !prevent_scroll)
126 {
127 struct line_desc *line_data = get_line_desc();
128 *line_data = *line;
129 /* precalculate to avoid doing it in the scroller, it's save to
130 * do this on the copy of the original line_desc*/
131 if (line_data->height == -1)
132 line_data->height = display->getcharheight();
133 display->putsxy_scroll_func(x, y, text,
134 scrollers[display->screen_type], line_data, text_skip_pixels);
135 }
136 else
137 display->putsxy_scroll_func(x, y, text, NULL, NULL, text_skip_pixels);
138}
139
140/* A line consists of:
141 * |[Ss]|[i]|[Ss]|[t]|, where s is empty space (pixels), S is empty space
142 * (n space characters), i is an icon and t is the text.
143 *
144 * All components are optional. However, even if none are specified the whole
145 * line will be cleared and redrawn.
146 *
147 * For empty space with the width of an icon use i and pass Icon_NOICON as
148 * corresponding argument.
149 */
150static void print_line(struct screen *display,
151 int x, int y, struct line_desc *line,
152 const char *fmt, va_list ap)
153{
154 const char *str;
155 bool num_is_valid;
156 int ch, num, height;
157 int xpos = x;
158 int icon_y, icon_h, icon_w;
159 enum themable_icons icon;
160 char tempbuf[128];
161 int tempbuf_idx;
162
163 height = line->height == -1 ? display->getcharheight() : line->height;
164 icon_h = get_icon_height(display->screen_type);
165 icon_w = get_icon_width(display->screen_type);
166 tempbuf_idx = 0;
167 /* vertically center string on the line
168 * x/2 - y/2 rounds up compared to (x-y)/2 if one of x and y is odd */
169 icon_y = y + height/2 - icon_h/2;
170 y += height/2 - display->getcharheight()/2;
171
172 /* parse format string */
173 while (1)
174 {
175 ch = *fmt++;
176 /* need to check for escaped '$' */
177 if (ch == '$' && *fmt != '$')
178 {
179 /* extra flag as num == 0 can be valid */
180 num_is_valid = false;
181 num = 0;
182 if (tempbuf_idx)
183 { /* flush pending inline text */
184 tempbuf_idx = tempbuf[tempbuf_idx] = 0;
185 put_text(display, xpos, y, line, tempbuf, false, 0);
186 xpos += display->getstringsize(tempbuf, NULL, NULL);
187 }
188next:
189 ch = *fmt++;
190 switch(ch)
191 {
192 case '*': /* num from parameter list */
193 num = va_arg(ap, int);
194 num_is_valid = true;
195 goto next;
196
197 case 'i': /* icon (without pad) */
198 case 'I': /* icon with pad */
199 if (ch == 'i')
200 num = 0;
201 else /* 'I' */
202 if (!num_is_valid)
203 num = 1;
204 icon = va_arg(ap, int);
205 /* draw it, then skip over */
206 if (icon != Icon_NOICON)
207 put_icon(display, xpos + num, icon_y, line, icon);
208 xpos += icon_w + num*2;
209 break;
210
211 case 'S':
212 if (!num_is_valid)
213 num = 1;
214 xpos += num * display->getcharwidth();
215 break;
216
217 case 's':
218 if (!num_is_valid)
219 num = 1;
220 xpos += num;
221 break;
222
223 case 't':
224 str = va_arg(ap, const char *);
225 put_text(display, xpos, y, line, str, false, num);
226 xpos += display->getstringsize(str, NULL, NULL);
227 break;
228
229 default:
230 if (LIKELY(isdigit(ch)))
231 {
232 num_is_valid = true;
233 num = 10*num + ch - '0';
234 goto next;
235 }
236 else
237 {
238 /* any other character here is an erroneous format string */
239 snprintf(tempbuf, sizeof(tempbuf), "<E:%c>", ch);
240 display->putsxy(xpos, y, tempbuf);
241 /* Don't consider going forward, fix the caller */
242 return;
243 }
244 }
245 }
246 else
247 { /* handle string constant in format string */
248 tempbuf[tempbuf_idx++] = ch;
249 if (!ch)
250 { /* end of string. put it online */
251 put_text(display, xpos, y, line, tempbuf, false, 0);
252 return;
253 }
254 else if (ch == '$')
255 fmt++; /* escaped '$', display just once */
256 }
257 }
258}
259
260#ifdef HAVE_LCD_BITMAP
261static void style_line(struct screen *display,
262 int x, int y, struct line_desc *line)
263{
264 int style = line->style;
265 int width = display->getwidth();
266 int height = line->height == -1 ? display->getcharheight() : line->height;
267 unsigned mask = STYLE_MODE_MASK & ~STYLE_COLORED;
268
269 /* mask out gradient and colorbar styles for non-color displays */
270 if (display->depth < 16)
271 {
272 if (style & (STYLE_COLORBAR|STYLE_GRADIENT))
273 {
274 style &= ~(STYLE_COLORBAR|STYLE_GRADIENT);
275 style |= STYLE_INVERT;
276 }
277 style &= ~STYLE_COLORED;
278 }
279
280 switch (style & mask)
281 {
282#if (LCD_DEPTH > 1 || (defined(LCD_REMOTE_DEPTH) && LCD_REMOTE_DEPTH > 1))
283 case STYLE_GRADIENT:
284 display->set_drawmode(DRMODE_FG);
285 display->gradient_fillrect_part(x, y, width, height,
286 line->line_color,
287 line->line_end_color,
288 height*line->nlines,
289 height*line->line);
290 break;
291 case STYLE_COLORBAR:
292 display->set_drawmode(DRMODE_FG);
293 display->set_foreground(line->line_color);
294 display->fillrect(x, y, width - x, height);
295 break;
296#endif
297 case STYLE_INVERT:
298 display->set_drawmode(DRMODE_FG);
299 display->fillrect(x, y, width - x, height);
300 break;
301 case STYLE_DEFAULT: default:
302 display->set_drawmode(DRMODE_BG | DRMODE_INVERSEVID);
303 display->fillrect(x, y, width - x, height);
304 break;
305 case STYLE_NONE:
306 break;
307 }
308#if (LCD_DEPTH > 1 || (defined(LCD_REMOTE_DEPTH) && LCD_REMOTE_DEPTH > 1))
309 /* fg color and bg color are left as-is for text drawing */
310 if (display->depth > 1)
311 {
312 if (style & STYLE_COLORED)
313 {
314 if (style & STYLE_INVERT)
315 display->set_background(line->text_color);
316 else
317 display->set_foreground(line->text_color);
318 }
319 else if (style & (STYLE_GRADIENT|STYLE_COLORBAR))
320 display->set_foreground(line->text_color);
321 else
322 display->set_foreground(global_settings.fg_color);
323 }
324#endif
325}
326#endif /* HAVE_LCD_BITMAP */
327
328void vput_line(struct screen *display,
329 int x, int y, struct line_desc *line,
330 const char *fmt, va_list ap)
331{
332 style_line(display, x, y, line);
333 print_line(display, x, y, line, fmt, ap);
334#if (LCD_DEPTH > 1 || (defined(LCD_REMOTE_DEPTH) && LCD_REMOTE_DEPTH > 1))
335 if (display->depth > 1)
336 display->set_foreground(global_settings.fg_color);
337#endif
338 display->set_drawmode(DRMODE_SOLID);
339}
340
341void put_line(struct screen *display,
342 int x, int y, struct line_desc *line,
343 const char *fmt, ...)
344{
345 va_list ap;
346 va_start(ap, fmt);
347 vput_line(display, x, y, line, fmt, ap);
348 va_end(ap);
349}
diff --git a/apps/gui/line.h b/apps/gui/line.h
new file mode 100644
index 0000000000..d5350eb410
--- /dev/null
+++ b/apps/gui/line.h
@@ -0,0 +1,117 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2013 Thomas Martitz
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#ifndef __LINE_H__
23#define __LINE_H__
24
25#include <stdint.h>
26#include <stdbool.h>
27#include <stdarg.h>
28
29#include "lcd.h"
30#include "screens.h"
31
32struct line_desc {
33 /* height of the line (in pixels). -1 to inherit the height
34 * from the font. The text will be centered if the height is larger,
35 * but the decorations will span the entire height */
36 int height;
37 /* multiline support: For some decorations (e.g. gradient) to work
38 * across multiple lines (e.g. to draw a line selector across 2 lines)
39 * the line index and line count must be known. For normal, single
40 * lines specify nlines=1 and line=0 */
41 /* line count of a group */
42 int16_t nlines;
43 /* index of the line in the group */
44 int16_t line;
45 /* line text color if STYLE_COLORED is specified, in native
46 * lcd format (convert with LCD_RGBPACK() if necessary) */
47 fb_data text_color;
48 /* line color if STYLE_COLORBAR or STYLE_GRADIENT is specified, in native
49 * lcd format (convert with LCD_RGBPACK() if necessary) */
50 fb_data line_color, line_end_color;
51 /* line decorations, see STYLE_DEFAULT etc. */
52 int style;
53 /* whether the line can scroll */
54 bool scroll;
55};
56
57/* default initializer, can be used for static initialitation also.
58 * This initializer will result in single lines without style that don't scroll */
59#define LINE_DESC_DEFINIT { .style = STYLE_DEFAULT, .height = -1, .line = 0, .nlines = 1, .scroll = false }
60
61/**
62 * Print a line at a given pixel postion, using decoration information from
63 * line and content information from the format specifier. The format specifier
64 * can include tags that depend on further parameters given to the function
65 * (similar to the well-known printf()).
66 *
67 * Tags start with the $ sign. Below is a list of the currently supported tags:
68 * $s - insert a column (1px wide) of empty space.
69 * $S - insert a column (1 char wide) of empty space.
70 * $i - insert an icon. put_line() expects a corresponding parameter of the
71 * type 'enum themable_icons'. If Icon_NOICON is passed, then empty
72 * space (icon-wide) will be inserted.
73 * $I - insert an icon with padding. Works like $i but additionally
74 * adds a column (1px wide) of empty space on either side of the icon.
75 * $t - insert text. put_line() expects a corresponding parameter of the type
76 * 'const char *'
77 * $$ - insert a '$' char, use it to escape $.
78 *
79 * $I, $s and $S support the following two forms:
80 * $n[IsS] - inserts n columns (pixels/chars respectively) of empty space
81 * $*[IsS] - inserts n columns (pixels/chars respectively) of empty space. put_line()
82 * expects a correspinding paramter of the type 'int' that specifies n.
83 *
84 * $t supports the following two forms:
85 * $nt - skips the first n pixels when displaying the string
86 * $*t - skips the first n pixels when displaying the string. put_line()
87 * expects a correspinding paramter of the type 'int' that specifies n.
88 *
89 * Inline text will be printed as is and can be freely intermixed with tags,
90 * except when the line can scroll. Due to limitations of the scroll engine
91 * only the last piece of text (whether inline or via $t) can scroll.
92 *
93 * x, y - pixel postion of the line.
94 * line - holds information for the line decorations
95 * fmt - holds the text and optionally format tags
96 * ... - additional paramters for the format tags
97 *
98 */
99void put_line(struct screen *display,
100 int x, int y, struct line_desc *line,
101 const char *fmt, ...);
102
103
104/**
105 * Print a line at a given pixel postion, using decoration information from
106 * line and content information from the format specifier. The format specifier
107 * can include tags that depend on further parameters given to the function
108 * (similar to the well-known vprintf()).
109 *
110 * For details, see put_line(). This function is equivalent, except for
111 * accepting a va_list instead of a variable paramter list.
112 */
113void vput_line(struct screen *display,
114 int x, int y, struct line_desc *line,
115 const char *fmt, va_list ap);
116
117#endif /* __LINE_H__*/
diff --git a/apps/plugin.h b/apps/plugin.h
index 38d8889d9e..4e6f4a8c4e 100644
--- a/apps/plugin.h
+++ b/apps/plugin.h
@@ -113,6 +113,7 @@ void* plugin_get_buffer(size_t *buffer_size);
113#include "crc32.h" 113#include "crc32.h"
114#include "rbpaths.h" 114#include "rbpaths.h"
115#include "core_alloc.h" 115#include "core_alloc.h"
116#include "screen_access.h"
116 117
117#ifdef HAVE_ALBUMART 118#ifdef HAVE_ALBUMART
118#include "albumart.h" 119#include "albumart.h"
diff --git a/apps/screen_access.c b/apps/screen_access.c
index 7f44cf5305..81bb6bae8f 100644
--- a/apps/screen_access.c
+++ b/apps/screen_access.c
@@ -100,6 +100,15 @@ static void screen_helper_set_drawmode(int mode)
100#endif 100#endif
101} 101}
102 102
103static void screen_helper_put_line(int x, int y, struct line_desc *line,
104 const char *fmt, ...)
105{
106 va_list ap;
107 va_start(ap, fmt);
108 vput_line(&screens[0], x, y, line, fmt, ap);
109 va_end(ap);
110}
111
103#if NB_SCREENS == 2 112#if NB_SCREENS == 2
104static int screen_helper_remote_getcharwidth(void) 113static int screen_helper_remote_getcharwidth(void)
105{ 114{
@@ -156,6 +165,15 @@ static void screen_helper_remote_setuifont(int font)
156#endif 165#endif
157} 166}
158 167
168static void screen_helper_remote_put_line(int x, int y, struct line_desc *line,
169 const char *fmt, ...)
170{
171 va_list ap;
172 va_start(ap, fmt);
173 vput_line(&screens[0], x, y, line, fmt, ap);
174 va_end(ap);
175}
176
159#endif 177#endif
160 178
161struct screen screens[NB_SCREENS] = 179struct screen screens[NB_SCREENS] =
@@ -280,6 +298,7 @@ struct screen screens[NB_SCREENS] =
280 .gradient_fillrect_part = lcd_gradient_fillrect_part, 298 .gradient_fillrect_part = lcd_gradient_fillrect_part,
281#endif 299#endif
282#endif 300#endif
301 .put_line = screen_helper_put_line,
283 }, 302 },
284#if NB_SCREENS == 2 303#if NB_SCREENS == 2
285 { 304 {
@@ -380,6 +399,7 @@ struct screen screens[NB_SCREENS] =
380#if defined(HAVE_LCD_BITMAP) 399#if defined(HAVE_LCD_BITMAP)
381 .set_framebuffer = (void*)lcd_remote_set_framebuffer, 400 .set_framebuffer = (void*)lcd_remote_set_framebuffer,
382#endif 401#endif
402 .put_line = screen_helper_remote_put_line,
383 } 403 }
384#endif /* NB_SCREENS == 2 */ 404#endif /* NB_SCREENS == 2 */
385}; 405};
diff --git a/apps/screen_access.h b/apps/screen_access.h
index 26c9977bf2..7bc9c35237 100644
--- a/apps/screen_access.h
+++ b/apps/screen_access.h
@@ -26,6 +26,7 @@
26#include "buttonbar.h" 26#include "buttonbar.h"
27#include "scroll_engine.h" 27#include "scroll_engine.h"
28#include "backdrop.h" 28#include "backdrop.h"
29#include "line.h"
29 30
30#if defined(HAVE_REMOTE_LCD) && !defined (ROCKBOX_HAS_LOGF) 31#if defined(HAVE_REMOTE_LCD) && !defined (ROCKBOX_HAS_LOGF)
31#define NB_SCREENS 2 32#define NB_SCREENS 2
@@ -177,6 +178,7 @@ struct screen
177 void (*nine_segment_bmp)(const struct bitmap* bm, int x, int y, 178 void (*nine_segment_bmp)(const struct bitmap* bm, int x, int y,
178 int width, int height); 179 int width, int height);
179#endif 180#endif
181 void (*put_line)(int x, int y, struct line_desc *line, const char *fmt, ...);
180}; 182};
181 183
182#if defined(HAVE_LCD_BITMAP) || defined(HAVE_REMOTE_LCD) 184#if defined(HAVE_LCD_BITMAP) || defined(HAVE_REMOTE_LCD)