foxygit / doom Log in
commit 165a20cf3e4cc4fbf22ee8754e50a557ad609ad6
Author:     Simon Howard <fraggle@gmail.com>
AuthorDate: Fri Sep 22 18:24:53 2006 +0000
Commit:     Simon Howard <fraggle@gmail.com>
CommitDate: Fri Sep 22 18:24:53 2006 +0000

    Add the ability to type in values for spin controls, like with normal
    input boxes.

    Subversion-branch: /trunk/chocolate-doom
    Subversion-revision: 651
---
 textscreen/txt_spinctrl.c | 156 +++++++++++++++++++++++++++++++++++++---------
 textscreen/txt_spinctrl.h |   2 +
 2 files changed, 128 insertions(+), 30 deletions(-)

diff --git a/textscreen/txt_spinctrl.c b/textscreen/txt_spinctrl.c
index 469d60d2..074adb07 100644
--- a/textscreen/txt_spinctrl.c
+++ b/textscreen/txt_spinctrl.c
@@ -37,43 +37,49 @@

 static int IntWidth(int val)
 {
-    if (val < 0)
-    {
-        return ((int) log(-val)) + 2;
-    }
-    else
-    {
-        return ((int) log(val)) + 1;
-    }
+    char buf[15];
+
+    sprintf(buf, "%i", val);
+
+    return strlen(buf);
 }

-static void TXT_SpinControlSizeCalc(TXT_UNCAST_ARG(spincontrol))
+// Returns the minimum width of the input box
+
+static int SpinControlWidth(txt_spincontrol_t *spincontrol)
 {
-    TXT_CAST_ARG(txt_spincontrol_t, spincontrol);
     int minw, maxw;
-    int w;

     minw = IntWidth(spincontrol->min);
     maxw = IntWidth(spincontrol->max);

+    // Choose the wider of the two values.  Add one so that there is always
+    // space for the cursor when editing.
+
     if (minw > maxw)
     {
-        w = minw;
+        return minw;
     }
     else
     {
-        w = maxw;
+        return maxw;
     }
+}
+
+static void TXT_SpinControlSizeCalc(TXT_UNCAST_ARG(spincontrol))
+{
+    TXT_CAST_ARG(txt_spincontrol_t, spincontrol);

-    spincontrol->widget.w = w + 4;
+    spincontrol->widget.w = SpinControlWidth(spincontrol) + 5;
     spincontrol->widget.h = 1;
 }

 static void TXT_SpinControlDrawer(TXT_UNCAST_ARG(spincontrol), int selected)
 {
     TXT_CAST_ARG(txt_spincontrol_t, spincontrol);
-    char buf[20];
+    char buf[15];
     unsigned int i;
+    unsigned int padding;

     TXT_FGColor(TXT_COLOR_BRIGHT_WHITE);
     TXT_BGColor(TXT_COLOR_BLUE, 0);
@@ -82,7 +88,11 @@ static void TXT_SpinControlDrawer(TXT_UNCAST_ARG(spincontrol), int selected)

     // Choose background color

-    if (selected)
+    if (selected && spincontrol->editing)
+    {
+        TXT_BGColor(TXT_COLOR_BLACK, 0);
+    }
+    else if (selected)
     {
         TXT_BGColor(TXT_COLOR_GREY, 0);
     }
@@ -91,14 +101,33 @@ static void TXT_SpinControlDrawer(TXT_UNCAST_ARG(spincontrol), int selected)
         TXT_BGColor(TXT_COLOR_BLUE, 0);
     }

-    sprintf(buf, "%i", *spincontrol->value);
+    if (spincontrol->editing)
+    {
+        strcpy(buf, spincontrol->buffer);
+    }
+    else
+    {
+        sprintf(buf, "%i", *spincontrol->value);
+    }
+
+    i = 0;

-    for (i=strlen(buf); i<spincontrol->widget.w - 4; ++i)
+    padding = spincontrol->widget.w - strlen(buf) - 4;
+
+    while (i < padding)
     {
         TXT_DrawString(" ");
+        ++i;
     }

     TXT_DrawString(buf);
+    i += strlen(buf);
+
+    while (i < spincontrol->widget.w - 4)
+    {
+        TXT_DrawString(" ");
+        ++i;
+    }

     TXT_BGColor(TXT_COLOR_BLUE, 0);
     TXT_DrawString(" >");
@@ -106,36 +135,100 @@ static void TXT_SpinControlDrawer(TXT_UNCAST_ARG(spincontrol), int selected)

 static void TXT_SpinControlDestructor(TXT_UNCAST_ARG(spincontrol))
 {
+    TXT_CAST_ARG(txt_spincontrol_t, spincontrol);
+
+    free(spincontrol->buffer);
+}
+
+static void AddCharacter(txt_spincontrol_t *spincontrol, int key)
+{
+    if (strlen(spincontrol->buffer) < SpinControlWidth(spincontrol))
+    {
+        spincontrol->buffer[strlen(spincontrol->buffer) + 1] = '\0';
+        spincontrol->buffer[strlen(spincontrol->buffer)] = key;
+    }
+}
+
+static void Backspace(txt_spincontrol_t *spincontrol)
+{
+    if (strlen(spincontrol->buffer) > 0)
+    {
+        spincontrol->buffer[strlen(spincontrol->buffer) - 1] = '\0';
+    }
+}
+
+static void EnforceLimits(txt_spincontrol_t *spincontrol)
+{
+    if (*spincontrol->value > spincontrol->max)
+        *spincontrol->value = spincontrol->max;
+    else if (*spincontrol->value < spincontrol->min)
+        *spincontrol->value = spincontrol->min;
 }

 static int TXT_SpinControlKeyPress(TXT_UNCAST_ARG(spincontrol), int key)
 {
     TXT_CAST_ARG(txt_spincontrol_t, spincontrol);

-    if (key == KEY_LEFTARROW)
+    // Enter to enter edit mode
+
+    if (spincontrol->editing)
     {
-        --*spincontrol->value;
+        if (key == KEY_ENTER)
+        {
+            *spincontrol->value = atoi(spincontrol->buffer);
+            spincontrol->editing = 0;
+            EnforceLimits(spincontrol);
+            return 1;
+        }

-        if (*spincontrol->value < spincontrol->min)
+        if (key == KEY_ESCAPE)
         {
-            *spincontrol->value = spincontrol->min;
+            // Abort without saving value
+            spincontrol->editing = 0;
+            return 1;
         }

-        return 1;
+        if (isdigit(key) || key == '-')
+        {
+            AddCharacter(spincontrol, key);
+            return 1;
+        }
+
+        if (key == KEY_BACKSPACE)
+        {
+            Backspace(spincontrol);
+            return 1;
+        }
     }
-
-    if (key == KEY_RIGHTARROW)
+    else
     {
-        ++*spincontrol->value;
+        // Non-editing mode

-        if (*spincontrol->value > spincontrol->max)
+        if (key == KEY_ENTER)
         {
-            *spincontrol->value = spincontrol->max;
+            sprintf(spincontrol->buffer, "%i", *spincontrol->value);
+            spincontrol->editing = 1;
+            return 1;
         }
+        if (key == KEY_LEFTARROW)
+        {
+            --*spincontrol->value;
+
+            EnforceLimits(spincontrol);

-        return 1;
+            return 1;
+        }
+
+        if (key == KEY_RIGHTARROW)
+        {
+            ++*spincontrol->value;
+
+            EnforceLimits(spincontrol);
+
+            return 1;
+        }
     }
-
+
     return 0;
 }

@@ -177,6 +270,9 @@ txt_spincontrol_t *TXT_NewSpinControl(int *value, int min, int max)
     spincontrol->value = value;
     spincontrol->min = min;
     spincontrol->max = max;
+    spincontrol->buffer = malloc(15);
+    strcpy(spincontrol->buffer, "");
+    spincontrol->editing = 0;

     return spincontrol;
 }
diff --git a/textscreen/txt_spinctrl.h b/textscreen/txt_spinctrl.h
index b0503d40..b3436ac7 100644
--- a/textscreen/txt_spinctrl.h
+++ b/textscreen/txt_spinctrl.h
@@ -31,6 +31,8 @@ struct txt_spincontrol_s
     txt_widget_t widget;
     int min, max;
     int *value;
+    int editing;
+    char *buffer;
 };

 txt_spincontrol_t *TXT_NewSpinControl(int *value, int min, int max);