From ac2dd064c777fdf44599950e6fe0475e850bba1a Mon Sep 17 00:00:00 2001
From: Ivica Ico Bukvic <ico@vt.edu>
Date: Fri, 29 Mar 2013 13:04:59 -0400
Subject: [PATCH] made drawsymbol a distinct object that properly opens its
 help file and also supports resizable fonts

---
 pd/src/g_template.c | 361 +++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 359 insertions(+), 2 deletions(-)

diff --git a/pd/src/g_template.c b/pd/src/g_template.c
index 3414b9b44..19c359f3f 100644
--- a/pd/src/g_template.c
+++ b/pd/src/g_template.c
@@ -2325,11 +2325,367 @@ static void drawnumber_setup(void)
         sizeof(t_drawnumber), 0, A_GIMME, 0);
     class_setdrawcommand(drawnumber_class);
     class_addfloat(drawnumber_class, drawnumber_float);
-    class_addcreator((t_newmethod)drawnumber_new, gensym("drawsymbol"),
-        A_GIMME, 0);
     class_setparentwidget(drawnumber_class, &drawnumber_widgetbehavior);
 }
 
+/* ---------------------- drawsymbol -------------------------------- */
+
+t_class *drawsymbol_class;
+
+typedef struct _drawsymbol
+{
+    t_object x_obj;
+    t_fielddesc x_value;
+    t_fielddesc x_xloc;
+    t_fielddesc x_yloc;
+    t_fielddesc x_color;
+    t_fielddesc x_vis;
+	t_fielddesc x_fontsize;
+    t_symbol *x_label;
+    int x_flags;
+    t_canvas *x_canvas;
+} t_drawsymbol;
+
+static void *drawsymbol_new(t_symbol *classsym, t_int argc, t_atom *argv)
+{
+    t_drawsymbol *x = (t_drawsymbol *)pd_new(drawsymbol_class);
+    char *classname = classsym->s_name;
+    int flags = 0;
+    
+    if (classname[4] == 's')
+        flags |= DRAW_SYMBOL;
+    x->x_flags = flags;
+    fielddesc_setfloat_const(&x->x_vis, 1);
+    x->x_canvas = canvas_getcurrent();
+    while (1)
+    {
+        t_symbol *firstarg = atom_getsymbolarg(0, argc, argv);
+        if (!strcmp(firstarg->s_name, "-v") && argc > 1)
+        {
+            fielddesc_setfloatarg(&x->x_vis, 1, argv+1);
+            argc -= 2; argv += 2;
+        }
+        else break;
+    }
+    if (flags & DRAW_SYMBOL)
+    {
+        if (argc) fielddesc_setsymbolarg(&x->x_value, argc--, argv++);
+        else fielddesc_setsymbol_const(&x->x_value, &s_);
+    }
+    else
+    {
+        if (argc) fielddesc_setfloatarg(&x->x_value, argc--, argv++);
+        else fielddesc_setfloat_const(&x->x_value, 0);
+    }
+    if (argc) fielddesc_setfloatarg(&x->x_xloc, argc--, argv++);
+    else fielddesc_setfloat_const(&x->x_xloc, 0);
+    if (argc) fielddesc_setfloatarg(&x->x_yloc, argc--, argv++);
+    else fielddesc_setfloat_const(&x->x_yloc, 0);
+    if (argc) fielddesc_setfloatarg(&x->x_color, argc--, argv++);
+    else fielddesc_setfloat_const(&x->x_color, 1);
+	if (argc == 2) fielddesc_setfloatarg(&x->x_fontsize, argc--, argv++);
+	else fielddesc_setfloatarg(&x->x_fontsize, 0, NULL);
+    if (argc)
+        x->x_label = atom_getsymbolarg(0, argc, argv);
+    else x->x_label = &s_;
+
+    return (x);
+}
+
+void drawsymbol_float(t_drawsymbol *x, t_floatarg f)
+{
+    int viswas;
+    if (x->x_vis.fd_type != A_FLOAT || x->x_vis.fd_var)
+    {
+        pd_error(x, "global vis/invis for a template with variable visibility");
+        return;
+    }
+    viswas = (x->x_vis.fd_un.fd_float != 0);
+    
+    if ((f != 0 && viswas) || (f == 0 && !viswas))
+        return;
+    canvas_redrawallfortemplatecanvas(x->x_canvas, 2);
+    fielddesc_setfloat_const(&x->x_vis, (f != 0));
+    canvas_redrawallfortemplatecanvas(x->x_canvas, 1);
+}
+
+/* -------------------- widget behavior for drawsymbol ------------ */
+
+#define DRAWSYMBOL_BUFSIZE 80
+static void drawsymbol_sprintf(t_drawsymbol *x, char *buf, t_atom *ap)
+{
+    int nchars;
+    strncpy(buf, x->x_label->s_name, DRAWSYMBOL_BUFSIZE);
+    buf[DRAWSYMBOL_BUFSIZE - 1] = 0;
+    nchars = strlen(buf);
+    atom_string(ap, buf + nchars, DRAWSYMBOL_BUFSIZE - nchars);
+}
+
+static void drawsymbol_getrect(t_gobj *z, t_glist *glist,
+    t_word *data, t_template *template, t_float basex, t_float basey,
+    int *xp1, int *yp1, int *xp2, int *yp2)
+{
+    t_drawsymbol *x = (t_drawsymbol *)z;
+    t_atom at;
+        int xloc, yloc, font, fontwidth, fontheight;
+    char buf[DRAWSYMBOL_BUFSIZE];
+
+    if (!fielddesc_getfloat(&x->x_vis, template, data, 0))
+    {
+        *xp1 = *yp1 = 0x7fffffff;
+        *xp2 = *yp2 = -0x7fffffff;
+        return;
+    }
+    xloc = glist_xtopixels(glist,
+        basex + fielddesc_getcoord(&x->x_xloc, template, data, 0));
+    yloc = glist_ytopixels(glist,
+        basey + fielddesc_getcoord(&x->x_yloc, template, data, 0));
+    font = fielddesc_getfloat(&x->x_value, template, data, 0);
+    fontwidth = sys_fontwidth(font);
+        fontheight = sys_fontheight(font);
+    if (x->x_flags & DRAW_SYMBOL)
+        SETSYMBOL(&at, fielddesc_getsymbol(&x->x_value, template, data, 0));
+    else SETFLOAT(&at, fielddesc_getfloat(&x->x_value, template, data, 0));
+    drawsymbol_sprintf(x, buf, &at);
+    *xp1 = xloc;
+    *yp1 = yloc;
+    *xp2 = xloc + fontwidth * strlen(buf);
+    *yp2 = yloc + fontheight;
+}
+
+static void drawsymbol_displace(t_gobj *z, t_glist *glist,
+    t_word *data, t_template *template, t_float basex, t_float basey,
+    int dx, int dy)
+{
+    /* refuse */
+}
+
+static void drawsymbol_select(t_gobj *z, t_glist *glist,
+    t_word *data, t_template *template, t_float basex, t_float basey,
+    int state)
+{
+    //post("drawsymbol_select %d", state);
+    /* fill in later */
+}
+
+static void drawsymbol_activate(t_gobj *z, t_glist *glist,
+    t_word *data, t_template *template, t_float basex, t_float basey,
+    int state)
+{
+    //post("drawsymbol_activate %d", state);
+}
+
+static void drawsymbol_vis(t_gobj *z, t_glist *glist, 
+    t_word *data, t_template *template, t_float basex, t_float basey,
+    int vis)
+{
+    t_drawsymbol *x = (t_drawsymbol *)z;
+    
+        /* see comment in plot_vis() */
+    if (vis && !fielddesc_getfloat(&x->x_vis, template, data, 0))
+        return;
+    if (vis)
+    {
+        t_atom at;
+		int fontsize = fielddesc_getfloat(&x->x_fontsize, template, data, 0);
+		if (!fontsize) fontsize = glist_getfont(glist);
+        int xloc = glist_xtopixels(glist,
+            basex + fielddesc_getcoord(&x->x_xloc, template, data, 0));
+        int yloc = glist_ytopixels(glist,
+            basey + fielddesc_getcoord(&x->x_yloc, template, data, 0));
+        char colorstring[20], buf[DRAWSYMBOL_BUFSIZE];
+        numbertocolor(fielddesc_getfloat(&x->x_color, template, data, 1),
+            colorstring);
+        if (x->x_flags & DRAW_SYMBOL)
+            SETSYMBOL(&at, fielddesc_getsymbol(&x->x_value, template, data, 0));
+        else SETFLOAT(&at, fielddesc_getfloat(&x->x_value, template, data, 0));
+        drawsymbol_sprintf(x, buf, &at);
+        sys_vgui(".x%lx.c create text %d %d -anchor nw -fill %s -text {%s}",
+                glist_getcanvas(glist), xloc, yloc, colorstring, buf);
+        sys_vgui(" -font {{%s} -%d %s}", sys_font,
+				 sys_hostfontsize(fontsize), sys_fontweight);
+        sys_vgui(" -tags {.x%lx.x%lx.drawsymbol%lx %lx}\n", 
+			glist_getcanvas(glist), glist, data, data);
+    }
+    else sys_vgui(".x%lx.c delete .x%lx.x%lx.drawsymbol%lx\n", glist_getcanvas(glist), 
+		glist_getcanvas(glist), glist, data);
+}
+
+static t_float drawsymbol_motion_ycumulative;
+static t_glist *drawsymbol_motion_glist;
+static t_scalar *drawsymbol_motion_scalar;
+static t_array *drawsymbol_motion_array;
+static t_word *drawsymbol_motion_wp;
+static t_template *drawsymbol_motion_template;
+static t_gpointer drawsymbol_motion_gpointer;
+static int drawsymbol_motion_symbol;
+static int drawsymbol_motion_firstkey;
+
+    /* LATER protect against the template changing or the scalar disappearing
+    probably by attaching a gpointer here ... */
+
+static void drawsymbol_motion(void *z, t_floatarg dx, t_floatarg dy)
+{
+    t_drawsymbol *x = (t_drawsymbol *)z;
+    t_fielddesc *f = &x->x_value;
+    t_atom at;
+    if (!gpointer_check(&drawsymbol_motion_gpointer, 0))
+    {
+        post("drawsymbol_motion: scalar disappeared");
+        return;
+    }
+    if (drawsymbol_motion_symbol)
+    {
+        post("drawsymbol_motion: symbol");
+        return;
+    }
+    drawsymbol_motion_ycumulative -= dy;
+    template_setfloat(drawsymbol_motion_template,
+        f->fd_un.fd_varsym,
+            drawsymbol_motion_wp, 
+            drawsymbol_motion_ycumulative,
+                1);
+    if (drawsymbol_motion_scalar)
+        template_notifyforscalar(drawsymbol_motion_template,
+            drawsymbol_motion_glist, drawsymbol_motion_scalar,
+                gensym("change"), 1, &at);
+
+    if (drawsymbol_motion_scalar)
+        scalar_redraw(drawsymbol_motion_scalar, drawsymbol_motion_glist);
+    if (drawsymbol_motion_array)
+        array_redraw(drawsymbol_motion_array, drawsymbol_motion_glist);
+}
+
+static void drawsymbol_key(void *z, t_floatarg fkey)
+{
+    t_drawsymbol *x = (t_drawsymbol *)z;
+    t_fielddesc *f = &x->x_value;
+    int key = fkey;
+    char sbuf[MAXPDSTRING];
+    t_atom at;
+    if (!gpointer_check(&drawsymbol_motion_gpointer, 0))
+    {
+        post("drawsymbol_motion: scalar disappeared");
+        return;
+    }
+    if (key == 0)
+        return;
+    if (drawsymbol_motion_symbol)
+    {
+            /* key entry for a symbol field */
+        if (drawsymbol_motion_firstkey)
+            sbuf[0] = 0;
+        else strncpy(sbuf, template_getsymbol(drawsymbol_motion_template,
+            f->fd_un.fd_varsym, drawsymbol_motion_wp, 1)->s_name,
+                MAXPDSTRING);
+        sbuf[MAXPDSTRING-1] = 0;
+        if (key == '\b')
+        {
+            if (*sbuf)
+                sbuf[strlen(sbuf)-1] = 0;
+        }
+        else
+        {
+            sbuf[strlen(sbuf)+1] = 0;
+            sbuf[strlen(sbuf)] = key;
+        }
+    }
+    else
+    {
+            /* key entry for a numeric field.  This is just a stopgap. */
+        float newf;
+        if (drawsymbol_motion_firstkey)
+            sbuf[0] = 0;
+        else sprintf(sbuf, "%g", template_getfloat(drawsymbol_motion_template,
+            f->fd_un.fd_varsym, drawsymbol_motion_wp, 1));
+        drawsymbol_motion_firstkey = (key == '\n');
+        if (key == '\b')
+        {
+            if (*sbuf)
+                sbuf[strlen(sbuf)-1] = 0;
+        }
+        else
+        {
+            sbuf[strlen(sbuf)+1] = 0;
+            sbuf[strlen(sbuf)] = key;
+        }
+        if (sscanf(sbuf, "%g", &newf) < 1)
+            newf = 0;
+        template_setfloat(drawsymbol_motion_template,
+            f->fd_un.fd_varsym, drawsymbol_motion_wp, newf, 1);
+        if (drawsymbol_motion_scalar)
+            template_notifyforscalar(drawsymbol_motion_template,
+                drawsymbol_motion_glist, drawsymbol_motion_scalar,
+                    gensym("change"), 1, &at);
+        if (drawsymbol_motion_scalar)
+            scalar_redraw(drawsymbol_motion_scalar, drawsymbol_motion_glist);
+        if (drawsymbol_motion_array)
+            array_redraw(drawsymbol_motion_array, drawsymbol_motion_glist);
+    }
+}
+
+static int drawsymbol_click(t_gobj *z, t_glist *glist, 
+    t_word *data, t_template *template, t_scalar *sc, t_array *ap,
+    t_float basex, t_float basey,
+    int xpix, int ypix, int shift, int alt, int dbl, int doit)
+{
+    t_drawsymbol *x = (t_drawsymbol *)z;
+    int x1, y1, x2, y2;
+    drawsymbol_getrect(z, glist,
+        data, template, basex, basey,
+        &x1, &y1, &x2, &y2);
+    if (xpix >= x1 && xpix <= x2 && ypix >= y1 && ypix <= y2
+        && x->x_value.fd_var &&
+            fielddesc_getfloat(&x->x_vis, template, data, 0))
+    {
+        if (doit)
+        {
+            drawsymbol_motion_glist = glist;
+            drawsymbol_motion_wp = data;
+            drawsymbol_motion_template = template;
+            drawsymbol_motion_scalar = sc;
+            drawsymbol_motion_array = ap;
+            drawsymbol_motion_firstkey = 1;
+            drawsymbol_motion_ycumulative =
+                fielddesc_getfloat(&x->x_value, template, data, 0);
+            drawsymbol_motion_symbol = ((x->x_flags & DRAW_SYMBOL) != 0);
+            if (drawsymbol_motion_scalar)
+                gpointer_setglist(&drawsymbol_motion_gpointer, 
+                    drawsymbol_motion_glist, drawsymbol_motion_scalar);
+            else gpointer_setarray(&drawsymbol_motion_gpointer,
+                    drawsymbol_motion_array, drawsymbol_motion_wp);
+           glist_grab(glist, z, drawsymbol_motion, drawsymbol_key,
+                xpix, ypix);
+        }
+        return (1);
+    }
+    else return (0);
+}
+
+t_parentwidgetbehavior drawsymbol_widgetbehavior =
+{
+    drawsymbol_getrect,
+    drawsymbol_displace,
+    drawsymbol_select,
+    drawsymbol_activate,
+    drawsymbol_vis,
+    drawsymbol_click,
+};
+
+static void drawsymbol_free(t_drawsymbol *x)
+{
+}
+
+static void drawsymbol_setup(void)
+{
+    drawsymbol_class = class_new(gensym("drawsymbol"),
+        (t_newmethod)drawsymbol_new, (t_method)drawsymbol_free,
+        sizeof(t_drawsymbol), 0, A_GIMME, 0);
+    class_setdrawcommand(drawsymbol_class);
+    class_addfloat(drawsymbol_class, drawsymbol_float);
+    class_setparentwidget(drawsymbol_class, &drawsymbol_widgetbehavior);
+}
+
 /* ---------------------- setup function ---------------------------- */
 
 void g_template_setup(void)
@@ -2339,5 +2695,6 @@ void g_template_setup(void)
     curve_setup();
     plot_setup();
     drawnumber_setup();
+	drawsymbol_setup();
 }
 
-- 
GitLab