From 4ac37f061a8a612a187d7c57093e5397e5aa7438 Mon Sep 17 00:00:00 2001
From: Ivica Ico Bukvic <ico@vt.edu>
Date: Fri, 18 Sep 2020 03:11:55 -0400
Subject: [PATCH] Bunch of additional refinements to the iemgui numbox

* Ability to edit incrementally with text and mouse (e.g. backspace erases only one digit)

* Better use of hte '>' as a cursor

* Key presses start a new number from scratch unless user has dragged a number and established a new number by dragging, or unless they shift+clicked when they gained focus on the numbox, in which case numbox will allow for user to append to the existing value

* Shift + backspace erases everything, while backspace erases only one character

* When there are no digits entered, the value reverts to 0

* Pressing return/enter removes the trailing '>' until a key is once again pressed

* Changing values with mouse also removes the trailing '>'

* Resizing across only x and y axes now works (vertical resize still inevitably affects the width due to change in character length, but it now never exceeds the x value it started with during that particular click'n'drag action)
---
 pd/nw/pdgui.js      |  2 +-
 pd/src/g_all_guis.h |  7 +++-
 pd/src/g_numbox.c   | 89 ++++++++++++++++++++++++++++++++++++---------
 3 files changed, 77 insertions(+), 21 deletions(-)

diff --git a/pd/nw/pdgui.js b/pd/nw/pdgui.js
index 4fcacc3d9..0d4e02b59 100644
--- a/pd/nw/pdgui.js
+++ b/pd/nw/pdgui.js
@@ -2964,7 +2964,7 @@ function gui_text_set (cid, tag, text) {
 
 function gui_text_set_mynumbox (cid, tag, text, active) {
     gui(cid).get_elem(tag + "text", function(e) {
-        //post("guit_text_set_activate " + tag + " " + text + " " + active);
+        //post("gui_text_set_mynumbox " + tag + " " + text + " " + active);
         text = text.trim();
         e.textContent = "";
         text_to_tspans(cid, e, text);
diff --git a/pd/src/g_all_guis.h b/pd/src/g_all_guis.h
index b40ac12fe..e978b67e9 100644
--- a/pd/src/g_all_guis.h
+++ b/pd/src/g_all_guis.h
@@ -190,9 +190,12 @@ typedef struct _my_numbox
     int      x_numwidth; // unsigned (width in pixels)
     int      x_scalewidth;  /* temporary value for scalehandle */
     int      x_scaleheight; /* temporary value for scalehandle */
+    int      x_yresize_x;   /* value of x when y resize started */
     int      x_tmpfontsize; /* temporary value for scalehandle */
-    int      x_num_fontsize; /* font size for the number only that should
-                                automatically adjust to the box size */
+    int      x_num_fontsize;/* font size for the number only that should
+                               automatically adjust to the box size */
+    int      x_focused;     /* helps us determine when and how we are editing value
+                               0 no focus, 1 keyboard focus, 2 mouse focus */
     int      x_log_height;
     int      x_drawstyle;  /* 0 default, 1 just frame, 2, just arrow, 3 number only */
 } t_my_numbox;
diff --git a/pd/src/g_numbox.c b/pd/src/g_numbox.c
index e668be5d2..d45bedacb 100644
--- a/pd/src/g_numbox.c
+++ b/pd/src/g_numbox.c
@@ -38,8 +38,11 @@ static void my_numbox_tick_reset(t_my_numbox *x)
     {
         //post("    success\n");
         my_numbox_set_change(x, 0);
+        my_numbox_ftoa(x);
         sys_queuegui(x, x->x_gui.x_glist, my_numbox_draw_update);
     }
+    glist_grab(x->x_gui.x_glist, 0, 0, 0, 0, 0);
+    x->x_focused = 0;
 }
 
 static void my_numbox_tick_wait(t_my_numbox *x)
@@ -158,11 +161,14 @@ static void my_numbox_draw_update(t_gobj *client, t_glist *glist)
     if (!glist_isvisible(glist)) return;
     if(x->x_gui.x_change && x->x_buf[0])
     {
-        //printf("draw_update 1\n");
+        //post("draw_update 1 : focused=%d", x->x_focused);
         char *cp=x->x_buf;
         int sl = strlen(x->x_buf);
-        x->x_buf[sl] = '>';
-        x->x_buf[sl+1] = 0;
+        if (x->x_focused == 1)
+        {
+            x->x_buf[sl] = '>';
+            x->x_buf[sl+1] = 0;
+        }
         if(sl >= x->x_gui.x_w)
             cp += sl - x->x_gui.x_w + 1;
         gui_vmess("gui_text_set_mynumbox", "xxsi",
@@ -174,7 +180,17 @@ static void my_numbox_draw_update(t_gobj *client, t_glist *glist)
     }
     else
     {
-        my_numbox_ftoa(x); /* mmm... side-effects */
+        //if (!x->x_focused || x->x_focused == 2)
+        //post("draw_update 2: x->x_buf=<%s> focused=%d change=%d", x->x_buf, x->x_focused, x->x_gui.x_change);
+        if (!x->x_buf[0] && x->x_focused == 1 && x->x_gui.x_change == 1)
+        {
+            x->x_buf[0] = '>';
+            x->x_buf[1] = 0;
+        }
+        else
+        {
+            my_numbox_ftoa(x); /* mmm... side-effects */
+        }
         gui_vmess("gui_text_set_mynumbox", "xxsi",
             glist_getcanvas(glist),
             x,
@@ -313,6 +329,7 @@ static void my_numbox__clickhook(t_scalehandle *sh, int newstate)
         canvas_apply_setundo(x->x_gui.x_glist, (t_gobj *)x);
         if (!sh->h_scale)
             scalehandle_click_label(sh);
+        x->x_yresize_x = 0;
     }
     /* not sure if we need this */
     sh->h_dragon = newstate;
@@ -324,8 +341,15 @@ static void my_numbox__motionhook(t_scalehandle *sh,
     if (sh->h_scale)
     {
         t_my_numbox *x = (t_my_numbox *)(sh->h_master);
+        x->x_focused = 2;
         //int dx = (int)mouse_x - sh->h_offset_x;
-        int dy = (int)mouse_y - sh->h_offset_y;
+        int dy = (sh->h_constrain == CURSOR_EDITMODE_RESIZE_X) ? 0 : 
+            (int)mouse_y - sh->h_offset_y;
+
+        if (sh->h_constrain == CURSOR_EDITMODE_RESIZE_Y && x->x_yresize_x == 0)
+        {
+            x->x_yresize_x = mouse_x;
+        }
 
         /* first calculate y */
         int newy = maxi(x->x_gui.x_obj.te_ypix + x->x_gui.x_h +
@@ -343,7 +367,8 @@ static void my_numbox__motionhook(t_scalehandle *sh,
         int char_w = (x->x_tmpfontsize * f) / 36;
 
         /* get the new total width */
-        int new_total_width = x->x_numwidth + (int)mouse_x -
+        int new_total_width = x->x_numwidth + 
+            (sh->h_constrain == CURSOR_EDITMODE_RESIZE_Y ? x->x_yresize_x : (int)mouse_x) -
             (text_xpix(&x->x_gui.x_obj, x->x_gui.x_glist) + x->x_numwidth);
 
         /* now figure out what does this translate into in terms of
@@ -574,6 +599,7 @@ static void my_numbox_dialog(t_my_numbox *x, t_symbol *s, int argc,
 
 static void my_numbox_motion(t_my_numbox *x, t_floatarg dx, t_floatarg dy)
 {
+    x->x_focused = 2;
     double k2=1.0;
     int old = x->x_val;
 
@@ -587,6 +613,7 @@ static void my_numbox_motion(t_my_numbox *x, t_floatarg dx, t_floatarg dy)
     if (old != x->x_val)
     {
         x->x_gui.x_changed = 1;
+        my_numbox_ftoa(x);
         sys_queuegui(x, x->x_gui.x_glist, my_numbox_draw_update);
         my_numbox_bang(x);
     }
@@ -597,7 +624,6 @@ static void my_numbox_motion(t_my_numbox *x, t_floatarg dx, t_floatarg dy)
 static void my_numbox_click(t_my_numbox *x, t_floatarg xpos, t_floatarg ypos,
                             t_floatarg shift, t_floatarg ctrl, t_floatarg alt)
 {
-	//post("my_numbox_click");
     glist_grab(x->x_gui.x_glist, &x->x_gui.x_obj.te_g,
         (t_glistmotionfn)my_numbox_motion, my_numbox_key, xpos, ypos);
 }
@@ -606,29 +632,32 @@ static int my_numbox_newclick(t_gobj *z, struct _glist *glist,
     int xpix, int ypix, int shift, int alt, int dbl, int doit)
 {
     t_my_numbox* x = (t_my_numbox *)z;
-    //post("my_numbox_newclick %d", doit);
     if(doit)
     {
         //printf("newclick doit\n");
         my_numbox_click( x, (t_floatarg)xpix, (t_floatarg)ypix,
             (t_floatarg)shift, 0, (t_floatarg)alt);
         if(shift)
+        {
             x->x_gui.x_finemoved = 1;
+        }
         else
             x->x_gui.x_finemoved = 0;
         if(!x->x_gui.x_change)
         {
-            //printf("    change=0\n");
             clock_delay(x->x_clock_wait, 50);
             my_numbox_set_change(x, 1);
             clock_delay(x->x_clock_reset, 3000);
 
-            x->x_buf[0] = 0;
+            if (shift)
+                my_numbox_ftoa(x);
+            else
+                x->x_buf[0] = 0;
+            x->x_focused = 2;
             sys_queuegui(x, x->x_gui.x_glist, my_numbox_draw_update);
         }
         else
         {
-            //printf("    change=1\n");
             my_numbox_set_change(x, 0);
             clock_unset(x->x_clock_reset);
             x->x_buf[0] = 0;
@@ -636,6 +665,10 @@ static int my_numbox_newclick(t_gobj *z, struct _glist *glist,
             sys_queuegui(x, x->x_gui.x_glist, my_numbox_draw_update);
         }
     }
+    else
+    {
+        //x->x_focused = 1;
+    }
     return (1);
 }
 
@@ -737,6 +770,8 @@ static void my_numbox_loadbang(t_my_numbox *x, t_floatarg action)
 static void my_numbox_key(void *z, t_floatarg fkey)
 {
     t_my_numbox *x = z;
+    if (fkey != 0)
+        x->x_focused = 1;
 
     // this is used for arrow up and down
     if (fkey == -1)
@@ -752,11 +787,14 @@ static void my_numbox_key(void *z, t_floatarg fkey)
     char buf[3];
     buf[1] = 0;
 
+    // this is what is triggered when one clicks outside the numbox
+    // and therefore loses focus
     if (c == 0)
     {
         my_numbox_set_change(x, 0);
         clock_unset(x->x_clock_reset);
         x->x_gui.x_changed = 1;
+        clock_delay(x->x_clock_reset, 0);
         sys_queuegui(x, x->x_gui.x_glist, my_numbox_draw_update);
         return;
     }
@@ -773,7 +811,11 @@ static void my_numbox_key(void *z, t_floatarg fkey)
     }
     else if((c=='\b')||(c==127))
     {
-        int sl=strlen(x->x_buf)-1;
+        int sl;
+        if (x->x_gui.x_finemoved)
+            sl = 0;
+        else
+            sl=strlen(x->x_buf)-1;
 
         if(sl < 0)
             sl = 0;
@@ -784,15 +826,23 @@ static void my_numbox_key(void *z, t_floatarg fkey)
     else if((c=='\n')||(c==13))
     {
         x->x_val = atof(x->x_buf);
-        x->x_buf[0] = 0;
+        //x->x_buf[0] = 0;
         my_numbox_set_change(x, 1);
         clock_unset(x->x_clock_reset);
         my_numbox_clip(x);
         my_numbox_bang(x);
         x->x_gui.x_changed = 1;
+        x->x_focused = 2;
         sys_queuegui(x, x->x_gui.x_glist, my_numbox_draw_update);
     }
-    clock_delay(x->x_clock_reset, 3000);
+
+    if(c==27)
+    {
+        clock_unset(x->x_clock_reset);
+        my_numbox_tick_reset(x);
+    }
+    else
+        clock_delay(x->x_clock_reset, 3000);
 }
 
 static void my_numbox_list(t_my_numbox *x, t_symbol *s, int ac, t_atom *av)
@@ -827,7 +877,7 @@ static void my_numbox_list(t_my_numbox *x, t_symbol *s, int ac, t_atom *av)
             if (!strcmp("Up", av[1].a_w.w_symbol->s_name))
             {
                 //fprintf(stderr,"...Up\n");
-                if(x->x_buf[0] == 0 && x->x_val != 0)
+                if((x->x_buf[0] == 0 || x->x_buf == '>') && x->x_val != 0)
                     sprintf(x->x_buf, "%g", x->x_val+1);
                 else
                     sprintf(x->x_buf, "%g", atof(x->x_buf) + 1);
@@ -836,7 +886,7 @@ static void my_numbox_list(t_my_numbox *x, t_symbol *s, int ac, t_atom *av)
             else if (!strcmp("ShiftUp", av[1].a_w.w_symbol->s_name))
             {
                 //fprintf(stderr,"...ShiftUp\n");
-                if(x->x_buf[0] == 0 && x->x_val != 0)
+                if((x->x_buf[0] == 0 || x->x_buf == '>') && x->x_val != 0)
                     sprintf(x->x_buf, "%g", x->x_val+0.01);
                 else
                     sprintf(x->x_buf, "%g", atof(x->x_buf) + 0.01);
@@ -845,7 +895,7 @@ static void my_numbox_list(t_my_numbox *x, t_symbol *s, int ac, t_atom *av)
             else if (!strcmp("Down", av[1].a_w.w_symbol->s_name))
             {
                 //fprintf(stderr,"...Down\n");
-                if(x->x_buf[0] == 0 && x->x_val != 0)
+                if((x->x_buf[0] == 0 || x->x_buf == '>') && x->x_val != 0)
                     sprintf(x->x_buf, "%g", x->x_val-1);
                 else
                     sprintf(x->x_buf, "%g", atof(x->x_buf) - 1);
@@ -854,7 +904,7 @@ static void my_numbox_list(t_my_numbox *x, t_symbol *s, int ac, t_atom *av)
             else if (!strcmp("ShiftDown", av[1].a_w.w_symbol->s_name))
             {
                 //fprintf(stderr,"...ShiftDown\n");
-                if(x->x_buf[0] == 0 && x->x_val != 0)
+                if((x->x_buf[0] == 0 || x->x_buf == '>') && x->x_val != 0)
                     sprintf(x->x_buf, "%g", x->x_val-0.01);
                 else
                     sprintf(x->x_buf, "%g", atof(x->x_buf) - 0.01);
@@ -943,6 +993,9 @@ static void *my_numbox_new(t_symbol *s, int argc, t_atom *argv)
     x->x_gui.legacy_x = 0;
     x->x_gui.legacy_y = 1;
 
+    x->x_focused = 0;
+    x->x_yresize_x = 0;
+
     return (x);
 }
 
-- 
GitLab