rbutil: store the voice language in the correct setting.
[kugel-rb.git] / apps / gui / color_picker.c
blob09d861245a03a4f7030a5dc7dc02b496ecf29ed8
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) Jonathan Gordon (2006)
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.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
21 #include "config.h"
22 #include "stdarg.h"
23 #include "string.h"
24 #include "stdio.h"
25 #include "kernel.h"
26 #include "system.h"
27 #include "screen_access.h"
28 #include "font.h"
29 #include "debug.h"
30 #include "misc.h"
31 #include "settings.h"
32 #include "scrollbar.h"
33 #include "lang.h"
34 #include "splash.h"
35 #include "action.h"
36 #include "icon.h"
37 #include "color_picker.h"
38 #include "viewport.h"
40 /* structure for color info */
41 struct rgb_pick
43 unsigned color; /* native color value */
44 union
46 unsigned char rgb_val[6]; /* access to components as array */
47 struct
49 unsigned char r; /* native red value */
50 unsigned char g; /* native green value */
51 unsigned char b; /* native blue value */
52 unsigned char red; /* 8 bit red value */
53 unsigned char green; /* 8 bit green value */
54 unsigned char blue; /* 8 bit blue value */
55 } __attribute__ ((__packed__)); /* assume byte packing */
60 /* list of primary colors */
61 #define SB_PRIM 0
62 #define SB_FILL 1
63 static const fb_data prim_rgb[][3] =
65 /* Foreground colors for sliders */
67 LCD_RGBPACK(255, 0, 0),
68 LCD_RGBPACK( 0, 255, 0),
69 LCD_RGBPACK( 0, 0, 255),
71 /* Fill colors for sliders */
73 LCD_RGBPACK( 85, 0, 0),
74 LCD_RGBPACK( 0, 85, 0),
75 LCD_RGBPACK( 0, 0, 85),
79 /* maximum values for components */
80 static const unsigned char rgb_max[3] =
82 LCD_MAX_RED,
83 LCD_MAX_GREEN,
84 LCD_MAX_BLUE
87 /* Unpacks the color value into native rgb values and 24 bit rgb values */
88 static void unpack_rgb(struct rgb_pick *rgb)
90 unsigned color = _LCD_UNSWAP_COLOR(rgb->color);
91 rgb->red = _RGB_UNPACK_RED(color);
92 rgb->green = _RGB_UNPACK_GREEN(color);
93 rgb->blue = _RGB_UNPACK_BLUE(color);
94 rgb->r = _RGB_UNPACK_RED_LCD(color);
95 rgb->g = _RGB_UNPACK_GREEN_LCD(color);
96 rgb->b = _RGB_UNPACK_BLUE_LCD(color);
99 /* Packs the native rgb colors into a color value */
100 static inline void pack_rgb(struct rgb_pick *rgb)
102 rgb->color = LCD_RGBPACK_LCD(rgb->r, rgb->g, rgb->b);
105 /* Returns LCD_BLACK if the color is above a threshold brightness
106 else return LCD_WHITE */
107 static inline unsigned get_black_or_white(const struct rgb_pick *rgb)
109 return (2*rgb->red + 5*rgb->green + rgb->blue) >= 1024 ?
110 LCD_BLACK : LCD_WHITE;
113 #define MARGIN_TOP 2 /* Top margin of screen */
114 #define MARGIN_BOTTOM 6 /* Bottom margin of screen */
115 #define SLIDER_TEXT_MARGIN 2 /* Gap between text and sliders */
116 #define TITLE_MARGIN_BOTTOM 4 /* Space below title bar */
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 /* Figure out widest label character in case they vary -
135 this function assumes labels are one character */
136 static int label_get_max_width(struct screen *display)
138 int max_width, i;
139 char buf[4];
140 for (i = 0, max_width = 0; i < 3; i++)
142 int width;
143 buf[0] = str(LANG_COLOR_RGB_LABELS)[i];
144 buf[1] = '\0';
145 width = display->getstringsize(buf, NULL, NULL);
146 if (width > max_width)
147 max_width = width;
149 return max_width;
152 static void draw_screen(struct screen *display, char *title,
153 struct rgb_pick *rgb, int row)
155 unsigned text_color = LCD_BLACK;
156 unsigned background_color = LCD_WHITE;
157 char buf[32];
158 int i, text_x, y, line_height;
159 int text_top;
160 int slider_x, slider_width;
161 bool display_three_rows;
162 int max_label_width;
163 struct viewport vp;
165 viewport_set_defaults(&vp, display->screen_type);
166 display->set_viewport(&vp);
168 display->clear_display();
170 if (display->depth > 1)
172 text_color = display->get_foreground();
173 background_color = display->get_background();
176 max_label_width = label_get_max_width(display);
178 /* Draw title string */
179 set_drawinfo(display, DRMODE_SOLID, text_color, background_color);
180 vp.flags |= VP_FLAG_ALIGN_CENTER;
181 display->getstringsize(title, NULL, &y);
182 display->putsxy(0, MARGIN_TOP, title);
184 /* Get slider positions and top starting position */
185 text_top = MARGIN_TOP + y + TITLE_MARGIN_BOTTOM + SELECTOR_TB_MARGIN;
186 text_x = SELECTOR_WIDTH;
187 slider_x = text_x + max_label_width + SLIDER_TEXT_MARGIN;
188 slider_width = vp.width - slider_x*2 - max_label_width;
189 line_height = display->getcharheight() + 2*SELECTOR_TB_MARGIN;
191 /* Find out if there's enough room for three sliders or just
192 enough to display the selected slider - calculate total height
193 of display with three sliders present */
194 display_three_rows =
195 vp.height >=
196 text_top + line_height*3 + /* Title + 3 sliders */
197 SWATCH_TOP_MARGIN + /* at least 2 lines */
198 display->getcharheight()*2 + /* + margins for bottom */
199 MARGIN_BOTTOM; /* colored rectangle */
201 for (i = 0; i < 3; i++)
203 unsigned sb_flags = HORIZONTAL;
204 int mode = DRMODE_SOLID;
205 unsigned fg = text_color;
206 unsigned bg = background_color;
208 if (i == row)
210 set_drawinfo(display, DRMODE_SOLID, text_color,
211 background_color);
213 if (global_settings.cursor_style != 0)
215 /* Draw solid bar selection bar */
216 display->fillrect(0,
217 text_top - SELECTOR_TB_MARGIN,
218 vp.width,
219 display->getcharheight() +
220 SELECTOR_TB_MARGIN*2);
222 if (display->depth < 16)
224 sb_flags |= FOREGROUND | INNER_FILL;
225 mode |= DRMODE_INVERSEVID;
228 else if (display_three_rows)
230 /* Draw "> <" around sliders */
231 int top = text_top + (display->getcharheight() -
232 SELECTOR_HEIGHT) / 2;
233 screen_put_iconxy(display, 0, top, Icon_Cursor);
234 screen_put_iconxy(display,
235 vp.width -
236 get_icon_width(display->screen_type),
237 top, Icon_Cursor);
240 if (display->depth >= 16)
242 sb_flags |= FOREGROUND | INNER_BGFILL;
243 mode = DRMODE_FG;
244 fg = prim_rgb[SB_PRIM][i];
245 bg = prim_rgb[SB_FILL][i];
248 else if (!display_three_rows)
249 continue;
251 set_drawinfo(display, mode, fg, bg);
253 /* Draw label */
254 buf[0] = str(LANG_COLOR_RGB_LABELS)[i];
255 buf[1] = '\0';
256 vp.flags &= ~VP_FLAG_ALIGNMENT_MASK;
257 display->putsxy(text_x, text_top, buf);
258 /* Draw color value */
259 snprintf(buf, 3, "%02d", rgb->rgb_val[i]);
260 vp.flags |= VP_FLAG_ALIGN_RIGHT;
261 display->putsxy(text_x, text_top, buf);
263 /* Draw scrollbar */
264 gui_scrollbar_draw(display, /* screen */
265 slider_x, /* x */
266 text_top + display->getcharheight() / 4,/* y */
267 slider_width, /* width */
268 display->getcharheight() / 2, /* height */
269 rgb_max[i], /* items */
270 0, /* min_shown */
271 rgb->rgb_val[i], /* max_shown */
272 sb_flags); /* flags */
274 /* Advance to next line */
275 text_top += line_height;
276 } /* end for */
278 /* Format RGB: #rrggbb */
279 snprintf(buf, sizeof(buf), str(LANG_COLOR_RGB_VALUE),
280 rgb->red, rgb->green, rgb->blue);
281 vp.flags |= VP_FLAG_ALIGN_CENTER;
282 if (display->depth >= 16)
284 /* Display color swatch on color screens only */
285 int top = text_top + SWATCH_TOP_MARGIN;
286 int width = vp.width - text_x*2;
287 int height = vp.height - top - MARGIN_BOTTOM;
289 /* Only draw if room */
290 if (height >= display->getcharheight() + 2)
292 /* draw the big rectangle */
293 display->set_foreground(rgb->color);
294 display->fillrect(text_x, top, width, height);
296 /* Draw RGB: #rrggbb in middle of swatch */
297 set_drawinfo(display, DRMODE_FG, get_black_or_white(rgb),
298 background_color);
299 display->getstringsize(buf, NULL, &y);
301 display->putsxy(0, top + (height - y) / 2, buf);
303 /* Draw border around the rect */
304 set_drawinfo(display, DRMODE_SOLID, text_color,
305 background_color);
306 display->drawrect(text_x, top, width, height);
309 else
311 /* Display RGB value only centered on remaining display if room */
312 display->getstringsize(buf, NULL, &y);
313 i = text_top + SWATCH_TOP_MARGIN;
315 if (i + y <= display->getheight() - MARGIN_BOTTOM)
317 set_drawinfo(display, DRMODE_SOLID, text_color, background_color);
318 display->putsxy(0, (i + vp.height - MARGIN_BOTTOM - y) / 2, buf);
322 display->setfont(FONT_UI);
324 display->update_viewport();
325 display->set_viewport(NULL);
326 /* Be sure screen mode is reset */
327 set_drawinfo(display, DRMODE_SOLID, text_color, background_color);
330 #ifdef HAVE_TOUCHSCREEN
331 static int touchscreen_slider(struct screen *display,
332 struct rgb_pick *rgb,
333 const char* title,
334 int *selected_slider)
336 short x,y;
337 int text_top, slider_x, slider_width, title_height;
338 int button;
339 bool display_three_rows;
340 int max_label_width;
341 int pressed_slider;
342 struct viewport vp;
343 int line_height;
345 viewport_set_defaults(&vp, display->screen_type);
347 max_label_width = label_get_max_width(display);
348 display->getstringsize(title, NULL, &title_height);
349 button = action_get_touchscreen_press_in_vp(&x, &y, &vp);
350 if (button == ACTION_UNKNOWN || button == BUTTON_NONE)
351 return ACTION_NONE;
352 /* Get slider positions and top starting position
353 * need vp.y here, because of the statusbar, since touchscreen
354 * coordinates are absolute */
355 text_top = MARGIN_TOP + title_height + TITLE_MARGIN_BOTTOM +
356 SELECTOR_TB_MARGIN;
357 slider_x = SELECTOR_WIDTH + max_label_width + SLIDER_TEXT_MARGIN;
358 slider_width = vp.width - slider_x*2 - max_label_width;
359 line_height = display->getcharheight() + 2*SELECTOR_TB_MARGIN;
361 /* same logic as in draw_screen */
362 /* Find out if there's enough room for three sliders or just
363 enough to display the selected slider - calculate total height
364 of display with three sliders present */
365 display_three_rows =
366 vp.height >=
367 text_top + title_height*3 + /* Title + 3 sliders */
368 SWATCH_TOP_MARGIN + /* at least 2 lines */
369 display->getcharheight()*2 + /* + margins for bottom */
370 MARGIN_BOTTOM; /* colored rectangle */
372 if (y < text_top)
374 if (button == BUTTON_REL)
375 return ACTION_STD_CANCEL;
378 vp.y += text_top;
379 vp.height = line_height * (display_three_rows ? 3:1);
380 if (!viewport_point_within_vp(&vp, x, y))
381 { /* touching the color area means accept */
382 if (button == BUTTON_REL)
383 return ACTION_STD_OK;
385 /* y is relative to the original viewport */
386 pressed_slider = (y - text_top)/line_height;
387 if (pressed_slider != *selected_slider)
388 *selected_slider = pressed_slider;
389 /* add max_label_width to overcome integer division limits,
390 * cap value later since that may lead to an overflow */
391 if (x < slider_x+(slider_width+max_label_width) &&
392 x > slider_x)
394 char computed_val;
395 x -= slider_x;
396 computed_val = (x*rgb_max[pressed_slider]/(slider_width));
397 rgb->rgb_val[pressed_slider] =
398 MIN(computed_val,rgb_max[pressed_slider]);
399 pack_rgb(rgb);
401 return ACTION_NONE;
403 #endif
404 /***********
405 set_color
406 returns true if USB was inserted, false otherwise
407 color is a pointer to the colour (in native format) to modify
408 set banned_color to -1 to allow all
409 ***********/
410 bool set_color(struct screen *display, char *title, unsigned *color,
411 unsigned banned_color)
413 int exit = 0, slider = 0;
414 struct rgb_pick rgb;
416 rgb.color = *color;
418 while (!exit)
420 int button;
422 unpack_rgb(&rgb);
424 if (display != NULL)
426 draw_screen(display, title, &rgb, slider);
428 else
430 int i;
431 FOR_NB_SCREENS(i)
432 draw_screen(&screens[i], title, &rgb, slider);
435 button = get_action(CONTEXT_SETTINGS_COLOURCHOOSER, TIMEOUT_BLOCK);
436 #ifdef HAVE_TOUCHSCREEN
437 if (button == ACTION_TOUCHSCREEN
438 && display->screen_type == SCREEN_MAIN)
439 button = touchscreen_slider(display, &rgb, title, &slider);
440 #endif
442 switch (button)
444 case ACTION_STD_PREV:
445 case ACTION_STD_PREVREPEAT:
446 slider = (slider + 2) % 3;
447 break;
449 case ACTION_STD_NEXT:
450 case ACTION_STD_NEXTREPEAT:
451 slider = (slider + 1) % 3;
452 break;
454 case ACTION_SETTINGS_INC:
455 case ACTION_SETTINGS_INCREPEAT:
456 if (rgb.rgb_val[slider] < rgb_max[slider])
457 rgb.rgb_val[slider]++;
458 pack_rgb(&rgb);
459 break;
461 case ACTION_SETTINGS_DEC:
462 case ACTION_SETTINGS_DECREPEAT:
463 if (rgb.rgb_val[slider] > 0)
464 rgb.rgb_val[slider]--;
465 pack_rgb(&rgb);
466 break;
468 case ACTION_STD_OK:
469 if (banned_color != (unsigned)-1 &&
470 banned_color == rgb.color)
472 splash(HZ*2, ID2P(LANG_COLOR_UNACCEPTABLE));
473 break;
475 *color = rgb.color;
476 exit = 1;
477 break;
479 case ACTION_STD_CANCEL:
480 exit = 1;
481 break;
483 default:
484 if (default_event_handler(button) == SYS_USB_CONNECTED)
485 return true;
486 break;
490 return false;