Add 2008 to the copyright notice.
[Rockbox.git] / apps / gui / color_picker.c
blobb883349620779aba2e95c835f70334b148b70582
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) Jonathan Gordon (2006)
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
18 ****************************************************************************/
19 #include "config.h"
20 #include "stdarg.h"
21 #include "string.h"
22 #include "stdio.h"
23 #include "kernel.h"
24 #include "system.h"
25 #include "screen_access.h"
26 #include "font.h"
27 #include "debug.h"
28 #include "misc.h"
29 #include "settings.h"
30 #include "scrollbar.h"
31 #include "lang.h"
32 #include "splash.h"
33 #include "action.h"
34 #include "icon.h"
36 /* structure for color info */
37 struct rgb_pick
39 unsigned color; /* native color value */
40 union
42 unsigned char rgb_val[6]; /* access to components as array */
43 struct
45 unsigned char r; /* native red value */
46 unsigned char g; /* native green value */
47 unsigned char b; /* native blue value */
48 unsigned char red; /* 8 bit red value */
49 unsigned char green; /* 8 bit green value */
50 unsigned char blue; /* 8 bit blue value */
51 } __attribute__ ((__packed__)); /* assume byte packing */
56 /* list of primary colors */
57 #define SB_PRIM 0
58 #define SB_FILL 1
59 static const fb_data prim_rgb[][3] =
61 /* Foreground colors for sliders */
63 LCD_RGBPACK(255, 0, 0),
64 LCD_RGBPACK( 0, 255, 0),
65 LCD_RGBPACK( 0, 0, 255),
67 /* Fill colors for sliders */
69 LCD_RGBPACK( 85, 0, 0),
70 LCD_RGBPACK( 0, 85, 0),
71 LCD_RGBPACK( 0, 0, 85),
75 /* maximum values for components */
76 static const unsigned char rgb_max[3] =
78 LCD_MAX_RED,
79 LCD_MAX_GREEN,
80 LCD_MAX_BLUE
83 /* Unpacks the color value into native rgb values and 24 bit rgb values */
84 static void unpack_rgb(struct rgb_pick *rgb)
86 unsigned color = _LCD_UNSWAP_COLOR(rgb->color);
87 rgb->red = _RGB_UNPACK_RED(color);
88 rgb->green = _RGB_UNPACK_GREEN(color);
89 rgb->blue = _RGB_UNPACK_BLUE(color);
90 rgb->r = _RGB_UNPACK_RED_LCD(color);
91 rgb->g = _RGB_UNPACK_GREEN_LCD(color);
92 rgb->b = _RGB_UNPACK_BLUE_LCD(color);
95 /* Packs the native rgb colors into a color value */
96 static inline void pack_rgb(struct rgb_pick *rgb)
98 rgb->color = LCD_RGBPACK_LCD(rgb->r, rgb->g, rgb->b);
101 /* Returns LCD_BLACK if the color is above a threshold brightness
102 else return LCD_WHITE */
103 static inline unsigned get_black_or_white(const struct rgb_pick *rgb)
105 return (2*rgb->red + 5*rgb->green + rgb->blue) >= 1024 ?
106 LCD_BLACK : LCD_WHITE;
109 #define MARGIN_LEFT 0 /* Left margin of screen */
110 #define MARGIN_TOP 2 /* Top margin of screen */
111 #define MARGIN_RIGHT 0 /* Right margin of screen */
112 #define MARGIN_BOTTOM 6 /* Bottom margin of screen */
113 #define SLIDER_MARGIN_LEFT 2 /* Gap to left of sliders */
114 #define SLIDER_MARGIN_RIGHT 2 /* Gap to right of sliders */
115 #define TITLE_MARGIN_BOTTOM 4 /* Space below title bar */
116 #define SELECTOR_LR_MARGIN 0 /* Margin between ">" and text */
117 #define SELECTOR_TB_MARGIN 1 /* Margin on top and bottom of selector */
118 #define SWATCH_TOP_MARGIN 4 /* Space between last slider and swatch */
119 #define SELECTOR_WIDTH get_icon_width(display->screen_type)
120 #define SELECTOR_HEIGHT 8 /* Height of > and < bitmaps */
122 /* dunno why lcd_set_drawinfo should be left out of struct screen */
123 static void set_drawinfo(struct screen *display, int mode,
124 unsigned foreground, unsigned background)
126 display->set_drawmode(mode);
127 if (display->depth > 1)
129 display->set_foreground(foreground);
130 display->set_background(background);
134 static void draw_screen(struct screen *display, char *title,
135 struct rgb_pick *rgb, int row)
137 unsigned text_color = LCD_BLACK;
138 unsigned background_color = LCD_WHITE;
139 char buf[32];
140 int i, x, y;
141 int text_top;
142 int slider_left, slider_width;
143 bool display_three_rows;
144 int max_label_width;
146 display->clear_display();
148 if (display->depth > 1)
150 text_color = display->get_foreground();
151 background_color = display->get_background();
154 /* Find out if there's enough room for three sliders or just
155 enough to display the selected slider - calculate total height
156 of display with three sliders present */
157 display_three_rows =
158 display->height >= MARGIN_TOP +
159 display->char_height*4 + /* Title + 3 sliders */
160 TITLE_MARGIN_BOTTOM +
161 SELECTOR_TB_MARGIN*6 + /* 2 margins/slider */
162 MARGIN_BOTTOM;
164 /* Figure out widest label character in case they vary -
165 this function assumes labels are one character */
166 for (i = 0, max_label_width = 0; i < 3; i++)
168 buf[0] = str(LANG_COLOR_RGB_LABELS)[i];
169 buf[1] = '\0';
170 x = display->getstringsize(buf, NULL, NULL);
171 if (x > max_label_width)
172 max_label_width = x;
175 /* Draw title string */
176 set_drawinfo(display, DRMODE_SOLID, text_color, background_color);
177 display->getstringsize(title, &x, &y);
178 display->putsxy((display->width - x) / 2, MARGIN_TOP, title);
180 /* Get slider positions and top starting position */
181 text_top = MARGIN_TOP + y + TITLE_MARGIN_BOTTOM + SELECTOR_TB_MARGIN;
182 slider_left = MARGIN_LEFT + SELECTOR_WIDTH + SELECTOR_LR_MARGIN +
183 max_label_width + SLIDER_MARGIN_LEFT;
184 slider_width = display->width - slider_left - SLIDER_MARGIN_RIGHT -
185 display->char_width*2 - SELECTOR_LR_MARGIN - SELECTOR_WIDTH -
186 MARGIN_RIGHT;
188 for (i = 0; i < 3; i++)
190 unsigned sb_flags = HORIZONTAL;
191 int mode = DRMODE_SOLID;
192 unsigned fg = text_color;
193 unsigned bg = background_color;
195 if (!display_three_rows)
196 i = row;
198 if (i == row)
200 set_drawinfo(display, DRMODE_SOLID, text_color,
201 background_color);
203 if (global_settings.cursor_style != 0)
205 /* Draw solid bar selection bar */
206 display->fillrect(0,
207 text_top - SELECTOR_TB_MARGIN,
208 display->width,
209 display->char_height +
210 SELECTOR_TB_MARGIN*2);
212 if (display->depth < 16)
214 sb_flags |= FOREGROUND | INNER_FILL;
215 mode |= DRMODE_INVERSEVID;
218 else if (display_three_rows)
220 /* Draw "> <" around sliders */
221 int top = text_top + (display->char_height -
222 SELECTOR_HEIGHT) / 2;
223 screen_put_iconxy(display, MARGIN_LEFT, top, Icon_Cursor);
224 screen_put_iconxy(display,
225 display->width - MARGIN_RIGHT -
226 get_icon_width(display->screen_type),
227 top, Icon_Cursor);
230 if (display->depth >= 16)
232 sb_flags |= FOREGROUND | INNER_BGFILL;
233 mode = DRMODE_FG;
234 fg = prim_rgb[SB_PRIM][i];
235 bg = prim_rgb[SB_FILL][i];
239 set_drawinfo(display, mode, fg, bg);
241 /* Draw label */
242 buf[0] = str(LANG_COLOR_RGB_LABELS)[i];
243 buf[1] = '\0';
244 display->putsxy(slider_left - display->char_width -
245 SLIDER_MARGIN_LEFT, text_top, buf);
247 /* Draw color value */
248 snprintf(buf, 3, "%02d", rgb->rgb_val[i]);
249 display->putsxy(slider_left + slider_width + SLIDER_MARGIN_RIGHT,
250 text_top, buf);
252 /* Draw scrollbar */
253 gui_scrollbar_draw(display,
254 slider_left,
255 text_top + display->char_height / 4,
256 slider_width,
257 display->char_height / 2,
258 rgb_max[i],
260 rgb->rgb_val[i],
261 sb_flags);
263 /* Advance to next line */
264 text_top += display->char_height + 2*SELECTOR_TB_MARGIN;
266 if (!display_three_rows)
267 break;
268 } /* end for */
270 /* Draw color value in system font */
271 display->setfont(FONT_SYSFIXED);
273 /* Format RGB: #rrggbb */
274 snprintf(buf, sizeof(buf), str(LANG_COLOR_RGB_VALUE),
275 rgb->red, rgb->green, rgb->blue);
277 if (display->depth >= 16)
279 /* Display color swatch on color screens only */
280 int left = MARGIN_LEFT + SELECTOR_WIDTH + SELECTOR_LR_MARGIN;
281 int top = text_top + SWATCH_TOP_MARGIN;
282 int width = display->width - left - SELECTOR_LR_MARGIN -
283 SELECTOR_WIDTH - MARGIN_RIGHT;
284 int height = display->height - top - MARGIN_BOTTOM;
286 /* Only draw if room */
287 if (height >= display->char_height + 2)
289 display->set_foreground(rgb->color);
290 display->fillrect(left, top, width, height);
292 /* Draw RGB: #rrggbb in middle of swatch */
293 display->set_drawmode(DRMODE_FG);
294 display->getstringsize(buf, &x, &y);
295 display->set_foreground(get_black_or_white(rgb));
297 x = left + (width - x) / 2;
298 y = top + (height - y) / 2;
300 display->putsxy(x, y, buf);
301 display->set_drawmode(DRMODE_SOLID);
303 /* Draw border */
304 display->set_foreground(text_color);
305 display->drawrect(left, top, width, height);
308 else
310 /* Display RGB value only centered on remaining display if room */
311 display->getstringsize(buf, &x, &y);
312 i = text_top + SWATCH_TOP_MARGIN;
314 if (i + y <= display->height - MARGIN_BOTTOM)
316 set_drawinfo(display, DRMODE_SOLID, text_color, background_color);
317 x = (display->width - x) / 2;
318 y = (i + display->height - MARGIN_BOTTOM - y) / 2;
319 display->putsxy(x, y, buf);
323 display->setfont(FONT_UI);
325 display->update();
326 /* Be sure screen mode is reset */
327 set_drawinfo(display, DRMODE_SOLID, text_color, background_color);
330 #ifdef HAVE_TOUCHPAD
331 int touchpad_slider(struct rgb_pick *rgb, int *selected_slider)
333 short x,y;
334 int text_top,i,x1;
335 int slider_left, slider_width;
336 unsigned button = action_get_touchpad_press(&x, &y);
337 bool display_three_rows;
338 int max_label_width;
339 struct screen *display = &screens[SCREEN_MAIN];
340 int pressed_slider;
341 char buf[2];
343 if (button == BUTTON_NONE)
344 return ACTION_NONE;
345 /* same logic as draw_screen */
346 /* Figure out widest label character in case they vary -
347 this function assumes labels are one character */
348 for (i = 0, max_label_width = 0; i < 3; i++)
350 buf[0] = str(LANG_COLOR_RGB_LABELS)[i];
351 buf[1] = '\0';
352 x1 = display->getstringsize(buf, NULL, NULL);
353 if (x1 > max_label_width)
354 max_label_width = x1;
356 /* Get slider positions and top starting position */
357 text_top = MARGIN_TOP + display->char_height + TITLE_MARGIN_BOTTOM + SELECTOR_TB_MARGIN;
358 slider_left = MARGIN_LEFT + SELECTOR_WIDTH + SELECTOR_LR_MARGIN +
359 max_label_width + SLIDER_MARGIN_LEFT;
360 slider_width = display->width - slider_left - SLIDER_MARGIN_RIGHT -
361 display->char_width*2 - SELECTOR_LR_MARGIN - SELECTOR_WIDTH -
362 MARGIN_RIGHT;
363 display_three_rows =
364 display->height >= MARGIN_TOP +
365 display->char_height*4 + /* Title + 3 sliders */
366 TITLE_MARGIN_BOTTOM +
367 SELECTOR_TB_MARGIN*6 + /* 2 margins/slider */
368 MARGIN_BOTTOM;
369 if (y < MARGIN_TOP+display->char_height)
371 if (button == BUTTON_REL)
372 return ACTION_STD_CANCEL;
374 y -= text_top;
375 pressed_slider = y/display->char_height;
376 if (pressed_slider > (display_three_rows?2:0))
378 if (button == BUTTON_REL)
379 return ACTION_STD_OK;
381 if (pressed_slider != *selected_slider)
382 *selected_slider = pressed_slider;
383 if (x < slider_left+slider_width &&
384 x > slider_left)
386 x -= slider_left;
387 rgb->rgb_val[pressed_slider] =
388 (x*rgb_max[pressed_slider]/(slider_width-slider_left));
389 pack_rgb(rgb);
391 return ACTION_NONE;
393 #endif
394 /***********
395 set_color
396 returns true if USB was inserted, false otherwise
397 color is a pointer to the colour (in native format) to modify
398 set banned_color to -1 to allow all
399 ***********/
400 bool set_color(struct screen *display, char *title, unsigned *color,
401 unsigned banned_color)
403 int exit = 0, slider = 0;
404 struct rgb_pick rgb;
406 rgb.color = *color;
408 while (!exit)
410 int button;
412 unpack_rgb(&rgb);
414 if (display != NULL)
416 draw_screen(display, title, &rgb, slider);
418 else
420 int i;
421 FOR_NB_SCREENS(i)
422 draw_screen(&screens[i], title, &rgb, slider);
425 button = get_action(CONTEXT_SETTINGS_COLOURCHOOSER, TIMEOUT_BLOCK);
426 #ifdef HAVE_TOUCHPAD
427 if (button == ACTION_TOUCHPAD)
428 button = touchpad_slider(&rgb, &slider);
429 #endif
431 switch (button)
433 case ACTION_STD_PREV:
434 case ACTION_STD_PREVREPEAT:
435 slider = (slider + 2) % 3;
436 break;
438 case ACTION_STD_NEXT:
439 case ACTION_STD_NEXTREPEAT:
440 slider = (slider + 1) % 3;
441 break;
443 case ACTION_SETTINGS_INC:
444 case ACTION_SETTINGS_INCREPEAT:
445 if (rgb.rgb_val[slider] < rgb_max[slider])
446 rgb.rgb_val[slider]++;
447 pack_rgb(&rgb);
448 break;
450 case ACTION_SETTINGS_DEC:
451 case ACTION_SETTINGS_DECREPEAT:
452 if (rgb.rgb_val[slider] > 0)
453 rgb.rgb_val[slider]--;
454 pack_rgb(&rgb);
455 break;
457 case ACTION_STD_OK:
458 if (banned_color != (unsigned)-1 &&
459 banned_color == rgb.color)
461 gui_syncsplash(HZ*2, ID2P(LANG_COLOR_UNACCEPTABLE));
462 break;
464 *color = rgb.color;
465 exit = 1;
466 break;
468 case ACTION_STD_CANCEL:
469 exit = 1;
470 break;
472 default:
473 if (default_event_handler(button) == SYS_USB_CONNECTED)
474 return true;
475 break;
479 return false;