1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
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 ****************************************************************************/
27 #include "screen_access.h"
32 #include "scrollbar.h"
37 #include "color_picker.h"
40 /* structure for color info */
43 unsigned color
; /* native color value */
46 unsigned char rgb_val
[6]; /* access to components as array */
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 */
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] =
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
)
140 for (i
= 0, max_width
= 0; i
< 3; i
++)
143 buf
[0] = str(LANG_COLOR_RGB_LABELS
)[i
];
145 width
= display
->getstringsize(buf
, NULL
, NULL
);
146 if (width
> 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
;
158 int i
, text_x
, y
, line_height
;
160 int slider_x
, slider_width
;
161 bool display_three_rows
;
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 */
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
;
210 set_drawinfo(display
, DRMODE_SOLID
, text_color
,
213 if (global_settings
.cursor_style
!= 0)
215 /* Draw solid bar selection bar */
217 text_top
- SELECTOR_TB_MARGIN
,
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
,
236 get_icon_width(display
->screen_type
),
240 if (display
->depth
>= 16)
242 sb_flags
|= FOREGROUND
| INNER_BGFILL
;
244 fg
= prim_rgb
[SB_PRIM
][i
];
245 bg
= prim_rgb
[SB_FILL
][i
];
248 else if (!display_three_rows
)
251 set_drawinfo(display
, mode
, fg
, bg
);
254 buf
[0] = str(LANG_COLOR_RGB_LABELS
)[i
];
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
);
264 gui_scrollbar_draw(display
, /* screen */
266 text_top
+ display
->getcharheight() / 4,/* y */
267 slider_width
, /* width */
268 display
->getcharheight() / 2, /* height */
269 rgb_max
[i
], /* items */
271 rgb
->rgb_val
[i
], /* max_shown */
272 sb_flags
); /* flags */
274 /* Advance to next line */
275 text_top
+= line_height
;
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
),
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
,
306 display
->drawrect(text_x
, top
, width
, height
);
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
,
334 int *selected_slider
)
337 int text_top
, slider_x
, slider_width
, title_height
;
339 bool display_three_rows
;
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
)
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
+
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 */
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 */
374 if (button
== BUTTON_REL
)
375 return ACTION_STD_CANCEL
;
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
) &&
396 computed_val
= (x
*rgb_max
[pressed_slider
]/(slider_width
));
397 rgb
->rgb_val
[pressed_slider
] =
398 MIN(computed_val
,rgb_max
[pressed_slider
]);
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
410 bool set_color(struct screen
*display
, char *title
, unsigned *color
,
411 unsigned banned_color
)
413 int exit
= 0, slider
= 0;
426 draw_screen(display
, title
, &rgb
, slider
);
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
);
444 case ACTION_STD_PREV
:
445 case ACTION_STD_PREVREPEAT
:
446 slider
= (slider
+ 2) % 3;
449 case ACTION_STD_NEXT
:
450 case ACTION_STD_NEXTREPEAT
:
451 slider
= (slider
+ 1) % 3;
454 case ACTION_SETTINGS_INC
:
455 case ACTION_SETTINGS_INCREPEAT
:
456 if (rgb
.rgb_val
[slider
] < rgb_max
[slider
])
457 rgb
.rgb_val
[slider
]++;
461 case ACTION_SETTINGS_DEC
:
462 case ACTION_SETTINGS_DECREPEAT
:
463 if (rgb
.rgb_val
[slider
] > 0)
464 rgb
.rgb_val
[slider
]--;
469 if (banned_color
!= (unsigned)-1 &&
470 banned_color
== rgb
.color
)
472 splash(HZ
*2, ID2P(LANG_COLOR_UNACCEPTABLE
));
479 case ACTION_STD_CANCEL
:
484 if (default_event_handler(button
) == SYS_USB_CONNECTED
)