Foreground/Background colour settings.  Based on patch #3050 by Jonathan Gordon, extended my me.  The principle of the patch is that the three sliders contain the native ranges (currently 0..31, 0..63, 0..31), and the equivalent RGB888 colour is displayed underneath.  The config block (and global_settings struct) contain the native value for the fg/bg colours (either RGB565 or RGB565SWAPPED), but the text .cfg files contain the RGB888 value written as 6 hex digits.


git-svn-id: svn://svn.rockbox.org/rockbox/trunk@8840 a1c6a512-1295-4272-9138-f99709370657
diff --git a/apps/SOURCES b/apps/SOURCES
index ef65789..f34cac9 100644
--- a/apps/SOURCES
+++ b/apps/SOURCES
@@ -58,6 +58,7 @@
 recorder/widgets.c
 #ifdef HAVE_LCD_COLOR
 recorder/backdrop.c
+gui/color_picker.c
 #endif
 #endif
 #ifdef CONFIG_TUNER
diff --git a/apps/gui/color_picker.c b/apps/gui/color_picker.c
new file mode 100644
index 0000000..2f851d2
--- /dev/null
+++ b/apps/gui/color_picker.c
@@ -0,0 +1,261 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id: 
+ *
+ * Copyright (C) Jonathan Gordon (2006)
+ *
+ * All files in this archive are subject to the GNU General Public License.
+ * See the file COPYING in the source tree root for full license agreement.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#include "stdarg.h"
+#include "string.h"
+#include "stdio.h"
+#include "kernel.h"
+#include "system.h"
+#include "screen_access.h"
+#include "debug.h"
+#include "misc.h"
+#include "settings.h"
+#include "scrollbar.h"
+#include "lang.h"
+
+#define TEXT_MARGIN display->char_width+2
+#define SLIDER_START 20
+
+#if (CONFIG_KEYPAD == IRIVER_H300_PAD)
+#define SLIDER_UP        BUTTON_UP
+#define SLIDER_DOWN      BUTTON_DOWN
+#define SLIDER_LEFT      BUTTON_LEFT
+#define SLIDER_RIGHT     BUTTON_RIGHT
+#define SLIDER_OK        BUTTON_ON
+#define SLIDER_CANCEL    BUTTON_OFF
+
+#define SLIDER_RC_UP     BUTTON_RC_REW
+#define SLIDER_RC_DOWN   BUTTON_RC_FF
+#define SLIDER_RC_LEFT   BUTTON_RC_SOURCE
+#define SLIDER_RC_RIGHT  BUTTON_RC_BITRATE
+#define SLIDER_RC_OK     BUTTON_RC_ON
+#define SLIDER_RC_CANCEL BUTTON_RC_STOP
+
+#elif (CONFIG_KEYPAD == IPOD_4G_PAD)
+#define SLIDER_UP        BUTTON_LEFT
+#define SLIDER_DOWN      BUTTON_RIGHT
+#define SLIDER_LEFT      BUTTON_SCROLL_BACK
+#define SLIDER_RIGHT     BUTTON_SCROLL_FWD
+#define SLIDER_OK        BUTTON_SELECT
+#define SLIDER_CANCEL    BUTTON_MENU
+#endif
+
+static const int max_val[3] = {LCD_MAX_RED,LCD_MAX_GREEN,LCD_MAX_BLUE};
+
+static void draw_screen(struct screen *display, char *title, 
+                        int *rgb_val, int color, int row)
+{
+    int i;
+    char *textrgb = str(LANG_COLOR_RGB_LABELS), rgb_dummy[2] = {0,0};
+    int text_top;
+    int text_centre, bg_col;
+    char buf[32];
+    int slider_width = (display->width-SLIDER_START-(display->char_width*5));
+    int background_color = global_settings.bg_color;
+    int text_color = global_settings.fg_color;
+
+    display->clear_display();
+
+    if (display->depth > 1) {
+        display->set_foreground(text_color);
+    }
+
+    i = display->getstringsize(title,0,0);
+    display->putsxy((display->width-i)/2,6,title );
+    
+    for (i=0;i<3;i++)
+    {
+        text_top =display->char_height*((i*2)+2);
+        
+        if (i==row)
+        {
+            if (global_settings.invert_cursor)
+            {
+                display->fillrect(0,text_top-1,display->width,display->char_height+2);
+                bg_col = text_color;
+            }
+            else 
+            {
+                display->putsxy(0,text_top,">");
+                display->putsxy(display->width-TEXT_MARGIN,text_top,"<");
+                bg_col = background_color;
+            }
+            if (display->depth > 1)
+            {
+                if (i==0)
+                    display->set_foreground(LCD_RGBPACK(255, 0, 0));
+                else if (i==1)
+                    display->set_foreground(LCD_RGBPACK(0, 255, 0));
+                else if (i==2)
+                    display->set_foreground(LCD_RGBPACK(0 ,0 ,255));
+            }
+        }
+        else
+        { 
+            if (display->depth > 1)
+                display->set_foreground(text_color); 
+            bg_col = background_color;
+        }
+
+        if (display->depth > 1)
+            display->set_background(bg_col);
+
+        text_centre = text_top+(display->char_height/2);
+        rgb_dummy[0] = textrgb[i];
+        display->putsxy(TEXT_MARGIN,text_top,rgb_dummy);
+        snprintf(buf,3,"%02d",rgb_val[i]);
+        display->putsxy(display->width-(display->char_width*4),text_top,buf);
+        
+        text_top += display->char_height/4;
+     
+        gui_scrollbar_draw(display,SLIDER_START,text_top,slider_width,
+                           display->char_height/2,
+                           max_val[i],0,rgb_val[i],HORIZONTAL); 
+    }
+
+    if (display->depth > 1) {
+        display->set_background(background_color);
+        display->set_foreground(text_color);
+    }
+
+    if (text_top + (display->char_height*2) < (LCD_HEIGHT-40-display->char_height))
+        text_top += (display->char_height*2);
+    else text_top += (display->char_height);
+
+    /* Display RGB: #rrggbb */
+    snprintf(buf,sizeof(buf),str(LANG_COLOR_RGB_VALUE),
+                                 RGB_UNPACK_RED(color),
+                                 RGB_UNPACK_GREEN(color),
+                                 RGB_UNPACK_BLUE(color));
+
+    display->putsxy((LCD_WIDTH-(display->char_width*21))/2,text_top,buf);
+
+    if (display->depth > 1) {
+        display->set_foreground(color);
+        display->fillrect(SLIDER_START,LCD_HEIGHT-40,slider_width,35);
+
+        display->set_foreground(LCD_BLACK);
+        display->drawrect(SLIDER_START-1,LCD_HEIGHT-41,slider_width+2,37);
+    }
+
+    display->update();
+}
+
+/***********
+ set_color 
+ returns true if USB was inserted, false otherwise
+ color is a pointer to the colour (in native format) to modify
+ ***********/
+bool set_color(struct screen *display,char *title, int* color)
+{
+    int exit = 0, button, slider=0;
+    int rgb_val[3]; /* native depth r,g,b*/;
+    int fgcolor = display->get_foreground();
+    int newcolor = *color;
+    int i;
+
+#if LCD_PIXELFORMAT == RGB565
+    rgb_val[0] = ((*color)&0xf800) >> 11;
+    rgb_val[1] = ((*color)&0x07e0) >> 5;
+    rgb_val[2] = ((*color)&0x001f);
+#elif LCD_PIXELFORMAT == RGB565SWAPPED
+    rgb_val[0] = ((swap16(*color))&0xf800) >> 11;
+    rgb_val[1] = ((swap16(*color))&0x07e0) >> 5;
+    rgb_val[2] = ((swap16(*color))&0x001f);
+#endif
+
+    while (!exit)
+    {
+        /* We need to maintain three versions of the colour:
+
+           rgb_val[3] - the native depth RGB values
+           newcolor - the native format packed colour
+         */
+
+#if LCD_PIXELFORMAT == RGB565
+        newcolor = (rgb_val[0] << 11) | (rgb_val[1] << 5) | (rgb_val[2]);
+#elif LCD_PIXELFORMAT == RGB565SWAPPED
+        newcolor = swap16((rgb_val[0] << 11) | (rgb_val[1] << 5) | (rgb_val[2]));
+#endif
+        FOR_NB_SCREENS(i)
+            draw_screen(&screens[i], title, rgb_val, newcolor, slider);
+
+        button = button_get(true);
+        switch (button) 
+        {
+            case SLIDER_UP:
+#ifdef HAVE_LCD_REMOTE
+            case SLIDER_RC_UP:
+#endif
+                slider = (slider+2)%3;
+                break;
+
+            case SLIDER_DOWN:
+#ifdef HAVE_LCD_REMOTE
+            case SLIDER_RC_DOWN:
+#endif
+                slider = (slider+1)%3;
+                break;
+
+            case SLIDER_RIGHT:
+            case SLIDER_RIGHT|BUTTON_REPEAT:
+#ifdef HAVE_LCD_REMOTE
+            case SLIDER_RC_RIGHT:
+            case SLIDER_RC_RIGHT|BUTTON_REPEAT:
+#endif
+                if (rgb_val[slider] < max_val[slider])
+                    rgb_val[slider]++;
+                break;
+
+            case SLIDER_LEFT:
+            case SLIDER_LEFT|BUTTON_REPEAT:
+#ifdef HAVE_LCD_REMOTE
+            case SLIDER_RC_LEFT:
+            case SLIDER_RC_LEFT|BUTTON_REPEAT:
+#endif
+                if (rgb_val[slider] > 0)
+                    rgb_val[slider]--;
+                break;
+            
+            case SLIDER_OK:
+#ifdef HAVE_LCD_REMOTE
+            case SLIDER_RC_OK:
+#endif
+                *color = newcolor;
+                exit = 1;
+                break;
+
+            case SLIDER_CANCEL:
+#ifdef HAVE_LCD_REMOTE
+            case SLIDER_RC_CANCEL:
+#endif
+                exit = 1;
+                break;
+
+            default:
+                if(default_event_handler(button) == SYS_USB_CONNECTED) {
+                    display->set_foreground(fgcolor);
+                    return true;
+                }
+                break;
+        }
+    }
+    display->set_foreground(fgcolor);
+
+    return false;
+}
diff --git a/apps/gui/color_picker.h b/apps/gui/color_picker.h
new file mode 100644
index 0000000..1fa35f0
--- /dev/null
+++ b/apps/gui/color_picker.h
@@ -0,0 +1,25 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id$
+ *
+ * Copyright (C) Jonathan Gordon (2006)
+ *
+ * All files in this archive are subject to the GNU General Public License.
+ * See the file COPYING in the source tree root for full license agreement.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#include "screen_access.h"
+
+#ifdef HAVE_LCD_COLOR /* this file is a bit useless on non color lcds.. */
+
+bool set_color(struct screen *display,char *title, int* color);
+
+#endif
diff --git a/apps/gui/splash.h b/apps/gui/splash.h
index 9d8def1..b1ac15c 100644
--- a/apps/gui/splash.h
+++ b/apps/gui/splash.h
@@ -20,6 +20,7 @@
 #ifndef _GUI_SPLASH_H_
 #define _GUI_SPLASH_H_
 #include "screen_access.h"
+
 /*
  * Puts a splash message on the given screen for a given period
  *  - screen : the screen to put the splash on
diff --git a/apps/lang/english.lang b/apps/lang/english.lang
index dcb7c07..bd7973e 100644
--- a/apps/lang/english.lang
+++ b/apps/lang/english.lang
@@ -3748,3 +3748,33 @@
 eng: "Main and remote unit"
 voice: "Main and remote unit"
 new:
+
+id: LANG_COLOR_RGB_LABELS
+desc: what to show for the 'R' 'G' 'B' ONE LETTER EACH
+eng: "RGB"
+voice:
+new:
+
+id: LANG_COLOR_RGB_VALUE
+desc: in color screen
+eng: "RGB: %02X%02X%02X"
+voice:
+new:
+
+id: LANG_BACKGROUND_COLOR
+desc: menu entry to set the background color
+eng: "Background Colour"
+voice:
+new:
+
+id: LANG_FOREGROUND_COLOR
+desc: menu entry to set the foreground color
+eng: "Foreground Colour"
+voice:
+new:
+
+id: LANG_RESET_COLORS
+desc: menu
+eng: "Reset Colours"
+voice:
+new:
diff --git a/apps/plugin.c b/apps/plugin.c
index c9fb0ac..61396b4 100644
--- a/apps/plugin.c
+++ b/apps/plugin.c
@@ -515,7 +515,12 @@
 
 #ifdef HAVE_LCD_BITMAP
 #if LCD_DEPTH > 1
+#ifdef HAVE_LCD_COLOR
+    lcd_set_drawinfo(DRMODE_SOLID, global_settings.fg_color, 
+                                   global_settings.bg_color);
+#else
     lcd_set_drawinfo(DRMODE_SOLID, LCD_DEFAULT_FG, LCD_DEFAULT_BG);
+#endif
 #else /* LCD_DEPTH == 1 */
     lcd_set_drawmode(DRMODE_SOLID);
 #endif /* LCD_DEPTH */
diff --git a/apps/settings.c b/apps/settings.c
index 72939e5..5a42b17 100644
--- a/apps/settings.c
+++ b/apps/settings.c
@@ -89,7 +89,7 @@
 #include "dsp.h"
 #endif
 
-#define CONFIG_BLOCK_VERSION 36
+#define CONFIG_BLOCK_VERSION 37
 #define CONFIG_BLOCK_SIZE 512
 #define RTC_BLOCK_SIZE 44
 
@@ -122,7 +122,7 @@
     int default_val; /* min 15 bit */
     /* variable name in a .cfg file, NULL if not to be saved */
     const char* cfg_name;
-    /* set of values, or NULL for a numerical value */
+    /* set of values, "rgb" for a color, or NULL for a numerical value */
     const char* cfg_val;
 };
 
@@ -545,6 +545,10 @@
     {2, S_O(cliplight), 0, "cliplight", "off,main,both,remote" },
 #endif /* CONFIG_BACKLIGHT */
 #endif /*HAVE_RECORDING*/
+#ifdef HAVE_LCD_COLOR
+    {LCD_DEPTH,S_O(fg_color),LCD_DEFAULT_FG,"foreground color","rgb"}, 
+    {LCD_DEPTH,S_O(bg_color),LCD_DEFAULT_BG,"background color","rgb"}, 
+#endif
     /* If values are just added to the end, no need to bump the version. */
     /* new stuff to be added at the end */
 
@@ -596,6 +600,39 @@
     p[long_index] = (p[long_index] & ~mask) | (value << bit_index);
 }
 
+#ifdef HAVE_LCD_COLOR
+/*
+ * Helper function to convert a string of 6 hex digits to a native colour
+ */
+
+#define hex2dec(c) (((c) >= '0' && ((c) <= '9')) ? (toupper(c)) - '0' : \
+                                                   (toupper(c)) - 'A' + 10)
+
+int hex_to_rgb(const char* hex)
+{   int ok = 1;
+    int i;
+    int red, green, blue;
+
+    if (strlen(hex) == 6) {
+        for (i=0; i < 6; i++ ) {
+           if (!isxdigit(hex[i])) {
+              ok=0;
+              break;
+           }
+        }
+
+        if (ok) {
+            red = (hex2dec(hex[0]) << 4) | hex2dec(hex[1]);
+            green = (hex2dec(hex[2]) << 4) | hex2dec(hex[3]);
+            blue = (hex2dec(hex[4]) << 4) | hex2dec(hex[5]);
+            return LCD_RGBPACK(red,green,blue);
+        }
+    }
+
+    return 0;
+}
+#endif
+
 /*
  * Calculates the checksum for the config block and returns it
  */
@@ -1013,6 +1050,8 @@
     } else {
         lcd_set_backdrop(NULL);
     }
+    screens[SCREEN_MAIN].set_foreground(global_settings.fg_color);
+    screens[SCREEN_MAIN].set_background(global_settings.bg_color);
 #endif
 
 #if defined(HAVE_REMOTE_LCD) && (NB_SCREENS > 1)
@@ -1225,6 +1264,12 @@
             {   /* numerical value, just convert the string */
                 val = atoi(value);
             }
+#if HAVE_LCD_COLOR
+            else if (!strncasecmp(p_table[i].cfg_val,"rgb",4))
+            {
+                val = hex_to_rgb(value);
+            }
+#endif
             else
             {   /* set of string values, find the index */
                 const char* item;
@@ -1410,6 +1455,15 @@
         {
             fdprintf(fd, "%s: %ld\r\n", p_run->cfg_name, value);
         }
+#ifdef HAVE_LCD_COLOR
+        else if (!strcasecmp(p_run->cfg_val, "rgb"))
+        {
+            fdprintf(fd, "%s: %02x%02x%02x\r\n", p_run->cfg_name, 
+                                                 (int)RGB_UNPACK_RED(value),
+                                                 (int)RGB_UNPACK_GREEN(value),
+                                                 (int)RGB_UNPACK_BLUE(value));
+        }
+#endif
         else /* write as item */
         {
             const char* p = p_run->cfg_val;
@@ -1566,6 +1620,9 @@
     global_settings.lang_file[0] = '\0';
 #ifdef HAVE_LCD_COLOR
     global_settings.backdrop_file[0] = '\0';
+      
+    global_settings.fg_color = LCD_DEFAULT_FG;
+    global_settings.bg_color = LCD_DEFAULT_BG;
 #endif
 
 }
diff --git a/apps/settings.h b/apps/settings.h
index 753f067..87020a1 100644
--- a/apps/settings.h
+++ b/apps/settings.h
@@ -465,6 +465,10 @@
 
     bool warnon_erase_dynplaylist; /* warn when erasing dynamic playlist */
     bool scroll_paginated;   /* 0=dont 1=do */
+#ifdef HAVE_LCD_COLOR
+    int bg_color; /* background color native format */
+    int fg_color; /* foreground color native format */
+#endif
 };
 
 enum optiontype { INT, BOOL };
diff --git a/apps/settings_menu.c b/apps/settings_menu.c
index 6ac0b6f..d089960 100644
--- a/apps/settings_menu.c
+++ b/apps/settings_menu.c
@@ -54,6 +54,7 @@
 #include "splash.h"
 #include "yesno.h"
 #include "list.h"
+#include "color_picker.h"
 
 #ifdef HAVE_LCD_BITMAP
 #include "peakmeter.h"
@@ -319,6 +320,43 @@
     lcd_set_backdrop(NULL);
     return true;
 }
+
+/**
+ * Menu for fore/back colors
+ */
+static bool set_fg_color(void)
+{
+    bool res;
+
+    res = set_color(&screens[SCREEN_MAIN],str(LANG_FOREGROUND_COLOR),
+                    &global_settings.fg_color);
+
+    screens[SCREEN_MAIN].set_foreground(global_settings.fg_color);
+
+    return res;
+}
+
+static bool set_bg_color(void)
+{
+    bool res;
+
+    res = set_color(&screens[SCREEN_MAIN],str(LANG_BACKGROUND_COLOR),
+                    &global_settings.bg_color);
+
+    screens[SCREEN_MAIN].set_background(global_settings.bg_color);
+
+    return res;
+}
+
+static bool reset_color(void)
+{
+    global_settings.fg_color = LCD_DEFAULT_FG;
+    global_settings.bg_color = LCD_DEFAULT_BG;
+    
+    screens[SCREEN_MAIN].set_foreground(global_settings.fg_color);
+    screens[SCREEN_MAIN].set_background(global_settings.bg_color);
+    return false;
+}
 #endif
 
 /**
@@ -1586,6 +1624,9 @@
 #endif
 #ifdef HAVE_LCD_COLOR
         { ID2P(LANG_CLEAR_BACKDROP),   clear_main_backdrop },
+        { ID2P(LANG_BACKGROUND_COLOR), set_bg_color },
+        { ID2P(LANG_FOREGROUND_COLOR), set_fg_color },
+        { ID2P(LANG_RESET_COLORS),     reset_color },
 #endif
     };
 
diff --git a/firmware/export/lcd.h b/firmware/export/lcd.h
index ba0e216..6f7fef9 100644
--- a/firmware/export/lcd.h
+++ b/firmware/export/lcd.h
@@ -150,6 +150,9 @@
 #define LCD_MAX_RED    31
 #define LCD_MAX_GREEN  63
 #define LCD_MAX_BLUE   31
+#define _RGB_UNPACK_RED(x)   ((((x) >> 8) & 0xf8) | ((x) >> 13))
+#define _RGB_UNPACK_GREEN(x) ((((x) >> 3) & 0xfc) | (((x) >> 9) & 0x03))
+#define _RGB_UNPACK_BLUE(x)  ((((x) << 3) & 0xf8) | (((x) >> 2) & 0x07))
 #define _RGBPACK(r, g, b) ( ((((r) * (31*257) + (127*257)) >> 16) << 11) \
                            |((((g) * (63*257) + (127*257)) >> 16) << 5) \
                            | (((b) * (31*257) + (127*257)) >> 16))
@@ -158,8 +161,14 @@
 #if (LCD_PIXELFORMAT == RGB565SWAPPED)
 #define LCD_RGBPACK(r, g, b) ( ((_RGBPACK((r), (g), (b)) & 0xff00) >> 8) \
                               |((_RGBPACK((r), (g), (b)) & 0x00ff) << 8))
+#define RGB_UNPACK_RED(x)   _RGB_UNPACK_RED(swap16(x))
+#define RGB_UNPACK_GREEN(x) _RGB_UNPACK_GREEN(swap16(x))
+#define RGB_UNPACK_BLUE(x)  _RGB_UNPACK_BLUE(swap16(x)) 
 #else
 #define LCD_RGBPACK(r, g, b) _RGBPACK((r), (g), (b))
+#define RGB_UNPACK_RED(x)   _RGB_UNPACK_RED(x)
+#define RGB_UNPACK_GREEN(x) _RGB_UNPACK_GREEN(x)
+#define RGB_UNPACK_BLUE(x)  _RGB_UNPACK_BLUE(x) 
 #endif
 #elif LCD_DEPTH == 18
 #define LCD_MAX_RED    63