Newer
Older
/* Copyright (c) 1997-1999 Miller Puckette.
* For information on usage and redistribution, and for a DISCLAIMER OF ALL
* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
/* This file defines the "scalar" object, which is not a text object, just a
"gobj". Scalars have templates which describe their structures, which
can contain numbers, sublists, and arrays.
*/
#include <stdlib.h>
#include <string.h>
#include <stdio.h> /* for read/write to files */
#include "m_pd.h"
#include "g_canvas.h"
t_class *scalar_class;
void word_init(t_word *wp, t_template *template, t_gpointer *gp)
{
int i, nitems = template->t_n;
t_dataslot *datatypes = template->t_vec;
for (i = 0; i < nitems; i++, datatypes++, wp++)
{
int type = datatypes->ds_type;
if (type == DT_FLOAT)
wp->w_float = 0;
else if (type == DT_SYMBOL)
wp->w_symbol = &s_symbol;
else if (type == DT_ARRAY)
{
Jonathan Wilkes
committed
wp->w_array = array_new(datatypes->ds_fieldtemplate, gp);
}
else if (type == DT_LIST)
{
/* LATER test this and get it to work */
wp->w_list = canvas_new(0, 0, 0, 0);
}
}
}
void word_restore(t_word *wp, t_template *template,
int argc, t_atom *argv)
{
int i, nitems = template->t_n;
t_dataslot *datatypes = template->t_vec;
for (i = 0; i < nitems; i++, datatypes++, wp++)
{
int type = datatypes->ds_type;
if (type == DT_FLOAT)
{
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
if (argc)
{
f = atom_getfloat(argv);
argv++, argc--;
}
else f = 0;
wp->w_float = f;
}
else if (type == DT_SYMBOL)
{
t_symbol *s;
if (argc)
{
s = atom_getsymbol(argv);
argv++, argc--;
}
else s = &s_;
wp->w_symbol = s;
}
}
if (argc)
post("warning: word_restore: extra arguments");
}
void word_free(t_word *wp, t_template *template)
{
int i;
t_dataslot *dt;
for (dt = template->t_vec, i = 0; i < template->t_n; i++, dt++)
{
if (dt->ds_type == DT_ARRAY)
array_free(wp[i].w_array);
else if (dt->ds_type == DT_LIST)
canvas_free(wp[i].w_list);
}
}
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
/* some of this code is used in a function in g_canvas.c...
need to modularize it */
static t_object *template_getstruct(t_template *template)
{
if (template)
{
t_gobj *y;
t_canvas *c;
if (c = template_findcanvas(template))
{
t_symbol *s1 = gensym("struct");
for (y = c->gl_list; y; y = y->g_next)
{
t_object *ob = pd_checkobject(&y->g_pd);
t_atom *argv;
if (!ob || ob->te_type != T_OBJECT ||
binbuf_getnatom(ob->te_binbuf) < 2)
continue;
argv = binbuf_getvec(ob->te_binbuf);
if (argv[0].a_w.w_symbol != s1)
continue;
if (canvas_makebindsym(argv[1].a_w.w_symbol) == template->t_sym)
return (ob);
}
}
}
return (0);
}
int template_hasxy(t_template *template)
{
t_symbol *zz;
int xonset, yonset, xtype, ytype, gotx, goty;
if (!template)
{
error("struct: couldn't find template %s", template->t_sym->s_name);
return 0;
}
gotx = template_find_field(template, gensym("x"), &xonset, &xtype, &zz);
goty = template_find_field(template, gensym("y"), &yonset, &ytype, &zz);
if ((gotx && (xtype == DT_FLOAT)) &&
(goty && (ytype == DT_FLOAT)) &&
(xonset == 0) && (yonset == sizeof(t_word)))
{
return 1;
}
else
return 0;
}
pokergaming
committed
int template_check_array_fields(t_symbol *structname, t_template *template)
pokergaming
committed
/* We're calling this from template_cancreate as well as
gtemplate_cancreate. With gtemplate_cancreate, the t_template doesn't
exist yet. So we send the struct name to see if it matches the name of
any array field templates that our gtemplate will depend on. If we find
a match we will refuse to create the gtemplate. However,
template_cancreate starts from the struct name for a template that
already exists. On the first time through this recursive function,
there isn't a containing structname yet. So we suppress this conditional
the first time through the recursive loop, and then set the structname
for all subsequent iterations through the loop.
1 = success
0 = circular dependency
-1 = non-existant array elemtemplate found */
pokergaming
committed
if (structname && structname == template->t_sym)
{
t_object *ob = template_getstruct(template);
pd_error(ob, "%s: circular dependency",
template->t_sym->s_name);
return (0);
pokergaming
committed
}
t_dataslot *datatypes = template->t_vec;
t_template *elemtemplate;
for (i = 0; i < nitems; i++, datatypes++)
{
pokergaming
committed
if (datatypes->ds_type == DT_ARRAY)
{
Jonathan Wilkes
committed
elemtemplate = template_findbyname(datatypes->ds_fieldtemplate);
pokergaming
committed
if (!(elemtemplate))
{
t_object *ob = template_getstruct(template);
pd_error(ob, "%s: no such template",
Jonathan Wilkes
committed
datatypes->ds_fieldtemplate->s_name);
pokergaming
committed
}
else if (elemtemplate->t_sym == structname)
{
t_object *ob = template_getstruct(template);
pd_error(ob, "%s: circular dependency",
Jonathan Wilkes
committed
datatypes->ds_fieldtemplate->s_name);
pokergaming
committed
return (0);
}
else
{
if (!structname)
{
structname = template->t_sym;
}
return (template_check_array_fields(structname, elemtemplate));
}
}
pokergaming
committed
int template_cancreate(t_template *template)
{
/* we send "0" for the structname since there is no container struct */
return (template_check_array_fields(0, template) == 1);
pokergaming
committed
}
/* make a new scalar and add to the glist. We create a "gp" here which
will be used for array items to point back here. This gp doesn't do
reference counting or "validation" updates though; the parent won't go away
without the contained arrays going away too. The "gp" is copied out
by value in the word_init() routine so we can throw our copy away. */
t_scalar *scalar_new(t_glist *owner, t_symbol *templatesym)
{
t_scalar *x;
t_template *template;
t_gpointer gp;
gpointer_init(&gp);
template = template_findbyname(templatesym);
if (!template)
{
error("scalar: couldn't find template %s", templatesym->s_name);
return (0);
}
if (!template_cancreate(template))
return (0);
x = (t_scalar *)getbytes(sizeof(t_scalar) +
(template->t_n - 1) * sizeof(*x->sc_vec));
x->sc_gobj.g_pd = scalar_class;
x->sc_template = templatesym;
gpointer_setglist(&gp, owner, &x->sc_gobj);
Ivica Bukvic
committed
char buf[50];
sprintf(buf, ".x%lx", (long unsigned int)x);
pd_bind(&x->sc_gobj.g_pd, gensym(buf));
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
return (x);
}
/* Pd method to create a new scalar, add it to a glist, and initialize
it from the message arguments. */
int glist_readscalar(t_glist *x, int natoms, t_atom *vec,
int *p_nextmsg, int selectit);
void glist_scalar(t_glist *glist,
t_symbol *classname, t_int argc, t_atom *argv)
{
t_symbol *templatesym =
canvas_makebindsym(atom_getsymbolarg(0, argc, argv));
t_binbuf *b;
int natoms, nextmsg = 0;
t_atom *vec;
if (!template_findbyname(templatesym))
{
pd_error(glist, "%s: no such template",
atom_getsymbolarg(0, argc, argv)->s_name);
return;
}
b = binbuf_new();
binbuf_restore(b, argc, argv);
natoms = binbuf_getnatom(b);
vec = binbuf_getvec(b);
glist_readscalar(glist, natoms, vec, &nextmsg, 0);
binbuf_free(b);
}
/* search template fields recursively to see if the template
depends on elemtemplate */
int template_has_elemtemplate(t_template *t, t_template *elemtemplate)
{
int returnval = 0;
if (t && elemtemplate)
{
int i;
t_dataslot *d = t->t_vec;
for (i = 0; i < t->t_n; i++, d++)
{
if (d->ds_type == DT_ARRAY)
{
Jonathan Wilkes
committed
if (d->ds_fieldtemplate == elemtemplate->t_sym)
{
returnval = 1;
break;
}
else
{
returnval = template_has_elemtemplate(
Jonathan Wilkes
committed
template_findbyname(d->ds_fieldtemplate),
elemtemplate);
}
}
}
}
return (returnval);
}
/* -------------------- widget behavior for scalar ------------ */
void scalar_getbasexy(t_scalar *x, t_float *basex, t_float *basey)
{
t_template *template = template_findbyname(x->sc_template);
*basex = template_getfloat(template, gensym("x"), x->sc_vec, 0);
*basey = template_getfloat(template, gensym("y"), x->sc_vec, 0);
}
Ivica Bukvic
committed
extern int array_joc;
Ivica Bukvic
committed
extern void template_notifyforscalar(t_template *template, t_glist *owner,
t_scalar *sc, t_symbol *s, int argc, t_atom *argv);
Ivica Bukvic
committed
t_canvas *sc_mouseover_canvas;
static void scalar_mouseover(t_scalar *x, t_floatarg state)
{
Ivica Bukvic
committed
t_atom at[1];
t_template *template = template_findbyname(x->sc_template);
if (state)
template_notifyforscalar(template, sc_mouseover_canvas,
x, gensym("leave"), 1, at);
else
template_notifyforscalar(template, sc_mouseover_canvas,
x, gensym("enter"), 1, at);
}
Ivica Bukvic
committed
static void scalar_getgrouprect(t_glist *owner, t_glist *groupcanvas,
t_word *data, t_template *template, int basex, int basey,
int *x1, int *x2, int *y1, int *y2)
{
t_gobj *y;
for (y = groupcanvas->gl_list; y; y = y->g_next)
{
if (pd_class(&y->g_pd) == canvas_class &&
((t_canvas *)y)->gl_svg)
Ivica Bukvic
committed
{
/* todo: accumulate basex and basey for correct offset */
scalar_getgrouprect(owner, (t_glist *)y, data, template,
basex, basey, x1, x2, y1, y2);
Ivica Bukvic
committed
}
else
{
t_parentwidgetbehavior *wb = pd_getparentwidget(&y->g_pd);
int nx1, ny1, nx2, ny2;
if (!wb) continue;
(*wb->w_parentgetrectfn)(y, owner,
data, template, basex, basey,
&nx1, &ny1, &nx2, &ny2);
if (nx1 < *x1) *x1 = nx1;
if (ny1 < *y1) *y1 = ny1;
if (nx2 > *x2) *x2 = nx2;
if (ny2 > *y2) *y2 = ny2;
//fprintf(stderr,"====scalar_getrect x1 %d y1 %d x2 %d y2 %d\n",
// x1, y1, x2, y2);
}
}
}
static void scalar_getrect(t_gobj *z, t_glist *owner,
int *xp1, int *yp1, int *xp2, int *yp2)
{
//fprintf(stderr,"scalar_getrect %d\n", array_joc);
Ivica Bukvic
committed
t_template *template = template_findbyname(x->sc_template);
t_canvas *templatecanvas = template_findcanvas(template);
int x1 = 0x7fffffff, x2 = -0x7fffffff, y1 = 0x7fffffff, y2 = -0x7fffffff;
t_float screenx1, screeny1, screenx2, screeny2;
Ivica Bukvic
committed
// EXPERIMENTAL: we assume that entire canvas is within
// the rectangle--this is for arrays
// with "jump on click" enabled TODO: test for other regressions
Ivica Bukvic
committed
// (there should not be any
Ivica Bukvic
committed
// provided the global variable array_joc is properly maintained)
if (glist_istoplevel(owner) && array_joc)
{
Ivica Bukvic
committed
x1 = -0x7fffffff, y1 = -0x7fffffff, x2 = 0x7fffffff, y2 = 0x7fffffff;
Ivica Bukvic
committed
scalar_getbasexy(x, &basex, &basey);
/* if someone deleted the template canvas, we're just a point */
if (!templatecanvas)
//fprintf(stderr,"...point\n");
Ivica Bukvic
committed
x1 = x2 = glist_xtopixels(owner, basex);
y1 = y2 = glist_ytopixels(owner, basey);
}
else
{
Ivica Bukvic
committed
/* todo: bad flow with internal return here. make it cleaner */
if (x->sc_bboxcache && 0)
Ivica Bukvic
committed
{
screenx1 = glist_xtopixels(owner, x->sc_x1);
screeny1 = glist_ytopixels(owner, x->sc_y1);
screenx2 = glist_xtopixels(owner, x->sc_x2);
screeny2 = glist_ytopixels(owner, x->sc_y2);
*xp1 = (int)(screenx1 < screenx2 ? screenx1 : screenx2);
*yp1 = (int)(screeny1 < screeny2 ? screeny1 : screeny2);
*xp2 = (int)(screenx2 > screenx1 ? screenx2 : screenx1);
*yp2 = (int)(screeny2 > screeny1 ? screeny2 : screeny1);
//fprintf(stderr,"CACHED FINAL scalar_getrect "
// "x1 %g y1 %g x2 %g y2 %g\n",
// screenx1,
// screeny1,
// screenx2,
// screeny2);
Ivica Bukvic
committed
return;
}
Ivica Bukvic
committed
x1 = y1 = 0x7fffffff;
x2 = y2 = -0x7fffffff;
Ivica Bukvic
committed
scalar_getgrouprect(owner, templatecanvas, x->sc_vec, template,
basex, basey, &x1, &x2, &y1, &y2);
if (x2 < x1 || y2 < y1)
Ivica Bukvic
committed
x1 = y1 = x2 = y2 = 0;
screenx1 = glist_xtopixels(owner, x1);
screeny1 = glist_ytopixels(owner, y1);
screenx2 = glist_xtopixels(owner, x2);
screeny2 = glist_ytopixels(owner, y2);
// Values for screen bounding box
*xp1 = (int)(screenx1 < screenx2 ? screenx1 : screenx2);
*xp2 = (int)(screenx2 > screenx1 ? screenx2 : screenx1);
*yp1 = (int)(screeny1 < screeny2 ? screeny1 : screeny2);
*yp2 = (int)(screeny2 > screeny1 ? screeny2 : screeny1);
// Cache without glist_topixel (in case a gop is moved, for example)
x->sc_x1 = x1;
x->sc_x2 = x2;
x->sc_y1 = y1;
x->sc_y2 = y2;
//fprintf(stderr,"COMPUTED FINAL scalar_getrect "
// "x1 %g y1 %g x2 %g y2 %g\n",
// screenx1,
// screeny1,
// screenx2,
// screeny2);
x->sc_bboxcache = 1; // We now have cached values for the next call
Ivica Bukvic
committed
void scalar_drawselectrect(t_scalar *x, t_glist *glist, int state)
char tagbuf[MAXPDSTRING];
sprintf(tagbuf, "scalar%lx", (long unsigned int)x->sc_vec);
//fprintf(stderr,"scalar_drawselecterect%d\n", state);
t_float basex, basey;
scalar_getbasexy(x, &basex, &basey);
scalar_getrect(&x->sc_gobj, glist, &x1, &y1, &x2, &y2);
x1--; x2++; y1--; y2++;
if (glist_istoplevel(glist))
t_float xscale = glist_xtopixels(glist, 1) -
glist_xtopixels(glist, 0);
t_float yscale = glist_ytopixels(glist, 1) -
glist_ytopixels(glist, 0);
post("xsclae is %g and yscale is %g", xscale, yscale);
//sys_vgui(".x%lx.c create prect %d %d %d %d "
// "-strokewidth 1 -stroke $pd_colors(selection) "
// "-tags {select%lx selected}\n",
// glist_getcanvas(glist), x1, y1, x2, y2,
// x);
gui_vmess("gui_scalar_draw_select_rect", "xsiiiiiff",
glist_getcanvas(glist), tagbuf,
(int)(x1 / xscale + 0.499),
(int)(y1 / yscale + 0.499),
(int)(x2 / xscale + 0.499),
(int)(y2 / yscale + 0.499),
basex,
basey);
if (glist_istoplevel(glist))
{
//sys_vgui(".x%lx.c delete select%lx\n", glist_getcanvas(glist), x);
gui_vmess("gui_scalar_draw_select_rect", "xsiiiiiii",
glist_getcanvas(glist), tagbuf,
state,
0, 0, 0, 0, 0, 0);
}
/* This is greatly simplified with Node-Webkit-- we just need to get the
basex/basey for the scalar, in addition to the bbox of the scalar.
This can be simplified further by using a single function on the GUI
side, and sending it the "state" parameter.
Ivica Bukvic
committed
*/
void scalar_select(t_gobj *z, t_glist *owner, int state)
//fprintf(stderr,"scalar_select %d\n", state);
char tagbuf[MAXPDSTRING];
sprintf(tagbuf, "scalar%lx", (long unsigned int)x->sc_vec);
t_template *tmpl;
t_symbol *templatesym = x->sc_template;
t_atom at;
//t_canvas *templatecanvas = NULL;
gpointer_setglist(&gp, owner, &x->sc_gobj);
if (tmpl = template_findbyname(templatesym))
{
template_notify(tmpl, (state ? gensym("select") : gensym("deselect")),
1, &at);
//templatecanvas = template_findcanvas(tmpl);
x->sc_selected = owner;
//sys_vgui(".x%lx.c addtag selected withtag blankscalar%lx\n",
// glist_getcanvas(owner), x);
//sys_vgui(".x%lx.c addtag scalar_selected withtag {.scalar%lx}\n",
// glist_getcanvas(owner), x->sc_vec);
gui_vmess("gui_gobj_select", "xs",
glist_getcanvas(owner), tagbuf);
x->sc_selected = 0;
//sys_vgui(".x%lx.c dtag blankscalar%lx selected\n",
// glist_getcanvas(owner), x);
//sys_vgui(".x%lx.c dtag .scalar%lx scalar_selected\n",
// glist_getcanvas(owner), x->sc_vec);
gui_vmess("gui_gobj_deselect", "xs",
glist_getcanvas(owner), tagbuf);
}
//sys_vgui("pdtk_select_all_gop_widgets .x%lx %lx %d\n",
// glist_getcanvas(owner), owner, state);
scalar_drawselectrect(x, owner, state);
}
static void scalar_displace(t_gobj *z, t_glist *glist, int dx, int dy)
{
//fprintf(stderr,"scalar_displace\n");
t_scalar *x = (t_scalar *)z;
t_symbol *templatesym = x->sc_template;
t_template *template = template_findbyname(templatesym);
t_symbol *zz;
t_atom at[3];
t_gpointer gp;
int xonset, yonset, xtype, ytype, gotx, goty;
if (!template)
{
error("scalar: couldn't find template %s", templatesym->s_name);
return;
}
gotx = template_find_field(template, gensym("x"), &xonset, &xtype, &zz);
Ivica Bukvic
committed
if ((gotx && (xtype != DT_FLOAT)) || x->sc_selected != glist)
gotx = 0;
goty = template_find_field(template, gensym("y"), &yonset, &ytype, &zz);
Ivica Bukvic
committed
if ((goty && (ytype != DT_FLOAT)) || x->sc_selected != glist)
Ivica Bukvic
committed
{
*(t_float *)(((char *)(x->sc_vec)) + xonset) +=
dx * (glist_pixelstox(glist, 1) - glist_pixelstox(glist, 0));
Ivica Bukvic
committed
x->sc_x1 += dx;
x->sc_x2 += dx;
}
Ivica Bukvic
committed
{
*(t_float *)(((char *)(x->sc_vec)) + yonset) +=
dy * (glist_pixelstoy(glist, 1) - glist_pixelstoy(glist, 0));
Ivica Bukvic
committed
x->sc_y1 += dy;
x->sc_y2 += dy;
}
gpointer_setglist(&gp, glist, &x->sc_gobj);
SETFLOAT(&at[1], (t_float)dx);
SETFLOAT(&at[2], (t_float)dy);
template_notify(template, gensym("displace"), 2, at);
scalar_redraw(x, glist);
}
/* Kind of complicated at the moment. If a scalar is in a gop canvas, then
Ivica Bukvic
committed
we don't need to update its x/y fields (if it even has them) when displacing
it. Otherwise we do. The member sc_selected is used to store the canvas
where the selection exists-- if it matches the glist parameter below then we
know the scalar is directly selected. If not it's in a gop canvas.
Ivica Bukvic
committed
*/
static void scalar_displace_withtag(t_gobj *z, t_glist *glist, int dx, int dy)
{
//fprintf(stderr,"scalar_displace_withtag %lx %d %d\n", (t_int)z, dx, dy);
t_scalar *x = (t_scalar *)z;
t_symbol *templatesym = x->sc_template;
t_template *template = template_findbyname(templatesym);
t_symbol *zz;
t_atom at[3];
t_gpointer gp;
int xonset, yonset, xtype, ytype, gotx, goty;
Ivica Bukvic
committed
t_float basex = 0, basey = 0;
if (!template)
{
error("scalar: couldn't find template %s", templatesym->s_name);
return;
}
gotx = template_find_field(template, gensym("x"), &xonset, &xtype, &zz);
Ivica Bukvic
committed
if ((gotx && (xtype != DT_FLOAT)) || x->sc_selected != glist)
gotx = 0;
goty = template_find_field(template, gensym("y"), &yonset, &ytype, &zz);
Ivica Bukvic
committed
if ((goty && (ytype != DT_FLOAT)) || x->sc_selected != glist)
Ivica Bukvic
committed
{
*(t_float *)(((char *)(x->sc_vec)) + xonset) +=
dx * (glist_pixelstox(glist, 1) - glist_pixelstox(glist, 0));
Ivica Bukvic
committed
x->sc_x1 += dx;
x->sc_x2 += dx;
}
Ivica Bukvic
committed
{
*(t_float *)(((char *)(x->sc_vec)) + yonset) +=
dy * (glist_pixelstoy(glist, 1) - glist_pixelstoy(glist, 0));
Ivica Bukvic
committed
x->sc_y1 += dy;
x->sc_y2 += dy;
}
Ivica Bukvic
committed
scalar_getbasexy(x, &basex, &basey);
gpointer_setglist(&gp, glist, &x->sc_gobj);
SETPOINTER(&at[0], &gp);
SETFLOAT(&at[1], (t_float)dx);
SETFLOAT(&at[2], (t_float)dy);
template_notify(template, gensym("displace"), 2, at);
Ivica Bukvic
committed
Mathieu L Bouchard
committed
canvas_getscroll(glist);
/* Apparently this is no longer needed, so it is commented out. But if
we merge garrays back into this code we may need it... */
if (template->t_sym != gensym("_float_array"))
{
t_gobj *y;
t_canvas *templatecanvas = template_findcanvas(template);
for (y = templatecanvas->gl_list; y; y = y->g_next)
{
t_parentwidgetbehavior *wb = pd_getparentwidget(&y->g_pd);
if (!wb) continue;
(*wb->w_parentdisplacefn)(y, glist, x->sc_vec, template,
basex, basey, dx, dy);
}
}
Ivica Bukvic
committed
//scalar_redraw(x, glist);
}
static void scalar_activate(t_gobj *z, t_glist *owner, int state)
{
/* post("scalar_activate %d", state); */
/* later */
}
static void scalar_delete(t_gobj *z, t_glist *glist)
{
/* nothing to do */
}
Ivica Bukvic
committed
extern void svg_grouptogui(t_glist *g, t_template *template, t_word *data);
extern void svg_parentwidgettogui(t_gobj *z, t_glist *owner, t_word *data,
t_template *template);
static void scalar_group_configure(t_scalar *x, t_glist *owner,
t_template *template, t_glist *gl, t_glist *parent)
{
t_gobj *y;
char tagbuf[MAXPDSTRING];
sprintf(tagbuf, "dgroup%lx.%lx", (long unsigned int)gl,
(long unsigned int)x->sc_vec);
char parentbuf[MAXPDSTRING];
sprintf(parentbuf, "dgroup%lx.%lx", (long unsigned int)parent,
(long unsigned int)x->sc_vec);
gui_start_vmess("gui_draw_configure_all", "xs",
glist_getcanvas(owner), tagbuf);
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
svg_grouptogui(gl, template, x->sc_vec);
gui_end_vmess();
for (y = gl->gl_list; y; y = y->g_next)
{
if (pd_class(&y->g_pd) == canvas_class &&
((t_glist *)y)->gl_svg)
{
scalar_group_configure(x, owner, template, (t_glist *)y, gl);
}
t_parentwidgetbehavior *wb = pd_getparentwidget(&y->g_pd);
if (!wb) continue;
//(*wb->w_parentvisfn)(y, owner, gl, x, x->sc_vec, template,
// 0, 0, vis);
svg_parentwidgettogui(y, owner, x->sc_vec, template);
}
}
void scalar_configure(t_scalar *x, t_glist *owner)
{
int vis = glist_isvisible(owner);
if (vis)
{
//fprintf(stderr,"scalar_vis %d %lx\n", vis, (t_int)z);
x->sc_bboxcache = 0;
t_template *template = template_findbyname(x->sc_template);
t_canvas *templatecanvas = template_findcanvas(template);
t_gobj *y;
t_float basex, basey;
scalar_getbasexy(x, &basex, &basey);
/* if we don't know how to draw it, make a small rectangle */
t_float xscale = glist_xtopixels(owner, 1) - glist_xtopixels(owner, 0);
t_float yscale = glist_ytopixels(owner, 1) - glist_ytopixels(owner, 0);
char tagbuf[MAXPDSTRING];
sprintf(tagbuf, "scalar%lx", (long unsigned int)x->sc_vec);
gui_vmess("gui_scalar_configure_gobj", "xsiffffii",
glist_getcanvas(owner),
tagbuf,
glist_isselected(owner, &x->sc_gobj),
xscale, 0.0, 0.0, yscale,
(int)glist_xtopixels(owner, basex),
(int)glist_ytopixels(owner, basey));
char groupbuf[MAXPDSTRING];
// Quick hack to make gui_create_scalar_group more general (so we
// don't have to tack on "gobj" manually)
//Not sure if we need this here...
//sprintf(tagbuf, "scalar%lxgobj", (long unsigned int)x->sc_vec);
//sprintf(groupbuf, "dgroup%lx.%lx", (long unsigned int)templatecanvas,
// (long unsigned int)x->sc_vec);
//gui_vmess("gui_create_scalar_group", "xss",
// glist_getcanvas(owner), groupbuf, tagbuf);
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
//sys_vgui("pdtk_bind_scalar_mouseover "
// ".x%lx.c .x%lx.x%lx.template%lx {.x%lx}\n",
// glist_getcanvas(owner), glist_getcanvas(owner),
// owner, x->sc_vec, x);
for (y = templatecanvas->gl_list; y; y = y->g_next)
{
t_parentwidgetbehavior *wb = pd_getparentwidget(&y->g_pd);
if (!wb)
{
/* check subpatches for more drawing commands.
(Optimized to only search [group] subpatches) */
if (pd_class(&y->g_pd) == canvas_class &&
((t_glist *)y)->gl_svg)
{
scalar_group_configure(x, owner, template,
(t_glist *)y, templatecanvas);
}
continue;
}
//(*wb->w_parentvisfn)(y, owner, 0, x, x->sc_vec, template,
// basex, basey, vis);
svg_parentwidgettogui(y, owner, x->sc_vec, template);
}
if (glist_isselected(owner, &x->sc_gobj))
{
// we removed this because it caused infinite recursion
// in the scalar-help.pd example
//scalar_select(z, owner, 1);
scalar_drawselectrect(x, owner, 0);
scalar_drawselectrect(x, owner, 1);
}
}
}
Ivica Bukvic
committed
static void scalar_groupvis(t_scalar *x, t_glist *owner, t_template *template,
t_glist *gl, t_glist *parent, int vis)
{
t_gobj *y;
if (vis)
{
//sys_vgui(".x%lx.c create group -tags {.dgroup%lx.%lx} "
// "-parent {.dgroup%lx.%lx}\\\n",
// glist_getcanvas(owner), gl, x->sc_vec,
// parent, x->sc_vec);
char tagbuf[MAXPDSTRING];
sprintf(tagbuf, "dgroup%lx.%lx", (long unsigned int)gl,
(long unsigned int)x->sc_vec);
char parentbuf[MAXPDSTRING];
sprintf(parentbuf, "dgroup%lx.%lx", (long unsigned int)parent,
(long unsigned int)x->sc_vec);
gui_start_vmess("gui_create_scalar_group", "xss",
glist_getcanvas(owner), tagbuf, parentbuf);
Ivica Bukvic
committed
svg_grouptogui(gl, template, x->sc_vec);
Ivica Bukvic
committed
}
for (y = gl->gl_list; y; y = y->g_next)
{
if (pd_class(&y->g_pd) == canvas_class &&
((t_glist *)y)->gl_svg)
Ivica Bukvic
committed
{
scalar_groupvis(x, owner, template, (t_glist *)y, gl, vis);
Ivica Bukvic
committed
}
t_parentwidgetbehavior *wb = pd_getparentwidget(&y->g_pd);
if (!wb) continue;
(*wb->w_parentvisfn)(y, owner, gl, x, x->sc_vec, template,
0, 0, vis);
}
}
/* At present, scalars have a three-level hierarchy in tkpath,
with two levels accessible by the user from within Pd:
scalar - ".scalar%lx", x->sc_vec
| tkpath group with matrix derived from x/y fields,
| gop basexy, and gop scaling values. This group is
| not configurable by the user. This means that the
| [draw group] below can ignore basexy and gop junk
| when computing the transform matrix.
Ivica Bukvic
committed
v
group - ".dgroup%lx.%lx", templatecanvas, x->sc_vec
| group used as parent for all the toplevel drawing
| commands of the scalar (i.e., the ones located on
| the same canvas as the [struct]). Its matrix and
| options aren't yet accessible by the user.
Ivica Bukvic
committed
v
(draw - ".draw%lx.%lx", (t_draw *ptr), x->sc_vec
| the actual drawing command: rectangle, path, etc.
Ivica Bukvic
committed
or Each has its own matrix and options which can set
scelem with messages to the corresponding [draw] object.
or - ds arrays can nest arbitrarily deep. Scelem is for
group) data structure arrays. group is for more groups.
|
v
etc.
Ivica Bukvic
committed
The tag "blankscalar" is for scalars that don't have a visual
representation, but maybe this can just be merged with "scalar"
*/
static void scalar_vis(t_gobj *z, t_glist *owner, int vis)
{
//fprintf(stderr,"scalar_vis %d %lx\n", vis, (t_int)z);
Ivica Bukvic
committed
x->sc_bboxcache = 0;
t_template *template = template_findbyname(x->sc_template);
t_canvas *templatecanvas = template_findcanvas(template);
t_gobj *y;
scalar_getbasexy(x, &basex, &basey);
/* if we don't know how to draw it, make a small rectangle */
if (!templatecanvas)
{
if (vis)
{
int x1 = glist_xtopixels(owner, basex);
int y1 = glist_ytopixels(owner, basey);
sys_vgui(".x%lx.c create prect %d %d %d %d "
"-tags {blankscalar%lx %s}\n",
glist_getcanvas(owner), x1-1, y1-1, x1+1, y1+1, x,
(glist_isselected(owner, &x->sc_gobj) ?
"scalar_selected" : ""));
else sys_vgui(".x%lx.c delete blankscalar%lx\n",
glist_getcanvas(owner), x);
//else sys_vgui(".x%lx.c delete blankscalar%lx\n",
// glist_getcanvas(owner), x);
Ivica Bukvic
committed
if (vis)
{
t_float xscale = glist_xtopixels(owner, 1) - glist_xtopixels(owner, 0);
t_float yscale = glist_ytopixels(owner, 1) - glist_ytopixels(owner, 0);
/* we translate the .scalar%lx group to displace it on the tk side.
This is the outermost group for the scalar, something like a
poor man's viewport.
Also:
* the default stroke is supposed to be "none"
* default fill is supposed to be black.
* stroke-linejoin should be "miter", not "round"
To fix these, we set the correct fill/stroke/strokelinjoin options
here on the .scalar%lx group. (Notice also that tkpath doesn't
understand "None"-- instead we must send an empty symbol.) */
//sys_vgui(".x%lx.c create group -tags {.scalar%lx %s} "
// "-matrix { {%g %g} {%g %g} {%d %d} } "
// "-stroke \"\" -fill black -strokelinejoin miter\n",
// glist_getcanvas(owner), x->sc_vec,
// (glist_isselected(owner, &x->sc_gobj) ? "scalar_selected" : ""),
// xscale, 0.0, 0.0, yscale, (int)glist_xtopixels(owner, basex),
// (int)glist_ytopixels(owner, basey)
// );
char tagbuf[MAXPDSTRING];
sprintf(tagbuf, "scalar%lx", (long unsigned int)x->sc_vec);
gui_vmess("gui_create_scalar", "xsiffffiii",
glist_getcanvas(owner),
tagbuf,
glist_isselected(owner, &x->sc_gobj),
xscale, 0.0, 0.0, yscale,
(int)glist_xtopixels(owner, basex),
Jonathan Wilkes
committed
(int)glist_ytopixels(owner, basey),
glist_istoplevel(owner));
//sys_vgui(".x%lx.c create group -tags {.dgroup%lx.%lx} "
// "-parent {.scalar%lx}\n",
// glist_getcanvas(owner), templatecanvas, x->sc_vec, x->sc_vec);
char groupbuf[MAXPDSTRING];
// Quick hack to make gui_create_scalar_group more general (so we
// don't have to tack on "gobj" manually)
sprintf(tagbuf, "scalar%lxgobj", (long unsigned int)x->sc_vec);
sprintf(groupbuf, "dgroup%lx.%lx", (long unsigned int)templatecanvas,
(long unsigned int)x->sc_vec);
gui_vmess("gui_create_scalar_group", "xss",
glist_getcanvas(owner), groupbuf, tagbuf);
Ivica Bukvic
committed
sys_vgui("pdtk_bind_scalar_mouseover "
".x%lx.c .x%lx.x%lx.template%lx {.x%lx}\n",
glist_getcanvas(owner), glist_getcanvas(owner),
owner, x->sc_vec, x);
Ivica Bukvic
committed
}
Ivica Bukvic
committed
/* warning: don't need--- have recursive func. */
for (y = templatecanvas->gl_list; y; y = y->g_next)
{
t_parentwidgetbehavior *wb = pd_getparentwidget(&y->g_pd);
Ivica Bukvic
committed
if (!wb)
{
/* check subpatches for more drawing commands.
(Optimized to only search [group] subpatches) */
Ivica Bukvic
committed
if (pd_class(&y->g_pd) == canvas_class &&
((t_glist *)y)->gl_svg)
{
Ivica Bukvic
committed
scalar_groupvis(x, owner, template,
(t_glist *)y, templatecanvas, vis);
Ivica Bukvic
committed
continue;
}
(*wb->w_parentvisfn)(y, owner, 0, x, x->sc_vec, template,
basex, basey, vis);
Ivica Bukvic
committed
if (!vis)
//sys_vgui(".x%lx.c delete .scalar%lx\n", glist_getcanvas(owner),
// x->sc_vec);
char tagbuf[MAXPDSTRING];
sprintf(tagbuf, "scalar%lx", (long unsigned int)x->sc_vec);
gui_vmess("gui_scalar_erase", "xs",
glist_getcanvas(owner), tagbuf);
Ivica Bukvic
committed
sys_unqueuegui(x);
// we removed this because it caused infinite recursion
// in the scalar-help.pd example
//scalar_select(z, owner, 1);
post("here we are in scalar vis, selected...");
scalar_drawselectrect(x, owner, 0);
scalar_drawselectrect(x, owner, 1);
}
}
static void scalar_doredraw(t_gobj *client, t_glist *glist)
{
scalar_vis(client, glist, 0);
scalar_vis(client, glist, 1);
if (glist_isselected(glist_getcanvas(glist), (t_gobj *)glist))
{
//fprintf(stderr,"yes\n");
sys_vgui("pdtk_select_all_gop_widgets .x%lx %lx %d\n",
glist_getcanvas(glist), glist, 1);
}
Mathieu L Bouchard
committed
canvas_getscroll(glist_getcanvas(glist));
}
void scalar_redraw(t_scalar *x, t_glist *glist)
{
if (glist_isvisible(glist))
scalar_doredraw((t_gobj *)x, glist);
//sys_queuegui(x, glist, scalar_doredraw);
/* here we call the parentclickfns for drawing commands.
We recurse all the way to the end of the glist (and, for the
groups, as deep as they go) and then call the functions from the bottom up.
This way the clicks can "bubble" up from the bottom. This has the effect
that the shape visually closest to the front gets called first.
This is called "event bubbling" in the HTML5 DOM. You can also call
events in top down order in HTML5/SVG as well (called "capturing" or
"trickling"). But because some old version of Internet Explorer only did
bubbling, that is the most widely used model today, and the only one