diff --git a/pd/nw/css/default.css b/pd/nw/css/default.css index d76e661fce202a739d08750def40f4183004bfd6..3765429754444ed40f92dfc3faedf3bbda609ec6 100644 --- a/pd/nw/css/default.css +++ b/pd/nw/css/default.css @@ -373,7 +373,7 @@ text.activated { } /* gatom "activated" text (i.e., when it has the keyboard focus) */ -.atom.activated text { +.atom.activated .data { fill: red; } diff --git a/pd/nw/pdgui.js b/pd/nw/pdgui.js index ced02db29df81c16a28bf689e0f9756cb40a8575..c358b3271508f7143549df7ebb0b43e39b65fd28 100644 --- a/pd/nw/pdgui.js +++ b/pd/nw/pdgui.js @@ -2654,7 +2654,20 @@ function gobj_font_y_kludge(fontsize) { function gui_text_new(cid, tag, type, isselected, left_margin, font_height, text, font) { //ico@vt.edu: different text spacing for GOPs + //post("gui_text_new type=" + type + " tag=" + tag); var xoff = 0.5; // Default value for normal objects, GOP uses -0.5 + /* ico@vt.edu 20200907: the following id_suffix is used for gatom objects. + When activated, they tend to highlight both the label and the gatom contents + since prior to this there was no differentiation between the two in terms of + their tags. However, g_rtext.c instantiates gatom contents with type "atom" + whereas the label inside g_text.c is instantiated as "gatom". We use this + difference here to provide the two with different tag names, so that we can + prevent the label from being also "activated" (e.g. when user clicks on the + gatom to edit its contents in non-edit mode). */ + var classname = "box_text"; + if (type === "atom") { + classname = "box_text data"; + } gui(cid).get_gobj(tag, function(e) { xoff = e.classList.contains("graph") ? -0.5 : 0.5; }); @@ -2686,7 +2699,7 @@ function gui_text_new(cid, tag, type, isselected, left_margin, font_height, text "font-size": pd_fontsize_to_gui_fontsize(font) + "px", "font-weight": "normal", id: tag + "text", - "class": "box_text" + "class": classname }); // trim off any extraneous leading/trailing whitespace. Because of // the way binbuf_gettext works we almost always have a trailing @@ -5459,6 +5472,7 @@ function gui_gatom_dialog(did, attr_array) { } function gui_gatom_activate(cid, tag, state) { + //post("gui_gatom_activate tag=" + tag + " state=" + state); gui(cid).get_gobj(tag, function(e) { if (state !== 0) { e.classList.add("activated"); diff --git a/pd/src/g_text.c b/pd/src/g_text.c index afe89e91956e0d72e4584c3ce55a10b2a4775dd9..f57025930c7bd7ac1c653d83cc1dbb2dd62f22dc 100644 --- a/pd/src/g_text.c +++ b/pd/src/g_text.c @@ -866,18 +866,22 @@ void canvas_msg(t_glist *gl, t_symbol *s, int argc, t_atom *argv) typedef struct _gatom { t_text a_text; - t_atom a_atom; /* this holds the value and the type */ - t_glist *a_glist; /* owning glist */ - t_float a_toggle; /* value to toggle to */ - t_float a_draghi; /* high end of drag range */ - t_float a_draglo; /* low end of drag range */ - t_symbol *a_label; /* symbol to show as label next to box */ - t_symbol *a_symfrom; /* "receive" name -- bind ourselvs to this */ - t_symbol *a_symto; /* "send" name -- send to this on output */ - char a_buf[ATOMBUFSIZE];/* string buffer for typing */ - char a_shift; /* was shift key down when dragging started? */ - char a_wherelabel; /* 0-3 for left, right, above, below */ + t_atom a_atom; /* this holds the value and the type */ + t_atom a_atomold; /* this holds old value, used to reverting to + when changing the number value using arrows */ + t_glist *a_glist; /* owning glist */ + t_float a_toggle; /* value to toggle to */ + t_float a_draghi; /* high end of drag range */ + t_float a_draglo; /* low end of drag range */ + t_symbol *a_label; /* symbol to show as label next to box */ + t_symbol *a_symfrom; /* "receive" name -- bind ourselvs to this */ + t_symbol *a_symto; /* "send" name -- send to this on output */ + char a_buf[ATOMBUFSIZE]; /* string buffer for typing */ + char a_shift; /* was shift key down when dragging started? */ + char a_wherelabel; /* 0-3 for left, right, above, below */ t_symbol *a_expanded_to; /* a_symto after $0, $1, ... expansion */ + int a_shift_clicked; /* used to keep old text after \n. this is + activated by shift+clicking no the object */ } t_gatom; /* prepend "-" as necessary to avoid empty strings, so we can @@ -913,16 +917,20 @@ static void gatom_redraw(t_gobj *client, t_glist *glist) glist_retext(x->a_glist, &x->a_text); } - /* recolor option offers 0 ignore recolor + /* recolor option offers 0 ignore recolor 1 recolor */ static void gatom_retext(t_gatom *x, int senditup, int recolor) { + //post("gatom_retext senditup=%d recolor=%d", senditup, recolor); t_canvas *canvas = glist_getcanvas(x->a_glist); t_rtext *y = glist_findrtext(x->a_glist, &x->a_text); if (recolor) { + //post("gatom click off"); gui_vmess("gui_gatom_activate", "xsi", canvas, rtext_gettag(y), 0); + x->a_shift_clicked = 0; + x->a_shift = 0; } binbuf_clear(x->a_text.te_binbuf); binbuf_add(x->a_text.te_binbuf, 1, &x->a_atom); @@ -947,8 +955,14 @@ static void gatom_set(t_gatom *x, t_symbol *s, int argc, t_atom *argv) gatom_retext(x, 1, 1); else gatom_retext(x, 1, 0); + x->a_atomold = x->a_atom; + } + if (x->a_atom.a_type == A_FLOAT) + { + x->a_buf[0] = 0; + } else { + strcpy(x->a_buf, x->a_atom.a_w.w_symbol->s_name); } - x->a_buf[0] = 0; } static void gatom_bang(t_gatom *x) @@ -1013,12 +1027,59 @@ static void gatom_symbol(t_gatom *x, t_symbol *s) "nofirstin" flag, the standard list behavior gets confused. */ static void gatom_list(t_gatom *x, t_symbol *s, int argc, t_atom *argv) { + //post("gatom_list <%s>", s->s_name); if (!argc) gatom_bang(x); - else if (argv->a_type == A_FLOAT) - gatom_float(x, argv->a_w.w_float); - else if (argv->a_type == A_SYMBOL) - gatom_symbol(x, argv->a_w.w_symbol); + else if (argc == 1) + { + if (argv->a_type == A_FLOAT) + gatom_float(x, argv->a_w.w_float); + else if (argv->a_type == A_SYMBOL) + gatom_symbol(x, argv->a_w.w_symbol); + } + /* ico@vt.edu 20200904 like g_numbox.c, here we hijack list to capture + keyname keypresses, so that we can use shift+backspace to delete + entire text */ + else if (argc == 2 && argv[0].a_type == A_FLOAT && argv[1].a_type == A_SYMBOL) + { + //post("got keyname %s while grabbed\n", argv[1].a_w.w_symbol->s_name); + if (!strcmp("Shift", argv[1].a_w.w_symbol->s_name)) + { + x->a_shift = (int)argv[0].a_w.w_float; + //post("...Shift %d", x->a_shift); + } + if (x->a_atom.a_type == A_FLOAT && argv[0].a_w.w_float == 1) + { + if (!strcmp("Up", argv[1].a_w.w_symbol->s_name)) + { + //fprintf(stderr,"...Up\n"); + x->a_atom.a_w.w_float += 1; + //sprintf(x->a_buf, "%g", x->a_atom.a_w.w_float); + gatom_retext(x, 1, 0); + } + else if (!strcmp("ShiftUp", argv[1].a_w.w_symbol->s_name)) + { + //fprintf(stderr,"...ShiftUp\n"); + x->a_atom.a_w.w_float += 0.01; + //sprintf(x->a_buf, "%g", x->a_atom.a_w.w_float); + gatom_retext(x, 1, 0); + } + if (!strcmp("Down", argv[1].a_w.w_symbol->s_name)) + { + //fprintf(stderr,"...Down\n"); + x->a_atom.a_w.w_float -= 1; + //sprintf(x->a_buf, "%g", x->a_atom.a_w.w_float); + gatom_retext(x, 1, 0); + } + else if (!strcmp("ShiftDown", argv[1].a_w.w_symbol->s_name)) + { + //fprintf(stderr,"...ShiftDown\n"); + x->a_atom.a_w.w_float -= 0.01; + //sprintf(x->a_buf, "%g", x->a_atom.a_w.w_float); + gatom_retext(x, 1, 0); + } + } + } else pd_error(x, "gatom_list: need float or symbol"); } @@ -1049,37 +1110,85 @@ static void gatom_motion(void *z, t_floatarg dx, t_floatarg dy) static void gatom_key(void *z, t_floatarg f) { - //fprintf(stderr,"gatom_key %f\n", f); t_gatom *x = (t_gatom *)z; int c = f; + //post("gatom_key <%c> %d", c, x->a_shift); int len = strlen(x->a_buf); t_atom at; char sbuf[ATOMBUFSIZE + 4]; if (c == 0) { - /* we're being notified that no more keys will come for this grab */ - if (x->a_buf[0]) + // we're being notified that no more keys will come for this grab + //post("gatom_key end <%s> <%s>", x->a_buf, x->a_atom.a_w.w_symbol->s_name); + pd_unbind(&x->a_text.ob_pd, gensym("#keyname_a")); + //post("unbind <%s>", x->a_buf); + if (x->a_atom.a_type == A_FLOAT) + { + x->a_atom = x->a_atomold; + //if (x->a_buf[0]) x->a_atom.a_w.w_float = atof(x->a_buf); + //sprintf(x->a_buf, "%f", x->a_atom.a_w.w_float); + //post("got float f=<%f> s=<%s>", x->a_atom.a_w.w_float, x->a_buf); + + // ico@vt.edu 20200904: + // we reset internal buffer since there is currently no graceful way + // to handle conversion from float to string and back without loss + // in the value accuracy + x->a_buf[0] = 0; gatom_retext(x, 1, 1); - else - gatom_retext(x, 0, 1); + } + else if (x->a_atom.a_type == A_SYMBOL) + { + //post("gatom_key release"); + if (strcmp(x->a_buf, x->a_atom.a_w.w_symbol->s_name)) + { + strcpy(x->a_buf, x->a_atom.a_w.w_symbol->s_name); + gatom_retext(x, 1, 1); + //post("gatom_key buf=<%s> s_name=<%s>", x->a_buf, + // x->a_atom.a_w.w_symbol->s_name); + } + else + gatom_retext(x, 0, 1); + } return; } else if (c == '\b') { if (len > 0) - x->a_buf[len-1] = 0; + { + if (x->a_shift) + x->a_buf[0] = 0; + else + x->a_buf[len-1] = 0; + } goto redraw; } else if (c == '\n') { - if (x->a_atom.a_type == A_FLOAT) - x->a_atom.a_w.w_float = atof(x->a_buf); + if (x->a_atom.a_type == A_FLOAT) { + if (x->a_buf[0]) x->a_atom.a_w.w_float = atof(x->a_buf); + //sprintf(x->a_buf, "%f", x->a_atom.a_w.w_float); + //post("got float f=<%f> s=<%s>", x->a_atom.a_w.w_float, x->a_buf); + + // ico@vt.edu 20200904: + // we reset internal buffer since there is currently no graceful way + // to handle conversion from float to string and back without loss + // in the value accuracy + x->a_buf[0] = 0; + } else if (x->a_atom.a_type == A_SYMBOL) - x->a_atom.a_w.w_symbol = gensym(x->a_buf); + x->a_atom.a_w.w_symbol = gensym(x->a_buf); else bug("gatom_key"); + + x->a_atomold = x->a_atom; gatom_bang(x); gatom_retext(x, 1, 0); - x->a_buf[0] = 0; + /* ico@vt.edu 20200904: We prevent deleting of internal buffer, + so that we can keep adding to the existing text unless we click + the second time in which case we will always start with an + empty symbol + */ + if (!x->a_shift_clicked) + x->a_buf[0] = 0; /* We want to keep grabbing the keyboard after hitting "Enter", so we're commenting the following out */ //glist_grab(x->a_glist, 0, 0, 0, 0, 0); @@ -1124,6 +1233,9 @@ static void gatom_click(t_gatom *x, t_floatarg xpos, t_floatarg ypos, t_floatarg shift, t_floatarg ctrl, t_floatarg alt) { + //post("gatom_click %f %f", ctrl, alt); + pd_bind(&x->a_text.ob_pd, gensym("#keyname_a")); + //post("bind"); if (x->a_text.te_width == 1) { if (x->a_atom.a_type == A_FLOAT) @@ -1144,9 +1256,14 @@ static void gatom_click(t_gatom *x, return; } x->a_shift = shift; - x->a_buf[0] = 0; - glist_grab(x->a_glist, &x->a_text.te_g, gatom_motion, gatom_key, - xpos, ypos); + glist_grab(x->a_glist, &x->a_text.te_g, gatom_motion, gatom_key, + xpos, ypos); + //post("a_shift_clicked=%d", x->a_shift_clicked); + x->a_shift_clicked = shift; + // second click wipes prior text + if (!x->a_shift_clicked) + x->a_buf[0] = 0; + //post("a_shift_clicked=%d", x->a_shift_clicked); } } @@ -1252,7 +1369,7 @@ static void gatom_displace(t_gobj *z, t_glist *glist, /* for gatom's label */ static void gatom_vis(t_gobj *z, t_glist *glist, int vis) { - //fprintf(stderr,"gatom_vis\n"); + //post("gatom_vis"); t_gatom *x = (t_gatom*)z; text_vis(z, glist, vis); if (*x->a_label->s_name) @@ -1305,6 +1422,7 @@ void canvas_atom(t_glist *gl, t_atomtype type, x->a_label = &s_; x->a_symfrom = &s_; x->a_symto = x->a_expanded_to = &s_; + x->a_shift_clicked = 0; if (type == A_FLOAT) { x->a_atom.a_w.w_float = 0; @@ -1317,6 +1435,7 @@ void canvas_atom(t_glist *gl, t_atomtype type, x->a_text.te_width = 10; SETSYMBOL(&at, &s_symbol); } + x->a_atomold = x->a_atom; binbuf_add(x->a_text.te_binbuf, 1, &at); if (argc > 1) /* create from file. x, y, width, low-range, high-range, flags, @@ -2175,8 +2294,8 @@ static int text_click(t_gobj *z, struct _glist *glist, t_rtext *y = glist_findrtext(glist, x); if (doit) { - //fprintf(stderr,"atom click\n"); - /* Change the gatom blue when it's clicked? Need to test... */ + //post("gatom click on"); + /* Change the gatom text color when it's clicked? Need to test... */ gui_vmess("gui_gatom_activate", "xsi", canvas, rtext_gettag(y), 1); gatom_click((t_gatom *)x, (t_floatarg)xpix, (t_floatarg)ypix,