FS#8961 - Anti-Aliased Fonts.
[kugel-rb.git] / apps / gui / color_picker.c
blob026ae82c4c7786251ced6b20e656004a3dce504d
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_LEFT 0 /* Left margin of screen */
114 #define MARGIN_TOP 2 /* Top margin of screen */
115 #define MARGIN_RIGHT 0 /* Right margin of screen */
116 #define MARGIN_BOTTOM 6 /* Bottom margin of screen */
117 #define SLIDER_MARGIN_LEFT 2 /* Gap to left of sliders */
118 #define SLIDER_MARGIN_RIGHT 2 /* Gap to right of sliders */
119 #define TITLE_MARGIN_BOTTOM 4 /* Space below title bar */
120 #define SELECTOR_LR_MARGIN 0 /* Margin between ">" and text */
121 #define SELECTOR_TB_MARGIN 1 /* Margin on top and bottom of selector */
122 #define SWATCH_TOP_MARGIN 4 /* Space between last slider and swatch */
123 #define SELECTOR_WIDTH get_icon_width(display->screen_type)
124 #define SELECTOR_HEIGHT 8 /* Height of > and < bitmaps */
126 /* dunno why lcd_set_drawinfo should be left out of struct screen */
127 static void set_drawinfo(struct screen *display, int mode,
128 unsigned foreground, unsigned background)
130 display->set_drawmode(mode);
131 if (display->depth > 1)
133 display->set_foreground(foreground);
134 display->set_background(background);
138 static void draw_screen(struct screen *display, char *title,
139 struct rgb_pick *rgb, int row)
141 unsigned text_color = LCD_BLACK;
142 unsigned background_color = LCD_WHITE;
143 char buf[32];
144 int i, x, y;
145 int text_top;
146 int slider_left, slider_width;
147 bool display_three_rows;
148 int max_label_width;
149 struct viewport vp;
151 viewport_set_defaults(&vp, display->screen_type);
152 display->set_viewport(&vp);
154 display->clear_display();
156 if (display->depth > 1)
158 text_color = display->get_foreground();
159 background_color = display->get_background();
162 /* Find out if there's enough room for three sliders or just
163 enough to display the selected slider - calculate total height
164 of display with three sliders present */
165 display_three_rows =
166 vp.height >=
167 MARGIN_TOP +
168 display->getcharheight()*4 + /* Title + 3 sliders */
169 TITLE_MARGIN_BOTTOM +
170 SELECTOR_TB_MARGIN*6 + /* 2 margins/slider */
171 MARGIN_BOTTOM;
173 /* Figure out widest label character in case they vary -
174 this function assumes labels are one character */
175 for (i = 0, max_label_width = 0; i < 3; i++)
177 buf[0] = str(LANG_COLOR_RGB_LABELS)[i];
178 buf[1] = '\0';
179 x = display->getstringsize(buf, NULL, NULL);
180 if (x > max_label_width)
181 max_label_width = x;
184 /* Draw title string */
185 set_drawinfo(display, DRMODE_SOLID, text_color, background_color);
186 display->getstringsize(title, &x, &y);
187 display->putsxy((vp.width - x) / 2, MARGIN_TOP, title);
189 /* Get slider positions and top starting position */
190 text_top = MARGIN_TOP + y + TITLE_MARGIN_BOTTOM + SELECTOR_TB_MARGIN;
191 slider_left = MARGIN_LEFT + SELECTOR_WIDTH + SELECTOR_LR_MARGIN +
192 max_label_width + SLIDER_MARGIN_LEFT;
193 slider_width = vp.width - slider_left - SLIDER_MARGIN_RIGHT -
194 display->getcharwidth()*2 - SELECTOR_LR_MARGIN -
195 SELECTOR_WIDTH - MARGIN_RIGHT;
197 for (i = 0; i < 3; i++)
199 unsigned sb_flags = HORIZONTAL;
200 int mode = DRMODE_SOLID;
201 unsigned fg = text_color;
202 unsigned bg = background_color;
204 if (!display_three_rows)
205 i = row;
207 if (i == row)
209 set_drawinfo(display, DRMODE_SOLID, text_color,
210 background_color);
212 if (global_settings.cursor_style != 0)
214 /* Draw solid bar selection bar */
215 display->fillrect(0,
216 text_top - SELECTOR_TB_MARGIN,
217 vp.width,
218 display->getcharheight() +
219 SELECTOR_TB_MARGIN*2);
221 if (display->depth < 16)
223 sb_flags |= FOREGROUND | INNER_FILL;
224 mode |= DRMODE_INVERSEVID;
227 else if (display_three_rows)
229 /* Draw "> <" around sliders */
230 int top = text_top + (display->getcharheight() -
231 SELECTOR_HEIGHT) / 2;
232 screen_put_iconxy(display, MARGIN_LEFT, top, Icon_Cursor);
233 screen_put_iconxy(display,
234 vp.width - MARGIN_RIGHT -
235 get_icon_width(display->screen_type),
236 top, Icon_Cursor);
239 if (display->depth >= 16)
241 sb_flags |= FOREGROUND | INNER_BGFILL;
242 mode = DRMODE_FG;
243 fg = prim_rgb[SB_PRIM][i];
244 bg = prim_rgb[SB_FILL][i];
248 set_drawinfo(display, mode, fg, bg);
250 /* Draw label */
251 buf[0] = str(LANG_COLOR_RGB_LABELS)[i];
252 buf[1] = '\0';
253 display->putsxy(slider_left - max_label_width -
254 SLIDER_MARGIN_LEFT, text_top, buf);
256 /* Draw color value */
257 snprintf(buf, 3, "%02d", rgb->rgb_val[i]);
258 display->putsxy(slider_left + slider_width + SLIDER_MARGIN_RIGHT,
259 text_top, buf);
261 /* Draw scrollbar */
262 gui_scrollbar_draw(display,
263 slider_left,
264 text_top + display->getcharheight() / 4,
265 slider_width,
266 display->getcharheight() / 2,
267 rgb_max[i],
269 rgb->rgb_val[i],
270 sb_flags);
272 /* Advance to next line */
273 text_top += display->getcharheight() + 2*SELECTOR_TB_MARGIN;
275 if (!display_three_rows)
276 break;
277 } /* end for */
279 /* Format RGB: #rrggbb */
280 snprintf(buf, sizeof(buf), str(LANG_COLOR_RGB_VALUE),
281 rgb->red, rgb->green, rgb->blue);
283 if (display->depth >= 16)
285 /* Display color swatch on color screens only */
286 int left = MARGIN_LEFT + SELECTOR_WIDTH + SELECTOR_LR_MARGIN;
287 int top = text_top + SWATCH_TOP_MARGIN;
288 int width = vp.width - left - SELECTOR_LR_MARGIN -
289 SELECTOR_WIDTH - MARGIN_RIGHT;
290 int height = vp.height - top - MARGIN_BOTTOM;
292 /* Only draw if room */
293 if (height >= display->getcharheight() + 2)
295 display->set_foreground(rgb->color);
296 display->fillrect(left, top, width, height);
298 /* Draw RGB: #rrggbb in middle of swatch */
299 display->set_drawmode(DRMODE_FG);
300 display->getstringsize(buf, &x, &y);
301 display->set_foreground(get_black_or_white(rgb));
303 x = left + (width - x) / 2;
304 y = top + (height - y) / 2;
306 display->putsxy(x, y, buf);
307 display->set_drawmode(DRMODE_SOLID);
309 /* Draw border */
310 display->set_foreground(text_color);
311 display->drawrect(left, top, width, height);
314 else
316 /* Display RGB value only centered on remaining display if room */
317 display->getstringsize(buf, &x, &y);
318 i = text_top + SWATCH_TOP_MARGIN;
320 if (i + y <= display->getheight() - MARGIN_BOTTOM)
322 set_drawinfo(display, DRMODE_SOLID, text_color, background_color);
323 x = (vp.width - x) / 2;
324 y = (i + vp.height - MARGIN_BOTTOM - y) / 2;
325 display->putsxy(x, y, buf);
329 display->setfont(FONT_UI);
331 display->update_viewport();
332 display->set_viewport(NULL);
333 /* Be sure screen mode is reset */
334 set_drawinfo(display, DRMODE_SOLID, text_color, background_color);
337 #ifdef HAVE_TOUCHSCREEN
338 static int touchscreen_slider(struct rgb_pick *rgb, int *selected_slider)
340 short x,y;
341 int text_top,i,x1;
342 int slider_left, slider_width;
343 unsigned button = action_get_touchscreen_press(&x, &y);
344 bool display_three_rows;
345 int max_label_width;
346 struct screen *display = &screens[SCREEN_MAIN];
347 int pressed_slider;
348 char buf[2];
350 if (button == BUTTON_NONE)
351 return ACTION_NONE;
352 /* same logic as draw_screen */
353 /* Figure out widest label character in case they vary -
354 this function assumes labels are one character */
355 for (i = 0, max_label_width = 0; i < 3; i++)
357 buf[0] = str(LANG_COLOR_RGB_LABELS)[i];
358 buf[1] = '\0';
359 x1 = display->getstringsize(buf, NULL, NULL);
360 if (x1 > max_label_width)
361 max_label_width = x1;
363 /* Get slider positions and top starting position */
364 text_top = MARGIN_TOP + display->getcharheight() + TITLE_MARGIN_BOTTOM +
365 SELECTOR_TB_MARGIN;
366 slider_left = MARGIN_LEFT + SELECTOR_WIDTH + SELECTOR_LR_MARGIN +
367 max_label_width + SLIDER_MARGIN_LEFT;
368 slider_width = display->getwidth() - slider_left - SLIDER_MARGIN_RIGHT -
369 display->getcharwidth()*2 - SELECTOR_LR_MARGIN -
370 SELECTOR_WIDTH - MARGIN_RIGHT;
371 display_three_rows =
372 display->getheight() >=
373 MARGIN_TOP +
374 display->getcharheight()*4 + /* Title + 3 sliders */
375 TITLE_MARGIN_BOTTOM +
376 SELECTOR_TB_MARGIN*6 + /* 2 margins/slider */
377 MARGIN_BOTTOM;
378 if (y < MARGIN_TOP+display->getcharheight())
380 if (button == BUTTON_REL)
381 return ACTION_STD_CANCEL;
383 y -= text_top;
384 pressed_slider = y/display->getcharheight();
385 if (pressed_slider > (display_three_rows?2:0))
387 if (button == BUTTON_REL)
388 return ACTION_STD_OK;
390 if (pressed_slider != *selected_slider)
391 *selected_slider = pressed_slider;
392 if (x < slider_left+slider_width &&
393 x > slider_left)
395 x -= slider_left;
396 rgb->rgb_val[pressed_slider] =
397 (x*rgb_max[pressed_slider]/(slider_width-slider_left));
398 pack_rgb(rgb);
400 return ACTION_NONE;
402 #endif
403 /***********
404 set_color
405 returns true if USB was inserted, false otherwise
406 color is a pointer to the colour (in native format) to modify
407 set banned_color to -1 to allow all
408 ***********/
409 bool set_color(struct screen *display, char *title, unsigned *color,
410 unsigned banned_color)
412 int exit = 0, slider = 0;
413 struct rgb_pick rgb;
415 rgb.color = *color;
417 while (!exit)
419 int button;
421 unpack_rgb(&rgb);
423 if (display != NULL)
425 draw_screen(display, title, &rgb, slider);
427 else
429 int i;
430 FOR_NB_SCREENS(i)
431 draw_screen(&screens[i], title, &rgb, slider);
434 button = get_action(CONTEXT_SETTINGS_COLOURCHOOSER, TIMEOUT_BLOCK);
435 #ifdef HAVE_TOUCHSCREEN
436 if (button == ACTION_TOUCHSCREEN)
437 button = touchscreen_slider(&rgb, &slider);
438 #endif
440 switch (button)
442 case ACTION_STD_PREV:
443 case ACTION_STD_PREVREPEAT:
444 slider = (slider + 2) % 3;
445 break;
447 case ACTION_STD_NEXT:
448 case ACTION_STD_NEXTREPEAT:
449 slider = (slider + 1) % 3;
450 break;
452 case ACTION_SETTINGS_INC:
453 case ACTION_SETTINGS_INCREPEAT:
454 if (rgb.rgb_val[slider] < rgb_max[slider])
455 rgb.rgb_val[slider]++;
456 pack_rgb(&rgb);
457 break;
459 case ACTION_SETTINGS_DEC:
460 case ACTION_SETTINGS_DECREPEAT:
461 if (rgb.rgb_val[slider] > 0)
462 rgb.rgb_val[slider]--;
463 pack_rgb(&rgb);
464 break;
466 case ACTION_STD_OK:
467 if (banned_color != (unsigned)-1 &&
468 banned_color == rgb.color)
470 splash(HZ*2, ID2P(LANG_COLOR_UNACCEPTABLE));
471 break;
473 *color = rgb.color;
474 exit = 1;
475 break;
477 case ACTION_STD_CANCEL:
478 exit = 1;
479 break;
481 default:
482 if (default_event_handler(button) == SYS_USB_CONNECTED)
483 return true;
484 break;
488 return false;