From 43dcba3d7bde52773fcd1d5d84b267259ee6262f Mon Sep 17 00:00:00 2001
From: Jonathan Wilkes <jancsika@yahoo.com>
Date: Sat, 31 May 2014 18:48:06 -0400
Subject: [PATCH] Added methods to change coordinate data for shapes: data,
 points, x, y, height, width, cx, cy, r, x1, y1, x2, y2, and rx, ry for
 ellipse

---
 pd/src/g_template.c | 340 ++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 313 insertions(+), 27 deletions(-)

diff --git a/pd/src/g_template.c b/pd/src/g_template.c
index 09d7cff8a..a253341f3 100644
--- a/pd/src/g_template.c
+++ b/pd/src/g_template.c
@@ -1398,12 +1398,37 @@ void svg_doupdate(t_svg *x, t_canvas *c, t_symbol *s)
                     &x->x_strokewidth.a_attr, template, data, 1));
                 redraw_bbox = 1;
             }
+            else if (s == gensym("r"))
+            {
+                sprintf(str, "-rx %g -ry %g",
+                fielddesc_getcoord(x->x_vec+2, template, data, 1),
+                fielddesc_getcoord(x->x_vec+2, template, data, 1));
+                redraw_bbox = 1;
+            }
             else if (s == gensym("rx"))
-                sprintf(str, "-rx %d", (int)fielddesc_getcoord(
-                    &x->x_rx.a_attr, template, data, 1));
+            {
+                if (x->x_type == gensym("rect"))
+                    sprintf(str, "-rx %d", (int)fielddesc_getcoord(
+                        &x->x_rx.a_attr, template, data, 1));
+                else
+                {
+                    sprintf(str, "-rx %g", fielddesc_getcoord(
+                        x->x_vec+2, template, data, 1));
+                    redraw_bbox = 1;
+                }
+            }
             else if (s == gensym("ry"))
-                sprintf(str, "-ry %d", (int)fielddesc_getcoord(
-                    &x->x_ry.a_attr, template, data, 1));
+            {
+                if (x->x_type == gensym("rect"))
+                    sprintf(str, "-ry %d", (int)fielddesc_getcoord(
+                        &x->x_ry.a_attr, template, data, 1));
+                else
+                {
+                     sprintf(str, "-ry %g", fielddesc_getcoord(
+                         x->x_vec+3, template, data, 1));
+                     redraw_bbox = 1;
+                }
+           }
             else if (s == gensym("vis"))
             {
                 sprintf(str, "-state %s", (int)fielddesc_getcoord(
@@ -1426,12 +1451,81 @@ void svg_doupdate(t_svg *x, t_canvas *c, t_symbol *s)
                 }
                 else return;
             }
-            if (x->x_type == gensym("group"))
+            else if (s == gensym("data"))
+            {
+                /* this needs to be abstracted out somehow... */
+                sys_vgui(".x%lx.c coords .draw%lx.%lx {\\\n",
+                    visible, parent, data);
+                /* let's turn off bbox caching so we can recalculate
+                   the bbox */
+                if (x->x_pathrect_cache != -1)
+                   x->x_pathrect_cache = 0;
+                redraw_bbox = 1;
+                int i;
+                char *cmd;
+                t_fielddesc *f;
+                int totalpoints = 0; /* running tally */
+                /* path parser: no error checking yet */
+                for (i = 0, cmd = x->x_pathcmds; i < x->x_npathcmds; i++, cmd++)
+                {
+                    int j;
+                    int cargs = x->x_nargs_per_cmd[i];
+                    f = (x->x_vec)+totalpoints;
+                    sys_vgui("%c\\\n", *(cmd));
+                    for (j = 0; j < x->x_nargs_per_cmd[i]; j++)
+                        sys_vgui("%g\\\n", fielddesc_getcoord(
+                            f+j, template, data, 1));
+                    totalpoints += x->x_nargs_per_cmd[i];
+                }
+                sys_gui("}\n");
+            }
+            else if (s == gensym("points"))
+            {
+                /* this needs to be abstracted out somehow... */
+                sys_vgui(".x%lx.c coords .draw%lx.%lx \\\n",
+                    visible, parent, data);
+                /* let's turn off bbox caching so we can recalculate
+                   the bbox */
+                if (x->x_pathrect_cache != -1)
+                   x->x_pathrect_cache = 0;
+                redraw_bbox = 1;
+                int i;
+                t_fielddesc *f = x->x_vec;
+                if (x->x_type == gensym("rect") ||
+                    x->x_type == gensym("ellipse"))
+                {
+                    t_float xval, yval, w, h;
+                    xval = fielddesc_getcoord(f, template, data, 1);
+                    yval = fielddesc_getcoord(f+1, template, data, 1);
+                    if (x->x_type == gensym("rect"))
+                    {
+                        w = xval + (fielddesc_getcoord(f+2, template, data, 1));
+                        h = yval + (fielddesc_getcoord(f+3, template, data, 1));
+                        sys_vgui("%g %g %g %g\\\n", xval, yval, w, h);
+                    }
+                    else
+                    {
+                        sys_vgui("%g %g\\\n", xval, yval);
+                    }
+                }
+                else
+                {
+                    int n = (x->x_type == gensym("circle")) ? 2 : x->x_nargs;
+                    for (i = 0; i < n; i++)
+                    {
+                        sys_vgui("%g\\\n", fielddesc_getcoord(
+                            f+i, template, data, 1));
+                    }
+                }
+                sys_gui("\n");
+            }
+            if (x->x_type == gensym("group") && s != gensym("data") &&
+                s != gensym("points"))
             {
                 sys_vgui(".x%lx.c itemconfigure .dgroup%lx.%lx %s\n",
                    visible, parent, data, str);
             }
-            else
+            else if (s != gensym("data") && s != gensym("points"))
             {
                 sys_vgui(".x%lx.c itemconfigure .draw%lx.%lx %s\n",
                    visible, parent, data, str);
@@ -1440,13 +1534,13 @@ void svg_doupdate(t_svg *x, t_canvas *c, t_symbol *s)
             {
                 /* uncache the scalar's bbox */
                 ((t_scalar *)g)->sc_bboxcache = 0;
+                sys_vgui("pdtk_canvas_getscroll .x%lx.c\n", visible);
                 if (glist_isselected(c, &((t_scalar *)g)->sc_gobj))
                 {
                     //scalar_select(g, c, 1);
                     scalar_drawselectrect((t_scalar *)g, c, 0);
                     scalar_drawselectrect((t_scalar *)g, c, 1);
                     /* only get the scroll if we had to redraw the bbox */
-                    sys_vgui("pdtk_canvas_getscroll .x%lx.c\n", visible);
                 }
             }
         }
@@ -1475,6 +1569,65 @@ void svg_vis(t_svg *x, t_symbol *s, int argc, t_atom *argv)
     }
 }
 
+/* resize x_vec et all for path or shape coordinate data */
+void svg_resizecoords(t_svg *x, int argc, t_atom *argv)
+{
+//    if (x->x_type != gensym("path")) return;
+    int oldn = x->x_npathcmds;
+    /* for polyline and polygon, we don't want any path commands */
+    x->x_npathcmds = (x->x_type == gensym("path")) ?
+        path_ncmds(argc, argv) : 0;
+    x->x_pathcmds = (char *)t_resizebytes(x->x_pathcmds,
+        oldn * sizeof(char),
+        x->x_npathcmds * sizeof(char));
+
+    x->x_nargs_per_cmd = (int *)t_resizebytes(x->x_nargs_per_cmd,
+        oldn * sizeof(*x->x_nargs_per_cmd),
+        x->x_npathcmds * sizeof(*x->x_nargs_per_cmd));
+
+    oldn = x->x_nargs;
+    x->x_nargs = argc - x->x_npathcmds;
+
+    x->x_vec = (t_fielddesc *)t_resizebytes(x->x_vec,
+        oldn * sizeof(*x->x_vec),
+        x->x_nargs * sizeof(*x->x_vec));
+}
+
+void svg_data(t_svg *x, t_symbol *s, int argc, t_atom *argv)
+{
+    /* only process path data and polygon/polyline points */
+    if (x->x_type != gensym("path") && s != gensym("points")) return;
+    /* resize the path data fields to fit the incoming data */
+    svg_resizecoords(x, argc, argv);
+    /* todo: loop is copy/pasted from draw_new-- break it out */
+    t_fielddesc *fd;
+    int i, cmdn = -1; /* hack */
+    for (i = 0, fd = x->x_vec; i < argc; i++, argv++)
+    {
+        if (x->x_type == gensym("path") &&
+            argv->a_type == A_SYMBOL &&
+            is_svgpath_cmd(atom_getsymbol(argv)))
+        {
+                x->x_pathcmds[++cmdn] = *(atom_getsymbol(argv)->s_name);
+                x->x_nargs_per_cmd[cmdn] = 0;
+        }
+        else
+        {
+            fielddesc_setfloatarg(fd++, 1, argv);
+            /* post("got a coord"); */
+            if (x->x_type == gensym("path"))
+            {
+                (x->x_nargs_per_cmd[cmdn])++;
+                /* if we get a field variable, just
+                   turn off the get_rect caching */
+                if (argv->a_type == A_SYMBOL)
+                    x->x_pathrect_cache = -1;
+            }
+        }
+    }
+    svg_update(x, s);
+}
+
 void svg_fillopacity(t_svg *x, t_symbol *s, t_int argc, t_atom *argv)
 {
     if (argv[0].a_type == A_FLOAT || argv[0].a_type == A_SYMBOL)
@@ -1649,38 +1802,145 @@ void svg_fillrule(t_svg *x, t_symbol *s, t_int argc, t_atom *argv)
     }
 }
 
-void svg_rx(t_svg *x, t_symbol *s, int argc, t_atom *argv)
+void svg_r(t_svg *x, t_symbol *s, int argc, t_atom *argv)
 {
-    if (x->x_type != gensym("rect"))
+    if (x->x_type != gensym("circle"))
     {
-        pd_error(x, "draw: %s: no method for 'rx'", x->x_type->s_name);
+        pd_error(x, "draw: %s: no method for 'r'", x->x_type->s_name);
         return;
     }
-    if (!argc || argv->a_type != A_FLOAT)
+    if (argv[0].a_type == A_FLOAT || argv[0].a_type == A_SYMBOL)
+    {
+        t_fielddesc *fd = x->x_vec;
+        fielddesc_setfloatarg(fd+2, argc, argv);
+        svg_update(x, s);
+    }
+}
+
+void svg_rx(t_svg *x, t_symbol *s, int argc, t_atom *argv)
+{
+    t_symbol *type = x->x_type;
+    if (type == gensym("rect") || type == gensym("ellipse"))
+    {
+        if (argv[0].a_type == A_FLOAT || argv[0].a_type == A_SYMBOL)
+        {
+            if (type == gensym("rect"))
+            {
+                fielddesc_setfloatarg(&x->x_rx.a_attr, argc, argv);
+                x->x_rx.a_flag = 1;
+            }
+            else
+            {
+                fielddesc_setfloatarg(x->x_vec+2, argc, argv);
+            }
+            svg_update(x, s);
+        }
+    }
+    else
     {
-        pd_error(x, "draw: rect: bad arguments for method 'rx'");
+        pd_error(x, "draw: %s: no method for 'rx'", x->x_type->s_name);
         return;
     }
-    fielddesc_setfloatarg(&x->x_rx.a_attr, argc, argv);
-    x->x_rx.a_flag = 1;
-    svg_update(x, s);
 }
 
 void svg_ry(t_svg *x, t_symbol *s, int argc, t_atom *argv)
 {
-    if (x->x_type != gensym("rect"))
+    t_symbol *type = x->x_type;
+    if (type == gensym("rect") || type == gensym("ellipse"))
+    {
+        if (argv[0].a_type == A_FLOAT || argv[0].a_type == A_SYMBOL)
+        {
+            if (type == gensym("rect"))
+            {
+                fielddesc_setfloatarg(&x->x_ry.a_attr, argc, argv);
+                x->x_rx.a_flag = 1;
+            }
+            else
+            {
+                fielddesc_setfloatarg(x->x_vec+3, argc, argv);
+            }
+            svg_update(x, s);
+        }
+    }
+    else
     {
         pd_error(x, "draw: %s: no method for 'ry'", x->x_type->s_name);
         return;
     }
-    if (!argc || argv->a_type != A_FLOAT)
+}
+
+/* todo: ensure that rect has 4 coords pre-allocated! otherwise a crash */
+void svg_rectpoints(t_svg *x, t_symbol *s, int argc, t_atom *argv)
+{
+    if (x->x_type == gensym("rect"))
+    {
+        int i;
+        if (s == gensym("x")) i = 0;
+        else if (s == gensym("y")) i = 1;
+        else if (s == gensym("width")) i = 2;
+        else i = 3; /* height */
+        if (argv[0].a_type == A_FLOAT || argv[0].a_type == A_SYMBOL)
+        {
+            t_fielddesc *fd = x->x_vec;
+            fielddesc_setfloatarg(fd + i, argc, argv);
+            /* just piggybacking on the "points" message */
+            svg_update(x, gensym("points"));
+        }
+    }
+    else
+    {
+        pd_error(x, "draw: %s: no poopy for '%s'",
+            x->x_type->s_name, s->s_name);
+        return;
+    }
+}
+
+void svg_ellipsepoints(t_svg *x, t_symbol *s, int argc, t_atom *argv)
+{
+    if (x->x_type == gensym("circle") || x->x_type == gensym("ellipse"))
+    {
+        int i;
+        if (s == gensym("cx")) i = 0;
+        else i = 1;
+        if (argv[0].a_type == A_FLOAT || argv[0].a_type == A_SYMBOL)
+        {
+            t_fielddesc *fd = x->x_vec;
+            fielddesc_setfloatarg(fd + i, argc, argv);
+            /* just piggybacking on the "points" message */
+            svg_update(x, gensym("points"));
+        }
+    }
+    else
     {
-        pd_error(x, "draw: rect: bad arguments for method 'ry'");
+        pd_error(x, "draw: %s: no method for '%s'",
+            x->x_type->s_name, s->s_name);
+        return;
+    }
+}
+
+void svg_linepoints(t_svg *x, t_symbol *s, int argc, t_atom *argv)
+{
+    int i = 0;
+    if (x->x_type == gensym("line"))
+    {
+        if (argv[0].a_type == A_FLOAT || argv[0].a_type == A_SYMBOL)
+        {
+            if (s == gensym("x1")) i = 0;
+            else if (s == gensym("y1")) i = 1;
+            else if (s == gensym("x2")) i = 2;
+            else if (s == gensym("y2")) i = 3;
+            t_fielddesc *fd = x->x_vec;
+            fielddesc_setfloatarg(fd + i, argc, argv);
+            /* just simulate the "points" method */
+            svg_update(x, gensym("points"));
+        }
+    }
+    else
+    {
+        pd_error(x, "draw: %s: no method for '%s'",
+            x->x_type->s_name, s->s_name);
         return;
     }
-    fielddesc_setfloatarg(&x->x_ry.a_attr, argc, argv);
-    x->x_ry.a_flag = 1;
-    svg_update(x, s);
 }
 
 static int minv(t_float a[][3], t_float b[][3])
@@ -3387,14 +3647,28 @@ static void draw_setup(void)
     /* methods for svg_class-- these will be accessible
        from the inlet of [draw] and the (rightmost) inlet of
        [group] */
-    class_addmethod(svg_class, (t_method)svg_vis,
-        gensym("vis"), A_GIMME, 0);
+    class_addmethod(svg_class, (t_method)svg_ellipsepoints,
+        gensym("cx"), A_GIMME, 0);
+    class_addmethod(svg_class, (t_method)svg_ellipsepoints,
+        gensym("cy"), A_GIMME, 0);
+    class_addmethod(svg_class, (t_method)svg_data,
+        gensym("data"), A_GIMME, 0);
     class_addmethod(svg_class, (t_method)svg_fill,
         gensym("fill"), A_GIMME, 0);
     class_addmethod(svg_class, (t_method)svg_fillopacity,
         gensym("fill-opacity"), A_GIMME, 0);
     class_addmethod(svg_class, (t_method)svg_fillrule,
         gensym("fill-rule"), A_GIMME, 0);
+    class_addmethod(svg_class, (t_method)svg_rectpoints,
+        gensym("height"), A_GIMME, 0);
+    class_addmethod(svg_class, (t_method)svg_data,
+        gensym("points"), A_GIMME, 0);
+    class_addmethod(svg_class, (t_method)svg_r,
+        gensym("r"), A_GIMME, 0);
+    class_addmethod(svg_class, (t_method)svg_rx,
+        gensym("rx"), A_GIMME, 0);
+    class_addmethod(svg_class, (t_method)svg_ry,
+        gensym("ry"), A_GIMME, 0);
     class_addmethod(svg_class, (t_method)svg_stroke,
         gensym("stroke"), A_GIMME, 0);
     class_addmethod(svg_class, (t_method)svg_strokedasharray,
@@ -3411,10 +3685,22 @@ static void draw_setup(void)
         gensym("stroke-width"), A_GIMME, 0);
     class_addmethod(svg_class, (t_method)svg_transform,
         gensym("transform"), A_GIMME, 0);
-    class_addmethod(svg_class, (t_method)svg_rx,
-        gensym("rx"), A_GIMME, 0);
-    class_addmethod(svg_class, (t_method)svg_ry,
-        gensym("ry"), A_GIMME, 0);
+    class_addmethod(svg_class, (t_method)svg_vis,
+        gensym("vis"), A_GIMME, 0);
+    class_addmethod(svg_class, (t_method)svg_rectpoints,
+        gensym("width"), A_GIMME, 0);
+    class_addmethod(svg_class, (t_method)svg_rectpoints,
+        gensym("x"), A_GIMME, 0);
+    class_addmethod(svg_class, (t_method)svg_linepoints,
+        gensym("x1"), A_GIMME, 0);
+    class_addmethod(svg_class, (t_method)svg_linepoints,
+        gensym("x2"), A_GIMME, 0);
+    class_addmethod(svg_class, (t_method)svg_rectpoints,
+        gensym("y"), A_GIMME, 0);
+    class_addmethod(svg_class, (t_method)svg_linepoints,
+        gensym("y1"), A_GIMME, 0);
+    class_addmethod(svg_class, (t_method)svg_linepoints,
+        gensym("y2"), A_GIMME, 0);
 }
 
 /* ---------------- curves and polygons (joined segments) ---------------- */
-- 
GitLab