Theme Editor: Committed FS#11477 to add a DECIMAL parameter type in the parser and adapt the Theme Editor to accomodate the change by Johnathan Gordon.  Fixed bug in the parser caused by the patch (error was thrown on zero value) and adapted tag rendering for new format

git-svn-id: svn://svn.rockbox.org/rockbox/trunk@27426 a1c6a512-1295-4272-9138-f99709370657
diff --git a/lib/skin_parser/skin_debug.c b/lib/skin_parser/skin_debug.c
index 00d09ae..4abe625 100644
--- a/lib/skin_parser/skin_debug.c
+++ b/lib/skin_parser/skin_debug.c
@@ -70,6 +70,9 @@
     case INT_EXPECTED:
         error_message =  "Expected integer";
         break;
+    case DECIMAL_EXPECTED:
+        error_message =  "Expected decimal";
+        break;
     case SEPERATOR_EXPECTED:
         error_message = "Expected argument seperator";
         break;
@@ -236,8 +239,13 @@
             printf("[%s]", params[i].data.text);
             break;
 
-        case NUMERIC:
-            printf("[%d]", params[i].data.numeric);
+        case INTEGER:
+            printf("[%d]", params[i].data.number);
+            break;
+            
+        case DECIMAL:
+            printf("[%d.%d]", params[i].data.number/10,
+                              params[i].data.number%10);
             break;
 
         case CODE:
diff --git a/lib/skin_parser/skin_parser.c b/lib/skin_parser/skin_parser.c
index 2ce41c6..5bc5984 100644
--- a/lib/skin_parser/skin_parser.c
+++ b/lib/skin_parser/skin_parser.c
@@ -23,6 +23,7 @@
 #include <stdio.h>
 #include <string.h>
 #include <ctype.h>
+#include <stdbool.h>
 
 #include "skin_buffer.h"
 #include "skin_parser.h"
@@ -534,7 +535,7 @@
         /* Storing the type code */
         element->params[i].type_code = *tag_args;
 
-        /* Checking a nullable argument for null */
+        /* Checking a nullable argument for null. */
         if(*cursor == DEFAULTSYM && !isdigit(cursor[1]))
         {
             if(islower(*tag_args))
@@ -557,8 +558,36 @@
                 return 0;
             }
 
-            element->params[i].type = NUMERIC;
-            element->params[i].data.numeric = scan_int(&cursor);
+            element->params[i].type = INTEGER;
+            element->params[i].data.number = scan_int(&cursor);
+        }
+        else if(tolower(*tag_args) == 'd')
+        {
+            int val = 0;
+            bool have_point = false;
+            bool have_tenth = false;
+            while ( isdigit(*cursor) || *cursor == '.' )
+            {
+                if (*cursor != '.')
+                {
+                    val *= 10;
+                    val += *cursor - '0';
+                    if (have_point)
+                    {
+                        have_tenth = true;
+                        cursor++;
+                        break;
+                    }
+                }
+                else
+                    have_point = true;
+                cursor++;
+            }
+            if (have_tenth == false)
+                val *= 10;
+
+            element->params[i].type = DECIMAL;
+            element->params[i].data.number = val;
         }
         else if(tolower(*tag_args) == 'n' ||
                 tolower(*tag_args) == 's' || tolower(*tag_args) == 'f')
diff --git a/lib/skin_parser/skin_parser.h b/lib/skin_parser/skin_parser.h
index 126a014..ad10f90 100644
--- a/lib/skin_parser/skin_parser.h
+++ b/lib/skin_parser/skin_parser.h
@@ -56,6 +56,7 @@
     UNEXPECTED_NEWLINE,
     INSUFFICIENT_ARGS,
     INT_EXPECTED,
+    DECIMAL_EXPECTED,
     SEPERATOR_EXPECTED,
     CLOSE_EXPECTED,
     MULTILINE_EXPECTED
@@ -66,7 +67,8 @@
 {
     enum
     {
-        NUMERIC,
+        INTEGER,
+        DECIMAL, /* stored in data.number as (whole*10)+part */
         STRING,
         CODE,
         DEFAULT
@@ -74,7 +76,7 @@
 
     union
     {
-        int numeric;
+        int number;
         char* text;
         struct skin_element* code;
     } data;
diff --git a/lib/skin_parser/tag_table.c b/lib/skin_parser/tag_table.c
index e0247ef..dd8df63 100644
--- a/lib/skin_parser/tag_table.c
+++ b/lib/skin_parser/tag_table.c
@@ -120,7 +120,7 @@
     { SKIN_TOKEN_REMOTE_HOLD,           "mr", "", 0 },
     { SKIN_TOKEN_REPEAT_MODE,           "mm", "", 0 },
     { SKIN_TOKEN_PLAYBACK_STATUS,       "mp", "", 0 },
-    { SKIN_TOKEN_BUTTON_VOLUME,         "mv", "|S", 0 },
+    { SKIN_TOKEN_BUTTON_VOLUME,         "mv", "|D", 0 },
     
     { SKIN_TOKEN_PEAKMETER,             "pm", "", 0 },
     { SKIN_TOKEN_PLAYER_PROGRESSBAR,    "pf", "", 0 },
@@ -131,8 +131,8 @@
     { SKIN_TOKEN_TRACK_TIME_ELAPSED,    "pc", "", 0 },
     { SKIN_TOKEN_TRACK_TIME_REMAINING,  "pr", "", 0 },
     { SKIN_TOKEN_TRACK_LENGTH,          "pt", "", 0 },
-    { SKIN_TOKEN_TRACK_STARTING,        "pS" , "|S", 0 },
-    { SKIN_TOKEN_TRACK_ENDING,          "pE" , "|S", 0 },
+    { SKIN_TOKEN_TRACK_STARTING,        "pS" , "|D", 0 },
+    { SKIN_TOKEN_TRACK_ENDING,          "pE" , "|D", 0 },
     { SKIN_TOKEN_PLAYLIST_POSITION,     "pp", "", 0 },
     { SKIN_TOKEN_PLAYLIST_ENTRIES,      "pe", "", 0 },
     { SKIN_TOKEN_PLAYLIST_NAME,         "pn", "", 0 },
@@ -161,7 +161,7 @@
     { SKIN_TOKEN_RDS_TEXT,              "tz", "", 0 },
     
     { SKIN_TOKEN_SUBLINE_SCROLL,        "s", "", 0 },
-    { SKIN_TOKEN_SUBLINE_TIMEOUT,       "t"  , "S", 0 },
+    { SKIN_TOKEN_SUBLINE_TIMEOUT,       "t"  , "D", 0 },
     
     { SKIN_TOKEN_ENABLE_THEME,          "we", "", NOBREAK },
     { SKIN_TOKEN_DISABLE_THEME,         "wd", "", NOBREAK },
@@ -196,7 +196,7 @@
     { SKIN_TOKEN_TRANSLATEDSTRING,      "Sx" , "S", 0 },
     { SKIN_TOKEN_LANG_IS_RTL,           "Sr" , "", 0 },
     
-    { SKIN_TOKEN_LASTTOUCH,             "Tl" , "|S", 0 },
+    { SKIN_TOKEN_LASTTOUCH,             "Tl" , "|D", 0 },
     { SKIN_TOKEN_CURRENT_SCREEN,        "cs", "", 0 },
     { SKIN_TOKEN_TOUCHREGION,           "T"  , "IIiiS", NOBREAK },
     
diff --git a/lib/skin_parser/tag_table.h b/lib/skin_parser/tag_table.h
index 149f148..f84d4ac 100644
--- a/lib/skin_parser/tag_table.h
+++ b/lib/skin_parser/tag_table.h
@@ -246,6 +246,9 @@
  *          characters for parameters are:
  *             I - Required integer
  *             i - Nullable integer
+ *             D - Required decimal 
+ *             d - Nullable decimal
+ *                  Decimals are stored as (whole*10)+part
  *             S - Required string
  *             s - Nullable string
  *             F - Required file name
diff --git a/utils/themeeditor/graphics/rbprogressbar.cpp b/utils/themeeditor/graphics/rbprogressbar.cpp
index 027520f..206a835 100644
--- a/utils/themeeditor/graphics/rbprogressbar.cpp
+++ b/utils/themeeditor/graphics/rbprogressbar.cpp
@@ -41,22 +41,22 @@
 
     if(paramCount > 0 && params[0].type != skin_tag_parameter::DEFAULT)
     {
-        x = params[0].data.numeric;
+        x = params[0].data.number;
     }
 
     if(paramCount > 1 && params[1].type != skin_tag_parameter::DEFAULT)
     {
-        y = params[1].data.numeric;
+        y = params[1].data.number;
     }
 
     if(paramCount > 2 && params[2].type != skin_tag_parameter::DEFAULT)
     {
-        w = params[2].data.numeric;
+        w = params[2].data.number;
     }
 
     if(paramCount > 3 && params[3].type != skin_tag_parameter::DEFAULT)
     {
-        h = params[3].data.numeric;
+        h = params[3].data.number;
     }
 
     if(paramCount > 4 && params[4].type != skin_tag_parameter::DEFAULT)
diff --git a/utils/themeeditor/graphics/rbviewport.cpp b/utils/themeeditor/graphics/rbviewport.cpp
index 96d7e8b..e9c58eb 100644
--- a/utils/themeeditor/graphics/rbviewport.cpp
+++ b/utils/themeeditor/graphics/rbviewport.cpp
@@ -97,24 +97,24 @@
             break;
         }
         /* Now we grab the info common to all viewports */
-        x = node->params[param++].data.numeric;
+        x = node->params[param++].data.number;
         if(x < 0)
             x = info.screen()->boundingRect().right() + x;
-        y = node->params[param++].data.numeric;
+        y = node->params[param++].data.number;
         if(y < 0)
             y = info.screen()->boundingRect().bottom() + y;
 
         if(node->params[param].type == skin_tag_parameter::DEFAULT)
             w = info.screen()->getWidth() - x;
         else
-            w = node->params[param].data.numeric;
+            w = node->params[param].data.number;
         if(w < 0)
             w = info.screen()->getWidth() + w - x;
 
         if(node->params[++param].type == skin_tag_parameter::DEFAULT)
             h = info.screen()->getHeight() - y;
         else
-            h = node->params[param].data.numeric;
+            h = node->params[param].data.number;
         if(h < 0)
             h = info.screen()->getHeight() + h - y;
 
@@ -128,7 +128,7 @@
         if(node->params[++param].type == skin_tag_parameter::DEFAULT)
             font = screen->getFont(1);
         else
-            font = screen->getFont(node->params[param].data.numeric);
+            font = screen->getFont(node->params[param].data.number);
 
         setPos(x, y);
         size = QRectF(0, 0, w, h);
diff --git a/utils/themeeditor/gui/devicestate.cpp b/utils/themeeditor/gui/devicestate.cpp
index 89985bf..e766a64 100644
--- a/utils/themeeditor/gui/devicestate.cpp
+++ b/utils/themeeditor/gui/devicestate.cpp
@@ -225,7 +225,7 @@
         QString path = tag[0].isLower()
                        ? data("file").toString() : data("nextfile").toString();
         if(paramCount > 0)
-            return directory(path, params[0].data.numeric);
+            return directory(path, params[0].data.number);
         else
             return QVariant();
     }
@@ -255,7 +255,7 @@
     else if(tag == "pS")
     {
         double threshhold = paramCount > 0
-                            ? std::atof(params[0].data.text) : 10;
+                            ? params[0].data.number / 10. : 10;
         if(data("?pc").toDouble() <= threshhold)
             return true;
         else
@@ -264,7 +264,7 @@
     else if(tag == "pE")
     {
         double threshhold = paramCount > 0
-                            ? std::atof(params[0].data.text) : 10;
+                            ? params[0].data.number / 10. : 10;
         if(data("?pt").toDouble() - data("?pc").toDouble() <= threshhold)
             return true;
         else
diff --git a/utils/themeeditor/models/parsetreemodel.cpp b/utils/themeeditor/models/parsetreemodel.cpp
index a04a0d9..66c9621 100644
--- a/utils/themeeditor/models/parsetreemodel.cpp
+++ b/utils/themeeditor/models/parsetreemodel.cpp
@@ -246,8 +246,8 @@
             if(!value.canConvert(QVariant::Int))
                 return false;
 
-            param->type = skin_tag_parameter::NUMERIC;
-            param->data.numeric = value.toInt();
+            param->type = skin_tag_parameter::INTEGER;
+            param->data.number = value.toInt();
         }
         else
         {
diff --git a/utils/themeeditor/models/parsetreenode.cpp b/utils/themeeditor/models/parsetreenode.cpp
index 1b894b7..fbb7b92 100644
--- a/utils/themeeditor/models/parsetreenode.cpp
+++ b/utils/themeeditor/models/parsetreenode.cpp
@@ -246,8 +246,12 @@
             }
             break;
 
-        case skin_tag_parameter::NUMERIC:
-            buffer.append(QString::number(param->data.numeric, 10));
+        case skin_tag_parameter::INTEGER:
+            buffer.append(QString::number(param->data.number, 10));
+            break;
+
+        case skin_tag_parameter::DECIMAL:
+            buffer.append(QString::number(param->data.number / 10., 'f', 1));
             break;
 
         case skin_tag_parameter::DEFAULT:
@@ -318,8 +322,8 @@
         case skin_tag_parameter::CODE:
             break;
 
-        case skin_tag_parameter::NUMERIC:
-            hash += param->data.numeric * (param->data.numeric / 4);
+        case skin_tag_parameter::INTEGER:
+            hash += param->data.number * (param->data.number / 4);
             break;
 
         case skin_tag_parameter::STRING:
@@ -331,6 +335,10 @@
                     hash += param->data.text[i];
             }
             break;
+
+        case skin_tag_parameter::DECIMAL:
+            hash += param->data.number;
+            break;
         }
     }
 
@@ -396,8 +404,11 @@
             case skin_tag_parameter::STRING:
                 return QObject::tr("String");
 
-            case skin_tag_parameter::NUMERIC:
-                return QObject::tr("Number");
+            case skin_tag_parameter::INTEGER:
+                return QObject::tr("Integer");
+
+            case skin_tag_parameter::DECIMAL:
+                return QObject::tr("Decimal");
 
             case skin_tag_parameter::DEFAULT:
                 return QObject::tr("Default Argument");
@@ -445,11 +456,15 @@
             case skin_tag_parameter::STRING:
                 return QString(param->data.text);
 
-            case skin_tag_parameter::NUMERIC:
-                return QString::number(param->data.numeric, 10);
+            case skin_tag_parameter::INTEGER:
+                return QString::number(param->data.number, 10);
+
+            case skin_tag_parameter::DECIMAL:
+                return QString::number(param->data.number / 10., 'f', 1);
 
             case skin_tag_parameter::CODE:
                 return QObject::tr("Seriously, something's wrong here");
+
             }
         }
         else
@@ -742,10 +757,10 @@
             id = element->params[0].data.text;
             filename = info.settings()->value("imagepath", "") + "/" +
                        element->params[1].data.text;
-            x = element->params[2].data.numeric;
-            y = element->params[3].data.numeric;
+            x = element->params[2].data.number;
+            y = element->params[3].data.number;
             if(element->params_count > 4)
-                tiles = element->params[4].data.numeric;
+                tiles = element->params[4].data.number;
             else
                 tiles = 1;
 
@@ -758,8 +773,8 @@
             id = element->params[0].data.text;
             filename = info.settings()->value("imagepath", "") + "/" +
                        element->params[1].data.text;
-            x = element->params[2].data.numeric;
-            y = element->params[3].data.numeric;
+            x = element->params[2].data.number;
+            y = element->params[3].data.number;
             image = new RBImage(filename, 1, x, y, viewport);
             info.screen()->loadImage(id, new RBImage(filename, 1, x, y,
                                                      viewport));
@@ -780,10 +795,10 @@
 
         case 'l':
             /* %Cl */
-            x = element->params[0].data.numeric;
-            y = element->params[1].data.numeric;
-            maxWidth = element->params[2].data.numeric;
-            maxHeight = element->params[3].data.numeric;
+            x = element->params[0].data.number;
+            y = element->params[1].data.number;
+            maxWidth = element->params[2].data.number;
+            maxHeight = element->params[3].data.number;
             hAlign = element->params_count > 4
                      ? element->params[4].data.text[0] : 'c';
             vAlign = element->params_count > 5
@@ -805,7 +820,7 @@
 
         case 'l':
             /* %Fl */
-            x = element->params[0].data.numeric;
+            x = element->params[0].data.number;
             filename = info.settings()->value("themebase", "") + "/fonts/" +
                        element->params[1].data.text;
             info.screen()->loadFont(x, new RBFont(filename));
@@ -822,10 +837,10 @@
             /* %T */
             if(element->params_count < 5)
                 return false;
-            int x = element->params[0].data.numeric;
-            int y = element->params[1].data.numeric;
-            int width = element->params[2].data.numeric;
-            int height = element->params[3].data.numeric;
+            int x = element->params[0].data.number;
+            int y = element->params[1].data.number;
+            int width = element->params[2].data.number;
+            int height = element->params[3].data.number;
             QString action(element->params[4].data.text);
             RBTouchArea* temp = new RBTouchArea(width, height, action, info);
             temp->setPos(x, y);
@@ -863,7 +878,7 @@
 
         case 'p':
             /* %Vp */
-            viewport->showPlaylist(info, element->params[0].data.numeric,
+            viewport->showPlaylist(info, element->params[0].data.number,
                                    element->params[1].data.code,
                                    element->params[2].data.code);
             return true;
@@ -1016,7 +1031,7 @@
             if(current->element->tag->name[0] == 't'
                && current->element->tag->name[1] == '\0')
             {
-                retval = atof(current->element->params[0].data.text);
+                retval = current->element->params[0].data.number / 10.;
             }
         }
         else if(current->element->type == CONDITIONAL)