From fe168b6d6fadcce2dff1007c4a10c657b6fc8ee5 Mon Sep 17 00:00:00 2001
From: Ivica Ico Bukvic <ico@vt.edu>
Date: Wed, 2 Sep 2020 17:44:31 -0400
Subject: [PATCH] *added ability to edit g_numbox with arrows, shift+arrows,
 and made it highlight itself properly when being edited to provide
 appropriate visual feedback. Most of this was in 1.x when it was ported but
 was somehow lost. IIRC the same may need to be addressed for the vanilla
 numbox.

---
 pd/nw/css/default.css |   8 ++-
 pd/nw/pdgui.js        |  16 ++++++
 pd/src/g_numbox.c     | 124 ++++++++++++++++++++++++++++++++++++------
 3 files changed, 130 insertions(+), 18 deletions(-)

diff --git a/pd/nw/css/default.css b/pd/nw/css/default.css
index b58290b90..ed7dc50d4 100644
--- a/pd/nw/css/default.css
+++ b/pd/nw/css/default.css
@@ -316,10 +316,16 @@ p.msg::after {
 
 /* not sure what this is doing here... */
 text {
-    // fill: red;
+    //fill: red;
     //cursor: default;
 }
 
+/* not sure what this is doing here... */
+text.activated {
+    fill: red;
+    cursor: default;
+}
+
 /* not sure if this is still needed...
    updated the coloring just in case */
 .selected_border {
diff --git a/pd/nw/pdgui.js b/pd/nw/pdgui.js
index 880525bab..a9ad5b511 100644
--- a/pd/nw/pdgui.js
+++ b/pd/nw/pdgui.js
@@ -2670,6 +2670,22 @@ 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);
+        text = text.trim();
+        e.textContent = "";
+        text_to_tspans(cid, e, text);
+        if (active === 2) {
+            e.classList.remove("activated");
+        } else if (active === 1) {
+            e.classList.add("activated");
+        } else {
+            e.classList.remove("activated");           
+        }
+    });
+}
+
 function gui_text_redraw_border(cid, tag, width, height) {
     // Hm, need to figure out how to refactor to get rid of
     // configure_item call...
diff --git a/pd/src/g_numbox.c b/pd/src/g_numbox.c
index 80d3a66f9..4de6d1187 100644
--- a/pd/src/g_numbox.c
+++ b/pd/src/g_numbox.c
@@ -26,23 +26,40 @@ static void my_numbox_draw_update(t_gobj *client, t_glist *glist);
 t_widgetbehavior my_numbox_widgetbehavior;
 /*static*/ t_class *my_numbox_class;
 
+static t_symbol *numbox_keyname_sym_a;
+
 static void my_numbox_tick_reset(t_my_numbox *x)
 {
-    //printf("tick_reset\n");
+    //post("tick_reset\n");
     if(x->x_gui.x_change && x->x_gui.x_glist)
     {
-        //printf("    success\n");
-        x->x_gui.x_change = 0;
+        //post("    success\n");
+        my_numbox_set_change(x, 0);
         sys_queuegui(x, x->x_gui.x_glist, my_numbox_draw_update);
     }
 }
 
 static void my_numbox_tick_wait(t_my_numbox *x)
 {
-    //printf("tick_wait\n");
+    //post("tick_wait\n");
     sys_queuegui(x, x->x_gui.x_glist, my_numbox_draw_update);
 }
 
+// to enable ability to change values using arrow keys (only when focused)
+void my_numbox_set_change(t_my_numbox *x, t_floatarg f)
+{
+    if (f == 0 && x->x_gui.x_change != 0)
+    {
+        x->x_gui.x_change = 0;
+        pd_unbind(&x->x_gui.x_obj.ob_pd, numbox_keyname_sym_a);
+    }
+    else if (f == 1 && x->x_gui.x_change != 1)
+    {
+        x->x_gui.x_change = 1;
+        pd_bind(&x->x_gui.x_obj.ob_pd, numbox_keyname_sym_a);        
+    }
+}
+
 void my_numbox_clip(t_my_numbox *x)
 {
     if(x->x_val < x->x_min)
@@ -143,19 +160,23 @@ static void my_numbox_draw_update(t_gobj *client, t_glist *glist)
         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", "xxs",
+        gui_vmess("gui_text_set_mynumbox", "xxsi",
             glist_getcanvas(glist),
             x,
-            cp);
+            cp,
+            1);
         x->x_buf[sl] = 0;
     }
     else
     {
         my_numbox_ftoa(x); /* mmm... side-effects */
-        gui_vmess("gui_text_set", "xxs",
+        gui_vmess("gui_text_set_mynumbox", "xxsi",
             glist_getcanvas(glist),
             x,
-            x->x_buf);
+            x->x_buf,
+            x->x_gui.x_selected == glist_getcanvas(glist) && 
+                !x->x_gui.x_change && x->x_gui.x_glist == glist_getcanvas(glist) ?
+                2 : (x->x_gui.x_change ? 1 : 0));
         x->x_buf[0] = 0; /* mmm... more side-effects... no clue why we'd need
                             to mutate a struct member in order to draw stuff */
     }
@@ -253,7 +274,7 @@ static void my_numbox_draw_select(t_my_numbox *x, t_glist *glist)
     int issel = x->x_gui.x_selected == canvas && x->x_gui.x_glist == canvas;
     if(x->x_gui.x_selected && x->x_gui.x_change)
     {
-        x->x_gui.x_change = 0;
+        my_numbox_set_change(x, 0);
         clock_unset(x->x_clock_reset);
         x->x_buf[0] = 0;
         sys_queuegui(x, x->x_gui.x_glist, my_numbox_draw_update);
@@ -393,7 +414,7 @@ static void my_numbox_save(t_gobj *z, t_binbuf *b)
     iemgui_save(&x->x_gui, srl, bflcol);
     if(x->x_gui.x_change)
     {
-        x->x_gui.x_change = 0;
+        my_numbox_set_change(x, 0);
         clock_unset(x->x_clock_reset);
         x->x_gui.x_changed = 1;
         sys_queuegui(x, x->x_gui.x_glist, my_numbox_draw_update);
@@ -456,7 +477,7 @@ static void my_numbox_properties(t_gobj *z, t_glist *owner)
     iemgui_properties(&x->x_gui, srl);
     if(x->x_gui.x_change)
     {
-        x->x_gui.x_change = 0;
+        my_numbox_set_change(x, 0);
         clock_unset(x->x_clock_reset);
         x->x_gui.x_changed = 1;
         sys_queuegui(x, x->x_gui.x_glist, my_numbox_draw_update);
@@ -557,11 +578,13 @@ static void my_numbox_motion(t_my_numbox *x, t_floatarg dx, t_floatarg dy)
         my_numbox_bang(x);
     }
     clock_unset(x->x_clock_reset);
+    clock_delay(x->x_clock_reset, 3000);
 }
 
 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);
 }
@@ -570,7 +593,7 @@ 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");
@@ -584,15 +607,16 @@ static int my_numbox_newclick(t_gobj *z, struct _glist *glist,
         {
             //printf("    change=0\n");
             clock_delay(x->x_clock_wait, 50);
-            x->x_gui.x_change = 1;
+            my_numbox_set_change(x, 1);
             clock_delay(x->x_clock_reset, 3000);
 
             x->x_buf[0] = 0;
+            sys_queuegui(x, x->x_gui.x_glist, my_numbox_draw_update);
         }
         else
         {
             //printf("    change=1\n");
-            x->x_gui.x_change = 0;
+            my_numbox_set_change(x, 0);
             clock_unset(x->x_clock_reset);
             x->x_buf[0] = 0;
             x->x_gui.x_changed = 1;
@@ -700,13 +724,24 @@ 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;
+
+    // this is used for arrow up and down
+    if (fkey == -1)
+    {
+        clock_unset(x->x_clock_reset);
+        x->x_gui.x_changed = 1;
+        sys_queuegui(x, x->x_gui.x_glist, my_numbox_draw_update);
+        clock_delay(x->x_clock_reset, 3000);
+        return;
+    }
+
     char c=fkey;
     char buf[3];
     buf[1] = 0;
 
     if (c == 0)
     {
-        x->x_gui.x_change = 0;
+        my_numbox_set_change(x, 0);
         clock_unset(x->x_clock_reset);
         x->x_gui.x_changed = 1;
         sys_queuegui(x, x->x_gui.x_glist, my_numbox_draw_update);
@@ -737,7 +772,7 @@ static void my_numbox_key(void *z, t_floatarg fkey)
     {
         x->x_val = atof(x->x_buf);
         x->x_buf[0] = 0;
-        x->x_gui.x_change = 0;
+        my_numbox_set_change(x, 1);
         clock_unset(x->x_clock_reset);
         my_numbox_clip(x);
         my_numbox_bang(x);
@@ -749,11 +784,63 @@ static void my_numbox_key(void *z, t_floatarg fkey)
 
 static void my_numbox_list(t_my_numbox *x, t_symbol *s, int ac, t_atom *av)
 {
-    if (IS_A_FLOAT(av,0))
+    int i;
+    int isKey = 0;
+    t_floatarg val;
+
+    for (i=0; i < ac; i++)
+    {
+        if (!IS_A_FLOAT(av,i))
+        {
+            isKey = 1;
+            break;
+        }
+    }
+    if (!isKey)
     {
         my_numbox_set(x, atom_getfloatarg(0, ac, av));
         my_numbox_bang(x);
     }
+    else if (ac == 2 && x->x_gui.x_change == 1 && IS_A_FLOAT(av,0) && IS_A_SYMBOL(av,1) && av[0].a_w.w_float == 1)
+    {
+        fprintf(stderr,"got keyname %s while grabbed\n", av[1].a_w.w_symbol->s_name);
+        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)
+                sprintf(x->x_buf, "%g", x->x_val+1);
+            else
+                sprintf(x->x_buf, "%g", atof(x->x_buf) + 1);
+            my_numbox_key((void *)x, -1);
+        }
+        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)
+                sprintf(x->x_buf, "%g", x->x_val+0.01);
+            else
+                sprintf(x->x_buf, "%g", atof(x->x_buf) + 0.01);
+            my_numbox_key((void *)x, -1);
+        }
+        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)
+                sprintf(x->x_buf, "%g", x->x_val-1);
+            else
+                sprintf(x->x_buf, "%g", atof(x->x_buf) - 1);
+            my_numbox_key((void *)x, -1);
+        }
+        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)
+                sprintf(x->x_buf, "%g", x->x_val-0.01);
+            else
+                sprintf(x->x_buf, "%g", atof(x->x_buf) - 0.01);
+            my_numbox_key((void *)x, -1);
+        }
+    }
 }
 
 static void *my_numbox_new(t_symbol *s, int argc, t_atom *argv)
@@ -838,6 +925,7 @@ static void my_numbox_free(t_my_numbox *x)
 {
     if(iemgui_has_rcv(&x->x_gui))
         pd_unbind(&x->x_gui.x_obj.ob_pd, x->x_gui.x_rcv);
+    my_numbox_set_change(x, 0);
     clock_free(x->x_clock_reset);
     clock_free(x->x_clock_wait);
     gfxstub_deleteforkey(x);
@@ -881,6 +969,8 @@ void g_numbox_setup(void)
     class_addmethod(my_numbox_class, (t_method)my_numbox_hide_frame,
         gensym("hide_frame"), A_FLOAT, 0);
 
+    numbox_keyname_sym_a = gensym("#keyname_a");
+
     wb_init(&my_numbox_widgetbehavior,my_numbox_getrect,my_numbox_newclick);
     class_setwidget(my_numbox_class, &my_numbox_widgetbehavior);
     class_sethelpsymbol(my_numbox_class, gensym("numbox2"));
-- 
GitLab