summaryrefslogtreecommitdiff
path: root/apps/plugins/pdbox/PDa/src/g_graph.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/plugins/pdbox/PDa/src/g_graph.c')
-rw-r--r--apps/plugins/pdbox/PDa/src/g_graph.c1111
1 files changed, 0 insertions, 1111 deletions
diff --git a/apps/plugins/pdbox/PDa/src/g_graph.c b/apps/plugins/pdbox/PDa/src/g_graph.c
index 6a64900213..c81bac10b8 100644
--- a/apps/plugins/pdbox/PDa/src/g_graph.c
+++ b/apps/plugins/pdbox/PDa/src/g_graph.c
@@ -1110,1115 +1110,4 @@ void g_graph_setup(void)
1110 class_addmethod(canvas_class, (t_method)glist_sort, 1110 class_addmethod(canvas_class, (t_method)glist_sort,
1111 gensym("sort"), A_NULL); 1111 gensym("sort"), A_NULL);
1112} 1112}
1113/* Copyright (c) 1997-2001 Miller Puckette and others.
1114* For information on usage and redistribution, and for a DISCLAIMER OF ALL
1115* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
1116
1117/* This file deals with the behavior of glists as either "text objects" or
1118"graphs" inside another glist. LATER move the inlet/outlet code of g_canvas.c
1119to this file... */
1120
1121#include <stdlib.h>
1122#include "m_pd.h"
1123#include "t_tk.h"
1124#include "g_canvas.h"
1125#include <stdio.h>
1126#include <string.h>
1127
1128/* ---------------------- forward definitions ----------------- */
1129
1130static void graph_vis(t_gobj *gr, t_glist *unused_glist, int vis);
1131static void graph_graphrect(t_gobj *z, t_glist *glist,
1132 int *xp1, int *yp1, int *xp2, int *yp2);
1133static void graph_getrect(t_gobj *z, t_glist *glist,
1134 int *xp1, int *yp1, int *xp2, int *yp2);
1135
1136/* -------------------- maintaining the list -------------------- */
1137
1138void glist_add(t_glist *x, t_gobj *y)
1139{
1140 t_object *ob;
1141 y->g_next = 0;
1142 if (!x->gl_list) x->gl_list = y;
1143 else
1144 {
1145 t_gobj *y2;
1146 for (y2 = x->gl_list; y2->g_next; y2 = y2->g_next);
1147 y2->g_next = y;
1148 }
1149 if (x->gl_editor && (ob = pd_checkobject(&y->g_pd)))
1150 rtext_new(x, ob);
1151 if (glist_isvisible(x))
1152 gobj_vis(y, x, 1);
1153 if (class_isdrawcommand(y->g_pd))
1154 canvas_redrawallfortemplate(glist_getcanvas(x));
1155}
1156
1157 /* this is to protect against a hairy problem in which deleting
1158 a sub-canvas might delete an inlet on a box, after the box had
1159 been invisible-ized, so that we have to protect against redrawing it! */
1160int canvas_setdeleting(t_canvas *x, int flag)
1161{
1162 int ret = x->gl_isdeleting;
1163 x->gl_isdeleting = flag;
1164 return (ret);
1165}
1166
1167 /* delete an object from a glist and free it */
1168void glist_delete(t_glist *x, t_gobj *y)
1169{
1170 t_gobj *g;
1171 t_object *ob;
1172 t_gotfn chkdsp = zgetfn(&y->g_pd, gensym("dsp"));
1173 t_canvas *canvas = glist_getcanvas(x);
1174 int drawcommand = class_isdrawcommand(y->g_pd);
1175 int wasdeleting;
1176
1177 wasdeleting = canvas_setdeleting(canvas, 1);
1178 if (x->gl_editor)
1179 {
1180 if (x->gl_editor->e_grab == y) x->gl_editor->e_grab = 0;
1181 if (glist_isselected(x, y)) glist_deselect(x, y);
1182
1183 /* HACK -- we had phantom outlets not getting erased on the
1184 screen because the canvas_setdeleting() mechanism is too
1185 crude. LATER carefully set up rules for when the rtexts
1186 should exist, so that they stay around until all the
1187 steps of becoming invisible are done. In the meantime, just
1188 zap the inlets and outlets here... */
1189 if (pd_class(&y->g_pd) == canvas_class)
1190 {
1191 t_glist *gl = (t_glist *)y;
1192 if (gl->gl_isgraph)
1193 {
1194 char tag[80];
1195 sprintf(tag, "graph%x", (int)gl);
1196 glist_eraseiofor(x, &gl->gl_obj, tag);
1197 }
1198 else
1199 {
1200 text_eraseborder(&gl->gl_obj, x,
1201 rtext_gettag(glist_findrtext(x, &gl->gl_obj)));
1202 }
1203 }
1204 }
1205 gobj_delete(y, x);
1206 if (glist_isvisible(canvas))
1207 gobj_vis(y, x, 0);
1208 if (x->gl_editor && (ob = pd_checkobject(&y->g_pd)))
1209 rtext_new(x, ob);
1210 if (x->gl_list == y) x->gl_list = y->g_next;
1211 else for (g = x->gl_list; g; g = g->g_next)
1212 if (g->g_next == y)
1213 {
1214 g->g_next = y->g_next;
1215 break;
1216 }
1217 pd_free(&y->g_pd);
1218 if (chkdsp) canvas_update_dsp();
1219 if (drawcommand) canvas_redrawallfortemplate(canvas);
1220 canvas_setdeleting(canvas, wasdeleting);
1221 x->gl_valid = ++glist_valid;
1222}
1223
1224 /* remove every object from a glist. Experimental. */
1225void glist_clear(t_glist *x)
1226{
1227 t_gobj *y, *y2;
1228 int dspstate = canvas_suspend_dsp();
1229 while (y = x->gl_list)
1230 glist_delete(x, y);
1231 canvas_resume_dsp(dspstate);
1232}
1233
1234void glist_retext(t_glist *glist, t_text *y)
1235{
1236 t_canvas *c = glist_getcanvas(glist);
1237 /* check that we have built rtexts yet. LATER need a better test. */
1238 if (glist->gl_editor && glist->gl_editor->e_rtext)
1239 {
1240 t_rtext *rt = glist_findrtext(glist, y);
1241 if (rt)
1242 rtext_retext(rt);
1243 }
1244}
1245
1246void glist_grab(t_glist *x, t_gobj *y, t_glistmotionfn motionfn,
1247 t_glistkeyfn keyfn, int xpos, int ypos)
1248{
1249 t_glist *x2 = glist_getcanvas(x);
1250 if (motionfn)
1251 x2->gl_editor->e_onmotion = MA_PASSOUT;
1252 else x2->gl_editor->e_onmotion = 0;
1253 x2->gl_editor->e_grab = y;
1254 x2->gl_editor->e_motionfn = motionfn;
1255 x2->gl_editor->e_keyfn = keyfn;
1256 x2->gl_editor->e_xwas = xpos;
1257 x2->gl_editor->e_ywas = ypos;
1258}
1259
1260t_canvas *glist_getcanvas(t_glist *x)
1261{
1262 while (x->gl_owner && !x->gl_havewindow && x->gl_isgraph)
1263 x = x->gl_owner;
1264 return((t_canvas *)x);
1265}
1266
1267static float gobj_getxforsort(t_gobj *g)
1268{
1269 if (pd_class(&g->g_pd) == scalar_class)
1270 {
1271 float x1, y1;
1272 scalar_getbasexy((t_scalar *)g, &x1, &y1);
1273 return(x1);
1274 }
1275 else return (0);
1276}
1277
1278static t_gobj *glist_merge(t_glist *x, t_gobj *g1, t_gobj *g2)
1279{
1280 t_gobj *g = 0, *g9 = 0;
1281 float f1 = 0, f2 = 0;
1282 if (g1)
1283 f1 = gobj_getxforsort(g1);
1284 if (g2)
1285 f2 = gobj_getxforsort(g2);
1286 while (1)
1287 {
1288 if (g1)
1289 {
1290 if (g2)
1291 {
1292 if (f1 <= f2)
1293 goto put1;
1294 else goto put2;
1295 }
1296 else goto put1;
1297 }
1298 else if (g2)
1299 goto put2;
1300 else break;
1301 put1:
1302 if (g9)
1303 g9->g_next = g1, g9 = g1;
1304 else g9 = g = g1;
1305 if (g1 = g1->g_next)
1306 f1 = gobj_getxforsort(g1);
1307 g9->g_next = 0;
1308 continue;
1309 put2:
1310 if (g9)
1311 g9->g_next = g2, g9 = g2;
1312 else g9 = g = g2;
1313 if (g2 = g2->g_next)
1314 f2 = gobj_getxforsort(g2);
1315 g9->g_next = 0;
1316 continue;
1317 }
1318 return (g);
1319}
1320
1321static t_gobj *glist_dosort(t_glist *x,
1322 t_gobj *g, int nitems)
1323{
1324 if (nitems < 2)
1325 return (g);
1326 else
1327 {
1328 int n1 = nitems/2, n2 = nitems - n1, i;
1329 t_gobj *g2, *g3;
1330 for (g2 = g, i = n1-1; i--; g2 = g2->g_next)
1331 ;
1332 g3 = g2->g_next;
1333 g2->g_next = 0;
1334 g = glist_dosort(x, g, n1);
1335 g3 = glist_dosort(x, g3, n2);
1336 return (glist_merge(x, g, g3));
1337 }
1338}
1339
1340void glist_sort(t_glist *x)
1341{
1342 int nitems = 0, foo = 0;
1343 float lastx = -1e37;
1344 t_gobj *g;
1345 for (g = x->gl_list; g; g = g->g_next)
1346 {
1347 float x1 = gobj_getxforsort(g);
1348 if (x1 < lastx)
1349 foo = 1;
1350 lastx = x1;
1351 nitems++;
1352 }
1353 if (foo)
1354 x->gl_list = glist_dosort(x, x->gl_list, nitems);
1355}
1356
1357void glist_cleanup(t_glist *x)
1358{
1359 freebytes(x->gl_xlabel, x->gl_nxlabels * sizeof(*(x->gl_xlabel)));
1360 freebytes(x->gl_ylabel, x->gl_nylabels * sizeof(*(x->gl_ylabel)));
1361 gstub_cutoff(x->gl_stub);
1362}
1363
1364void glist_free(t_glist *x)
1365{
1366 glist_cleanup(x);
1367 freebytes(x, sizeof(*x));
1368}
1369
1370/* --------------- inlets and outlets ----------- */
1371
1372
1373t_inlet *canvas_addinlet(t_canvas *x, t_pd *who, t_symbol *s)
1374{
1375 t_inlet *ip = inlet_new(&x->gl_obj, who, s, 0);
1376 if (!x->gl_loading && x->gl_owner && glist_isvisible(x->gl_owner))
1377 {
1378 gobj_vis(&x->gl_gobj, x->gl_owner, 0);
1379 gobj_vis(&x->gl_gobj, x->gl_owner, 1);
1380 canvas_fixlinesfor(x->gl_owner, &x->gl_obj);
1381 }
1382 if (!x->gl_loading) canvas_resortinlets(x);
1383 return (ip);
1384}
1385
1386void canvas_rminlet(t_canvas *x, t_inlet *ip)
1387{
1388 t_canvas *owner = x->gl_owner;
1389 int redraw = (owner && glist_isvisible(owner) && (!owner->gl_isdeleting)
1390 && glist_istoplevel(owner));
1391
1392 if (owner) canvas_deletelinesforio(owner, &x->gl_obj, ip, 0);
1393 if (redraw)
1394 gobj_vis(&x->gl_gobj, x->gl_owner, 0);
1395 inlet_free(ip);
1396 if (redraw)
1397 {
1398 gobj_vis(&x->gl_gobj, x->gl_owner, 1);
1399 canvas_fixlinesfor(x->gl_owner, &x->gl_obj);
1400 }
1401}
1402
1403extern t_inlet *vinlet_getit(t_pd *x);
1404extern void obj_moveinletfirst(t_object *x, t_inlet *i);
1405
1406void canvas_resortinlets(t_canvas *x)
1407{
1408 int ninlets = 0, i, j, xmax;
1409 t_gobj *y, **vec, **vp, **maxp;
1410
1411 for (ninlets = 0, y = x->gl_list; y; y = y->g_next)
1412 if (pd_class(&y->g_pd) == vinlet_class) ninlets++;
1413
1414 if (ninlets < 2) return;
1415
1416 vec = (t_gobj **)getbytes(ninlets * sizeof(*vec));
1417
1418 for (y = x->gl_list, vp = vec; y; y = y->g_next)
1419 if (pd_class(&y->g_pd) == vinlet_class) *vp++ = y;
1420
1421 for (i = ninlets; i--;)
1422 {
1423 t_inlet *ip;
1424 for (vp = vec, xmax = -0x7fffffff, maxp = 0, j = ninlets;
1425 j--; vp++)
1426 {
1427 int x1, y1, x2, y2;
1428 t_gobj *g = *vp;
1429 if (!g) continue;
1430 gobj_getrect(g, x, &x1, &y1, &x2, &y2);
1431 if (x1 > xmax) xmax = x1, maxp = vp;
1432 }
1433 if (!maxp) break;
1434 y = *maxp;
1435 *maxp = 0;
1436 ip = vinlet_getit(&y->g_pd);
1437
1438 obj_moveinletfirst(&x->gl_obj, ip);
1439 }
1440 freebytes(vec, ninlets * sizeof(*vec));
1441 if (x->gl_owner && glist_isvisible(x->gl_owner))
1442 canvas_fixlinesfor(x->gl_owner, &x->gl_obj);
1443}
1444
1445t_outlet *canvas_addoutlet(t_canvas *x, t_pd *who, t_symbol *s)
1446{
1447 t_outlet *op = outlet_new(&x->gl_obj, s);
1448 if (!x->gl_loading && x->gl_owner && glist_isvisible(x->gl_owner))
1449 {
1450 gobj_vis(&x->gl_gobj, x->gl_owner, 0);
1451 gobj_vis(&x->gl_gobj, x->gl_owner, 1);
1452 canvas_fixlinesfor(x->gl_owner, &x->gl_obj);
1453 }
1454 if (!x->gl_loading) canvas_resortoutlets(x);
1455 return (op);
1456}
1457
1458void canvas_rmoutlet(t_canvas *x, t_outlet *op)
1459{
1460 t_canvas *owner = x->gl_owner;
1461 int redraw = (owner && glist_isvisible(owner) && (!owner->gl_isdeleting)
1462 && glist_istoplevel(owner));
1463
1464 if (owner) canvas_deletelinesforio(owner, &x->gl_obj, 0, op);
1465 if (redraw)
1466 gobj_vis(&x->gl_gobj, x->gl_owner, 0);
1467
1468 outlet_free(op);
1469 if (redraw)
1470 {
1471 gobj_vis(&x->gl_gobj, x->gl_owner, 1);
1472 canvas_fixlinesfor(x->gl_owner, &x->gl_obj);
1473 }
1474}
1475
1476extern t_outlet *voutlet_getit(t_pd *x);
1477extern void obj_moveoutletfirst(t_object *x, t_outlet *i);
1478
1479void canvas_resortoutlets(t_canvas *x)
1480{
1481 int noutlets = 0, i, j, xmax;
1482 t_gobj *y, **vec, **vp, **maxp;
1483
1484 for (noutlets = 0, y = x->gl_list; y; y = y->g_next)
1485 if (pd_class(&y->g_pd) == voutlet_class) noutlets++;
1486
1487 if (noutlets < 2) return;
1488
1489 vec = (t_gobj **)getbytes(noutlets * sizeof(*vec));
1490
1491 for (y = x->gl_list, vp = vec; y; y = y->g_next)
1492 if (pd_class(&y->g_pd) == voutlet_class) *vp++ = y;
1493
1494 for (i = noutlets; i--;)
1495 {
1496 t_outlet *ip;
1497 for (vp = vec, xmax = -0x7fffffff, maxp = 0, j = noutlets;
1498 j--; vp++)
1499 {
1500 int x1, y1, x2, y2;
1501 t_gobj *g = *vp;
1502 if (!g) continue;
1503 gobj_getrect(g, x, &x1, &y1, &x2, &y2);
1504 if (x1 > xmax) xmax = x1, maxp = vp;
1505 }
1506 if (!maxp) break;
1507 y = *maxp;
1508 *maxp = 0;
1509 ip = voutlet_getit(&y->g_pd);
1510
1511 obj_moveoutletfirst(&x->gl_obj, ip);
1512 }
1513 freebytes(vec, noutlets * sizeof(*vec));
1514 if (x->gl_owner && glist_isvisible(x->gl_owner))
1515 canvas_fixlinesfor(x->gl_owner, &x->gl_obj);
1516}
1517
1518/* ----------calculating coordinates and controlling appearance --------- */
1519
1520
1521static void graph_bounds(t_glist *x, t_floatarg x1, t_floatarg y1,
1522 t_floatarg x2, t_floatarg y2)
1523{
1524 x->gl_x1 = x1;
1525 x->gl_x2 = x2;
1526 x->gl_y1 = y1;
1527 x->gl_y2 = y2;
1528 if (x->gl_x2 == x->gl_x1 ||
1529 x->gl_y2 == x->gl_y1)
1530 {
1531 error("graph: empty bounds rectangle");
1532 x1 = y1 = 0;
1533 x2 = y2 = 1;
1534 }
1535 glist_redraw(x);
1536}
1537
1538static void graph_xticks(t_glist *x,
1539 t_floatarg point, t_floatarg inc, t_floatarg f)
1540{
1541 x->gl_xtick.k_point = point;
1542 x->gl_xtick.k_inc = inc;
1543 x->gl_xtick.k_lperb = f;
1544 glist_redraw(x);
1545}
1546
1547static void graph_yticks(t_glist *x,
1548 t_floatarg point, t_floatarg inc, t_floatarg f)
1549{
1550 x->gl_ytick.k_point = point;
1551 x->gl_ytick.k_inc = inc;
1552 x->gl_ytick.k_lperb = f;
1553 glist_redraw(x);
1554}
1555
1556static void graph_xlabel(t_glist *x, t_symbol *s, int argc, t_atom *argv)
1557{
1558 int i;
1559 if (argc < 1) error("graph_xlabel: no y value given");
1560 else
1561 {
1562 x->gl_xlabely = atom_getfloat(argv);
1563 argv++; argc--;
1564 x->gl_xlabel = (t_symbol **)t_resizebytes(x->gl_xlabel,
1565 x->gl_nxlabels * sizeof (t_symbol *), argc * sizeof (t_symbol *));
1566 x->gl_nxlabels = argc;
1567 for (i = 0; i < argc; i++) x->gl_xlabel[i] = atom_gensym(&argv[i]);
1568 }
1569 glist_redraw(x);
1570}
1571
1572static void graph_ylabel(t_glist *x, t_symbol *s, int argc, t_atom *argv)
1573{
1574 int i;
1575 if (argc < 1) error("graph_ylabel: no x value given");
1576 else
1577 {
1578 x->gl_ylabelx = atom_getfloat(argv);
1579 argv++; argc--;
1580 x->gl_ylabel = (t_symbol **)t_resizebytes(x->gl_ylabel,
1581 x->gl_nylabels * sizeof (t_symbol *), argc * sizeof (t_symbol *));
1582 x->gl_nylabels = argc;
1583 for (i = 0; i < argc; i++) x->gl_ylabel[i] = atom_gensym(&argv[i]);
1584 }
1585 glist_redraw(x);
1586}
1587 1113
1588/****** routines to convert pixels to X or Y value and vice versa ******/
1589
1590 /* convert an x pixel value to an x coordinate value */
1591float glist_pixelstox(t_glist *x, float xpix)
1592{
1593 /* if we appear as a text box on parent, our range in our
1594 coordinates (x1, etc.) specifies the coordinate range
1595 of a one-pixel square at top left of the window. */
1596 if (!x->gl_isgraph)
1597 return (x->gl_x1 + (x->gl_x2 - x->gl_x1) * xpix);
1598
1599 /* if we're a graph when shown on parent, but own our own
1600 window right now, our range in our coordinates (x1, etc.) is spread
1601 over the visible window size, given by screenx1, etc. */
1602 else if (x->gl_isgraph && x->gl_havewindow)
1603 return (x->gl_x1 + (x->gl_x2 - x->gl_x1) *
1604 (xpix) / (x->gl_screenx2 - x->gl_screenx1));
1605
1606 /* otherwise, we appear in a graph within a parent glist,
1607 so get our screen rectangle on parent and transform. */
1608 else
1609 {
1610 int x1, y1, x2, y2;
1611 if (!x->gl_owner)
1612 bug("glist_pixelstox");
1613 graph_graphrect(&x->gl_gobj, x->gl_owner, &x1, &y1, &x2, &y2);
1614 return (x->gl_x1 + (x->gl_x2 - x->gl_x1) *
1615 (xpix - x1) / (x2 - x1));
1616 }
1617}
1618
1619float glist_pixelstoy(t_glist *x, float ypix)
1620{
1621 if (!x->gl_isgraph)
1622 return (x->gl_y1 + (x->gl_y2 - x->gl_y1) * ypix);
1623 else if (x->gl_isgraph && x->gl_havewindow)
1624 return (x->gl_y1 + (x->gl_y2 - x->gl_y1) *
1625 (ypix) / (x->gl_screeny2 - x->gl_screeny1));
1626 else
1627 {
1628 int x1, y1, x2, y2;
1629 if (!x->gl_owner)
1630 bug("glist_pixelstox");
1631 graph_graphrect(&x->gl_gobj, x->gl_owner, &x1, &y1, &x2, &y2);
1632 return (x->gl_y1 + (x->gl_y2 - x->gl_y1) *
1633 (ypix - y1) / (y2 - y1));
1634 }
1635}
1636
1637 /* convert an x coordinate value to an x pixel location in window */
1638float glist_xtopixels(t_glist *x, float xval)
1639{
1640 if (!x->gl_isgraph)
1641 return ((xval - x->gl_x1) / (x->gl_x2 - x->gl_x1));
1642 else if (x->gl_isgraph && x->gl_havewindow)
1643 return (x->gl_screenx2 - x->gl_screenx1) *
1644 (xval - x->gl_x1) / (x->gl_x2 - x->gl_x1);
1645 else
1646 {
1647 int x1, y1, x2, y2;
1648 if (!x->gl_owner)
1649 bug("glist_pixelstox");
1650 graph_graphrect(&x->gl_gobj, x->gl_owner, &x1, &y1, &x2, &y2);
1651 return (x1 + (x2 - x1) * (xval - x->gl_x1) / (x->gl_x2 - x->gl_x1));
1652 }
1653}
1654
1655float glist_ytopixels(t_glist *x, float yval)
1656{
1657 if (!x->gl_isgraph)
1658 return ((yval - x->gl_y1) / (x->gl_y2 - x->gl_y1));
1659 else if (x->gl_isgraph && x->gl_havewindow)
1660 return (x->gl_screeny2 - x->gl_screeny1) *
1661 (yval - x->gl_y1) / (x->gl_y2 - x->gl_y1);
1662 else
1663 {
1664 int x1, y1, x2, y2;
1665 if (!x->gl_owner)
1666 bug("glist_pixelstox");
1667 graph_graphrect(&x->gl_gobj, x->gl_owner, &x1, &y1, &x2, &y2);
1668 return (y1 + (y2 - y1) * (yval - x->gl_y1) / (x->gl_y2 - x->gl_y1));
1669 }
1670}
1671
1672 /* convert an X screen distance to an X coordinate increment.
1673 This is terribly inefficient;
1674 but probably not a big enough CPU hog to warrant optimizing. */
1675float glist_dpixtodx(t_glist *x, float dxpix)
1676{
1677 return (dxpix * (glist_pixelstox(x, 1) - glist_pixelstox(x, 0)));
1678}
1679
1680float glist_dpixtody(t_glist *x, float dypix)
1681{
1682 return (dypix * (glist_pixelstoy(x, 1) - glist_pixelstoy(x, 0)));
1683}
1684
1685 /* get the window location in pixels of a "text" object. The
1686 object's x and y positions are in pixels when the glist they're
1687 in is toplevel. If it's not, we convert to pixels on the parent
1688 window. */
1689int text_xpix(t_text *x, t_glist *glist)
1690{
1691 if (glist->gl_havewindow || !glist->gl_isgraph)
1692 return (x->te_xpix);
1693 else return (glist_xtopixels(glist,
1694 glist->gl_x1 + (glist->gl_x2 - glist->gl_x1) *
1695 x->te_xpix / (glist->gl_screenx2 - glist->gl_screenx1)));
1696}
1697
1698int text_ypix(t_text *x, t_glist *glist)
1699{
1700 if (glist->gl_havewindow || !glist->gl_isgraph)
1701 return (x->te_ypix);
1702 else return (glist_ytopixels(glist,
1703 glist->gl_y1 + (glist->gl_y2 - glist->gl_y1) *
1704 x->te_ypix / (glist->gl_screeny2 - glist->gl_screeny1)));
1705}
1706
1707 /* redraw all the items in a glist. We construe this to mean
1708 redrawing in its own window and on parent, as needed in each case.
1709 This is too conservative -- for instance, when you draw an "open"
1710 rectangle on the parent, you shouldn't have to redraw the window! */
1711void glist_redraw(t_glist *x)
1712{
1713 if (glist_isvisible(x))
1714 {
1715 /* LATER fix the graph_vis() code to handle both cases */
1716 if (glist_istoplevel(x))
1717 {
1718 t_gobj *g;
1719 t_linetraverser t;
1720 t_outconnect *oc;
1721 for (g = x->gl_list; g; g = g->g_next)
1722 {
1723 gobj_vis(g, x, 0);
1724 gobj_vis(g, x, 1);
1725 }
1726 /* redraw all the lines */
1727 linetraverser_start(&t, x);
1728 while (oc = linetraverser_next(&t))
1729 sys_vgui(".x%x.c coords l%x %d %d %d %d\n",
1730 glist_getcanvas(x), oc,
1731 t.tr_lx1, t.tr_ly1, t.tr_lx2, t.tr_ly2);
1732 }
1733 if (x->gl_owner)
1734 {
1735 graph_vis(&x->gl_gobj, x->gl_owner, 0);
1736 graph_vis(&x->gl_gobj, x->gl_owner, 1);
1737 }
1738 }
1739}
1740
1741/* --------------------------- widget behavior ------------------- */
1742
1743extern t_widgetbehavior text_widgetbehavior;
1744
1745 /* Note that some code in here would also be useful for drawing
1746 graph decorations in toplevels... */
1747static void graph_vis(t_gobj *gr, t_glist *parent_glist, int vis)
1748{
1749 t_glist *x = (t_glist *)gr;
1750 char tag[50];
1751 t_gobj *g;
1752 int x1, y1, x2, y2;
1753 /* ordinary subpatches: just act like a text object */
1754 if (!x->gl_isgraph)
1755 {
1756 text_widgetbehavior.w_visfn(gr, parent_glist, vis);
1757 return;
1758 }
1759
1760 if (vis && canvas_showtext(x))
1761 rtext_draw(glist_findrtext(parent_glist, &x->gl_obj));
1762 graph_getrect(gr, parent_glist, &x1, &y1, &x2, &y2);
1763 if (!vis)
1764 rtext_erase(glist_findrtext(parent_glist, &x->gl_obj));
1765
1766 sprintf(tag, "graph%x", (int)x);
1767 if (vis)
1768 glist_drawiofor(parent_glist, &x->gl_obj, 1,
1769 tag, x1, y1, x2, y2);
1770 else glist_eraseiofor(parent_glist, &x->gl_obj, tag);
1771 /* if we look like a graph but have been moved to a toplevel,
1772 just show the bounding rectangle */
1773 if (x->gl_havewindow)
1774 {
1775 if (vis)
1776 {
1777 sys_vgui(".x%x.c create polygon\
1778 %d %d %d %d %d %d %d %d %d %d -tags %s -fill #c0c0c0\n",
1779 glist_getcanvas(x->gl_owner),
1780 x1, y1, x1, y2, x2, y2, x2, y1, x1, y1, tag);
1781 }
1782 else
1783 {
1784 sys_vgui(".x%x.c delete %s\n",
1785 glist_getcanvas(x->gl_owner), tag);
1786 }
1787 return;
1788 }
1789 /* otherwise draw (or erase) us as a graph inside another glist. */
1790 if (vis)
1791 {
1792 int i;
1793 float f;
1794
1795 /* draw a rectangle around the graph */
1796 sys_vgui(".x%x.c create line\
1797 %d %d %d %d %d %d %d %d %d %d -tags %s\n",
1798 glist_getcanvas(x->gl_owner),
1799 x1, y1, x1, y2, x2, y2, x2, y1, x1, y1, tag);
1800
1801 /* draw ticks on horizontal borders. If lperb field is
1802 zero, this is disabled. */
1803 if (x->gl_xtick.k_lperb)
1804 {
1805 float upix, lpix;
1806 if (y2 < y1)
1807 upix = y1, lpix = y2;
1808 else upix = y2, lpix = y1;
1809 for (i = 0, f = x->gl_xtick.k_point;
1810 f < 0.99 * x->gl_x2 + 0.01*x->gl_x1; i++,
1811 f += x->gl_xtick.k_inc)
1812 {
1813 int tickpix = (i % x->gl_xtick.k_lperb ? 2 : 4);
1814 sys_vgui(".x%x.c create line %d %d %d %d -tags %s\n",
1815 glist_getcanvas(x->gl_owner),
1816 (int)glist_xtopixels(x, f), (int)upix,
1817 (int)glist_xtopixels(x, f), (int)upix - tickpix, tag);
1818 sys_vgui(".x%x.c create line %d %d %d %d -tags %s\n",
1819 glist_getcanvas(x->gl_owner),
1820 (int)glist_xtopixels(x, f), (int)lpix,
1821 (int)glist_xtopixels(x, f), (int)lpix + tickpix, tag);
1822 }
1823 for (i = 1, f = x->gl_xtick.k_point - x->gl_xtick.k_inc;
1824 f > 0.99 * x->gl_x1 + 0.01*x->gl_x2;
1825 i++, f -= x->gl_xtick.k_inc)
1826 {
1827 int tickpix = (i % x->gl_xtick.k_lperb ? 2 : 4);
1828 sys_vgui(".x%x.c create line %d %d %d %d -tags %s\n",
1829 glist_getcanvas(x->gl_owner),
1830 (int)glist_xtopixels(x, f), (int)upix,
1831 (int)glist_xtopixels(x, f), (int)upix - tickpix, tag);
1832 sys_vgui(".x%x.c create line %d %d %d %d -tags %s\n",
1833 glist_getcanvas(x->gl_owner),
1834 (int)glist_xtopixels(x, f), (int)lpix,
1835 (int)glist_xtopixels(x, f), (int)lpix + tickpix, tag);
1836 }
1837 }
1838
1839 /* draw ticks in vertical borders*/
1840 if (x->gl_ytick.k_lperb)
1841 {
1842 float ubound, lbound;
1843 if (x->gl_y2 < x->gl_y1)
1844 ubound = x->gl_y1, lbound = x->gl_y2;
1845 else ubound = x->gl_y2, lbound = x->gl_y1;
1846 for (i = 0, f = x->gl_ytick.k_point;
1847 f < 0.99 * ubound + 0.01 * lbound;
1848 i++, f += x->gl_ytick.k_inc)
1849 {
1850 int tickpix = (i % x->gl_ytick.k_lperb ? 2 : 4);
1851 sys_vgui(".x%x.c create line %d %d %d %d -tags %s\n",
1852 glist_getcanvas(x->gl_owner),
1853 x1, (int)glist_ytopixels(x, f),
1854 x1 + tickpix, (int)glist_ytopixels(x, f), tag);
1855 sys_vgui(".x%x.c create line %d %d %d %d -tags %s\n",
1856 glist_getcanvas(x->gl_owner),
1857 x2, (int)glist_ytopixels(x, f),
1858 x2 - tickpix, (int)glist_ytopixels(x, f), tag);
1859 }
1860 for (i = 1, f = x->gl_ytick.k_point - x->gl_ytick.k_inc;
1861 f > 0.99 * lbound + 0.01 * ubound;
1862 i++, f -= x->gl_ytick.k_inc)
1863 {
1864 int tickpix = (i % x->gl_ytick.k_lperb ? 2 : 4);
1865 sys_vgui(".x%x.c create line %d %d %d %d -tags %s\n",
1866 glist_getcanvas(x->gl_owner),
1867 x1, (int)glist_ytopixels(x, f),
1868 x1 + tickpix, (int)glist_ytopixels(x, f), tag);
1869 sys_vgui(".x%x.c create line %d %d %d %d -tags %s\n",
1870 glist_getcanvas(x->gl_owner),
1871 x2, (int)glist_ytopixels(x, f),
1872 x2 - tickpix, (int)glist_ytopixels(x, f), tag);
1873 }
1874 }
1875 /* draw x labels */
1876 for (i = 0; i < x->gl_nxlabels; i++)
1877 sys_vgui(".x%x.c create text\
1878 %d %d -text {%s} -font -*-courier-bold--normal--%d-* -tags %s\n",
1879 glist_getcanvas(x),
1880 (int)glist_xtopixels(x, atof(x->gl_xlabel[i]->s_name)),
1881 (int)glist_ytopixels(x, x->gl_xlabely), x->gl_xlabel[i]->s_name,
1882 glist_getfont(x), tag);
1883
1884 /* draw y labels */
1885 for (i = 0; i < x->gl_nylabels; i++)
1886 sys_vgui(".x%x.c create text\
1887 %d %d -text {%s} -font -*-courier-bold--normal--%d-* -tags %s\n",
1888 glist_getcanvas(x),
1889 (int)glist_xtopixels(x, x->gl_ylabelx),
1890 (int)glist_ytopixels(x, atof(x->gl_ylabel[i]->s_name)),
1891 x->gl_ylabel[i]->s_name,
1892 glist_getfont(x), tag);
1893
1894 /* draw contents of graph as glist */
1895 for (g = x->gl_list; g; g = g->g_next)
1896 gobj_vis(g, x, 1);
1897 }
1898 else
1899 {
1900 sys_vgui(".x%x.c delete %s\n",
1901 glist_getcanvas(x->gl_owner), tag);
1902 for (g = x->gl_list; g; g = g->g_next)
1903 gobj_vis(g, x, 0);
1904 }
1905}
1906
1907 /* get the graph's rectangle, not counting extra swelling for controls
1908 to keep them inside the graph. This is the "logical" pixel size. */
1909
1910static void graph_graphrect(t_gobj *z, t_glist *glist,
1911 int *xp1, int *yp1, int *xp2, int *yp2)
1912{
1913 t_glist *x = (t_glist *)z;
1914 int x1 = text_xpix(&x->gl_obj, glist);
1915 int y1 = text_ypix(&x->gl_obj, glist);
1916 int x2, y2;
1917#if 0 /* this used to adjust graph size when it was in another graph;
1918 now we just preserve the size. */
1919 /* same logic here as in text_xpix(): */
1920 if (glist->gl_havewindow)
1921 {
1922 x2 = x1 + x->gl_pixwidth;
1923 y2 = y1 + x->gl_pixheight;
1924 }
1925 else
1926 {
1927 x2 = glist_xtopixels(glist,
1928 glist->gl_x1 + (glist->gl_x2 - glist->gl_x1) *
1929 (x->gl_obj.te_xpix + x->gl_pixwidth) /
1930 (glist->gl_screenx2 - glist->gl_screenx1));
1931 y2 = glist_ytopixels(glist,
1932 glist->gl_y1 + (glist->gl_y2 - glist->gl_y1) *
1933 (x->gl_obj.te_ypix + x->gl_pixheight) /
1934 (glist->gl_screeny2 - glist->gl_screeny1));
1935 }
1936#endif
1937 x2 = x1 + x->gl_pixwidth;
1938 y2 = y1 + x->gl_pixheight;
1939
1940 *xp1 = x1;
1941 *yp1 = y1;
1942 *xp2 = x2;
1943 *yp2 = y2;
1944}
1945
1946 /* get the rectangle, enlarged to contain all the "contents" --
1947 meaning their formal bounds rectangles. */
1948static void graph_getrect(t_gobj *z, t_glist *glist,
1949 int *xp1, int *yp1, int *xp2, int *yp2)
1950{
1951 int x1 = 0x7fffffff, y1 = 0x7fffffff, x2 = -0x7fffffff, y2 = -0x7fffffff;
1952 t_glist *x = (t_glist *)z;
1953 if (x->gl_isgraph)
1954 {
1955 int hadwindow;
1956 t_gobj *g;
1957 t_text *ob;
1958 int x21, y21, x22, y22;
1959
1960 graph_graphrect(z, glist, &x1, &y1, &x2, &y2);
1961 if (canvas_showtext(x))
1962 {
1963 text_widgetbehavior.w_getrectfn(z, glist, &x21, &y21, &x22, &y22);
1964 if (x22 > x2)
1965 x2 = x22;
1966 if (y22 > y2)
1967 y2 = y22;
1968 }
1969 /* lie about whether we have our own window to affect gobj_getrect
1970 calls below. (LATER add argument to gobj_getrect()?) */
1971 hadwindow = x->gl_havewindow;
1972 x->gl_havewindow = 0;
1973 for (g = x->gl_list; g; g = g->g_next)
1974 if ((!(ob = pd_checkobject(&g->g_pd))) || text_shouldvis(ob, x))
1975 {
1976 /* don't do this for arrays, just let them hang outsize the
1977 box. */
1978 if (pd_class(&g->g_pd) == garray_class)
1979 continue;
1980 gobj_getrect(g, x, &x21, &y21, &x22, &y22);
1981 if (x22 > x2)
1982 x2 = x22;
1983 if (y22 > y2)
1984 y2 = y22;
1985 }
1986 x->gl_havewindow = hadwindow;
1987 }
1988 else text_widgetbehavior.w_getrectfn(z, glist, &x1, &y1, &x2, &y2);
1989 *xp1 = x1;
1990 *yp1 = y1;
1991 *xp2 = x2;
1992 *yp2 = y2;
1993}
1994
1995static void graph_displace(t_gobj *z, t_glist *glist, int dx, int dy)
1996{
1997 t_glist *x = (t_glist *)z;
1998 if (!x->gl_isgraph)
1999 text_widgetbehavior.w_displacefn(z, glist, dx, dy);
2000 else
2001 {
2002 x->gl_obj.te_xpix += dx;
2003 x->gl_obj.te_ypix += dy;
2004 glist_redraw(x);
2005 canvas_fixlinesfor(glist_getcanvas(glist), &x->gl_obj);
2006 }
2007}
2008
2009static void graph_select(t_gobj *z, t_glist *glist, int state)
2010{
2011 t_glist *x = (t_glist *)z;
2012 if (!x->gl_isgraph)
2013 text_widgetbehavior.w_selectfn(z, glist, state);
2014 else
2015 {
2016 t_rtext *y = glist_findrtext(glist, &x->gl_obj);
2017 if (canvas_showtext(x))
2018 rtext_select(y, state);
2019 sys_vgui(".x%x.c itemconfigure %sR -fill %s\n", glist,
2020 rtext_gettag(y), (state? "blue" : "black"));
2021 sys_vgui(".x%x.c itemconfigure graph%x -fill %s\n",
2022 glist_getcanvas(glist), z, (state? "blue" : "black"));
2023 }
2024}
2025
2026static void graph_activate(t_gobj *z, t_glist *glist, int state)
2027{
2028 t_glist *x = (t_glist *)z;
2029 if (canvas_showtext(x))
2030 text_widgetbehavior.w_activatefn(z, glist, state);
2031}
2032
2033#if 0
2034static void graph_delete(t_gobj *z, t_glist *glist)
2035{
2036 t_glist *x = (t_glist *)z;
2037 if (!x->gl_isgraph)
2038 text_widgetbehavior.w_deletefn(z, glist);
2039 else
2040 {
2041 t_gobj *y;
2042 while (y = x->gl_list) glist_delete(x, y);
2043#if 0 /* I think this was just wrong. */
2044 if (glist_isvisible(x))
2045 sys_vgui(".x%x.c delete graph%x\n", glist_getcanvas(glist), x);
2046#endif
2047 }
2048}
2049#endif
2050
2051static void graph_delete(t_gobj *z, t_glist *glist)
2052{
2053 t_glist *x = (t_glist *)z;
2054 t_gobj *y;
2055 text_widgetbehavior.w_deletefn(z, glist);
2056 while (y = x->gl_list)
2057 glist_delete(x, y);
2058}
2059
2060static float graph_lastxpix, graph_lastypix;
2061
2062static void graph_motion(void *z, t_floatarg dx, t_floatarg dy)
2063{
2064 t_glist *x = (t_glist *)z;
2065 float newxpix = graph_lastxpix + dx, newypix = graph_lastypix + dy;
2066 t_garray *a = (t_garray *)(x->gl_list);
2067 int oldx = 0.5 + glist_pixelstox(x, graph_lastxpix);
2068 int newx = 0.5 + glist_pixelstox(x, newxpix);
2069 t_sample *vec;
2070 int nelem, i;
2071 float oldy = glist_pixelstoy(x, graph_lastypix);
2072 float newy = glist_pixelstoy(x, newypix);
2073 graph_lastxpix = newxpix;
2074 graph_lastypix = newypix;
2075 /* verify that the array is OK */
2076 if (!a || pd_class((t_pd *)a) != garray_class)
2077 return;
2078 if (!garray_getfloatarray(a, &nelem, &vec))
2079 return;
2080 if (oldx < 0) oldx = 0;
2081 if (oldx >= nelem)
2082 oldx = nelem - 1;
2083 if (newx < 0) newx = 0;
2084 if (newx >= nelem)
2085 newx = nelem - 1;
2086 if (oldx < newx - 1)
2087 {
2088 for (i = oldx + 1; i <= newx; i++)
2089 vec[i] = newy + (oldy - newy) *
2090 ((float)(newx - i))/(float)(newx - oldx);
2091 }
2092 else if (oldx > newx + 1)
2093 {
2094 for (i = oldx - 1; i >= newx; i--)
2095 vec[i] = newy + (oldy - newy) *
2096 ((float)(newx - i))/(float)(newx - oldx);
2097 }
2098 else vec[newx] = newy;
2099 garray_redraw(a);
2100}
2101
2102static int graph_click(t_gobj *z, struct _glist *glist,
2103 int xpix, int ypix, int shift, int alt, int dbl, int doit)
2104{
2105 t_glist *x = (t_glist *)z;
2106 t_gobj *y;
2107 int clickreturned = 0;
2108 if (!x->gl_isgraph)
2109 return (text_widgetbehavior.w_clickfn(z, glist,
2110 xpix, ypix, shift, alt, dbl, doit));
2111 else if (x->gl_havewindow)
2112 return (0);
2113 else
2114 {
2115 for (y = x->gl_list; y; y = y->g_next)
2116 {
2117 int x1, y1, x2, y2;
2118 /* check if the object wants to be clicked */
2119 if (canvas_hitbox(x, y, xpix, ypix, &x1, &y1, &x2, &y2)
2120 && (clickreturned = gobj_click(y, x, xpix, ypix,
2121 shift, alt, 0, doit)))
2122 break;
2123 }
2124 if (!doit)
2125 {
2126 if (y)
2127 canvas_setcursor(glist_getcanvas(x), clickreturned);
2128 else canvas_setcursor(glist_getcanvas(x), CURSOR_RUNMODE_NOTHING);
2129 }
2130 return (clickreturned);
2131 }
2132}
2133
2134void garray_properties(t_garray *x);
2135
2136t_widgetbehavior graph_widgetbehavior =
2137{
2138 graph_getrect,
2139 graph_displace,
2140 graph_select,
2141 graph_activate,
2142 graph_delete,
2143 graph_vis,
2144 graph_click,
2145};
2146
2147void graph_properties(t_gobj *z, t_glist *owner)
2148{
2149 t_glist *x = (t_glist *)z;
2150 {
2151 t_gobj *y;
2152 char graphbuf[200];
2153 sprintf(graphbuf, "pdtk_graph_dialog %%s %g %g %g %g %d %d\n",
2154 x->gl_x1, x->gl_y1, x->gl_x2, x->gl_y2,
2155 x->gl_pixwidth, x->gl_pixheight);
2156 gfxstub_new(&x->gl_pd, x, graphbuf);
2157
2158 for (y = x->gl_list; y; y = y->g_next)
2159 if (pd_class(&y->g_pd) == garray_class)
2160 garray_properties((t_garray *)y);
2161 }
2162}
2163
2164 /* find the graph most recently added to this glist;
2165 if none exists, return 0. */
2166
2167t_glist *glist_findgraph(t_glist *x)
2168{
2169 t_gobj *y = 0, *z;
2170 for (z = x->gl_list; z; z = z->g_next)
2171 if (pd_class(&z->g_pd) == canvas_class && ((t_glist *)z)->gl_isgraph)
2172 y = z;
2173 return ((t_glist *)y);
2174}
2175
2176 /* message back from dialog GUI to set parameters. Args are:
2177 1-4: bounds in our coordinates; 5-6: size in parent */
2178static void graph_dialog(t_glist *x, t_symbol *s, int argc, t_atom *argv)
2179{
2180 t_float x1 = atom_getfloatarg(0, argc, argv);
2181 t_float y1 = atom_getfloatarg(1, argc, argv);
2182 t_float x2 = atom_getfloatarg(2, argc, argv);
2183 t_float y2 = atom_getfloatarg(3, argc, argv);
2184 t_float xpix = atom_getfloatarg(4, argc, argv);
2185 t_float ypix = atom_getfloatarg(5, argc, argv);
2186 if (x1 != x->gl_x1 || x2 != x->gl_x2 ||
2187 y1 != x->gl_y1 || y2 != x->gl_y2)
2188 graph_bounds(x, x1, y1, x2, y2);
2189 if (xpix != x->gl_pixwidth || ypix != x->gl_pixheight)
2190 {
2191 x->gl_pixwidth = xpix;
2192 x->gl_pixheight = ypix;
2193 glist_redraw(x);
2194 if (x->gl_owner)
2195 canvas_fixlinesfor(x->gl_owner, &x->gl_obj);
2196 }
2197}
2198
2199extern void canvas_menuarray(t_glist *canvas);
2200
2201void g_graph_setup(void)
2202{
2203 class_setwidget(canvas_class, &graph_widgetbehavior);
2204 class_addmethod(canvas_class, (t_method)graph_bounds, gensym("bounds"),
2205 A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0);
2206 class_addmethod(canvas_class, (t_method)graph_xticks, gensym("xticks"),
2207 A_FLOAT, A_FLOAT, A_FLOAT, 0);
2208 class_addmethod(canvas_class, (t_method)graph_xlabel, gensym("xlabel"),
2209 A_GIMME, 0);
2210 class_addmethod(canvas_class, (t_method)graph_yticks, gensym("yticks"),
2211 A_FLOAT, A_FLOAT, A_FLOAT, 0);
2212 class_addmethod(canvas_class, (t_method)graph_ylabel, gensym("ylabel"),
2213 A_GIMME, 0);
2214 class_addmethod(canvas_class, (t_method)graph_array, gensym("array"),
2215 A_SYMBOL, A_FLOAT, A_SYMBOL, A_DEFFLOAT, A_NULL);
2216 class_addmethod(canvas_class, (t_method)canvas_menuarray,
2217 gensym("menuarray"), A_NULL);
2218 class_addmethod(canvas_class, (t_method)graph_dialog, gensym("dialog"),
2219 A_GIMME, 0);
2220 class_addmethod(canvas_class, (t_method)glist_arraydialog,
2221 gensym("arraydialog"), A_SYMBOL, A_FLOAT, A_FLOAT, A_FLOAT, A_NULL);
2222 class_addmethod(canvas_class, (t_method)glist_sort,
2223 gensym("sort"), A_NULL);
2224}