1 /* $Id$ $Revision$ */
2 /* vim:set shiftwidth=4 ts=8: */
3
4 /*************************************************************************
5 * Copyright (c) 2011 AT&T Intellectual Property
6 * All rights reserved. This program and the accompanying materials
7 * are made available under the terms of the Eclipse Public License v1.0
8 * which accompanies this distribution, and is available at
9 * http://www.eclipse.org/legal/epl-v10.html
10 *
11 * Contributors: See CVS logs. Details at http://www.graphviz.org/
12 *************************************************************************/
13
14 /* Lefteris Koutsofios - AT&T Labs Research */
15
16 #include "common.h"
17 #include "g.h"
18 #include "mem.h"
19 #include "leftyio.h"
20 #include "code.h"
21 #include "tbl.h"
22 #include "parse.h"
23 #include "exec.h"
24 #include "gfxview.h"
25
26 #define max(a, b) (((a) >= (b)) ? (a) : (b))
27 #define min(a, b) (((a) >= (b)) ? (b) : (a))
28
29 #define getwintnset(to) \
30 if (getint (to, &wattrp[wattri].u.i) != -1) wattri++;
31 #define getwpointnset(to) \
32 if (getxy (to, &wattrp[wattri].u.p) != -1) wattri++;
33 #define getwsizenset(to) \
34 if (getxy (to, &wattrp[wattri].u.s) != -1) wattri++;
35 #define getwrectnset(to) \
36 if (getrect (to, &wattrp[wattri].u.r) != -1) wattri++;
37 #define getwstrnset(to) \
38 if (getstr (to, &wattrp[wattri].u.t) != -1) wattri++;
39 #define getwcolornset(ko, vo) \
40 if (getcolor (ko, vo, &wattrp[wattri].u.c) != -1) wattri++;
41
42 #define getaintnset(to, n, flag) \
43 if (to) { \
44 getint (to, &n), dp->flags |= flag; \
45 }
46 #define getastrnset(to, s, flag) \
47 if (to) \
48 getstr (to, &s), dp->flags |= flag;
49
50 typedef struct colorname_t {
51 char *name;
52 unsigned char r, g, b;
53 } colorname_t;
54
55 #include "colors.txt"
56
57 typedef struct gfxrect_t {
58 struct gfxrect_t *next;
59 Tobj ko;
60 Grect_t r;
61 } gfxrect_t;
62 typedef struct gfxmenu_t {
63 struct gfxmenu_t *next;
64 Tobj ko;
65 long time;
66 int mi;
67 } gfxmenu_t;
68 #define LISTSIZE 100
69 typedef struct gfxnode_t {
70 int inuse;
71 int wi;
72 Tobj plvo, pmvo, prvo, pb3vo, pb4vo, pkvo[256];
73 Gpoint_t plp, pmp, prp, pb3p, pb4p, pkp[256];
74 char ls, ms, rs, b3s, b4s, ks[256];
75 struct gfxrect_t *rect[LISTSIZE];
76 struct gfxmenu_t *menu[LISTSIZE];
77 } gfxnode_t;
78 #define GFXNODEINCR 20
79 #define GFXNODESIZE sizeof (gfxnode_t)
80 static gfxnode_t *gfxnodes;
81 static int gfxnoden;
82
83 #define ISAWIDGET(wi) (wi >= 0 && wi < Gwidgetn && Gwidgets[wi].inuse)
84 #define ISALABEL(wi) (Gwidgets[wi].type == G_LABELWIDGET)
85 #define ISACANVAS(wi) (Gwidgets[wi].type == G_CANVASWIDGET)
86 #define ISACANVAS2(wi) ( \
87 Gwidgets[wi].type == G_CANVASWIDGET || \
88 Gwidgets[wi].type == G_PCANVASWIDGET \
89 )
90 #define NODEID(wi) Gwidgets[wi].udata
91 #define ISABITMAP(bi) (bi >= 0 && bi < Gbitmapn && Gbitmaps[bi].inuse)
92
93 static Gpoint_t *gpp = NULL;
94 static long gpn = 0;
95 #define GPINCR 100
96 #define GPSIZE sizeof (Gpoint_t)
97
98 static Gwattr_t *wattrp = NULL;
99 static int wattrn = 0;
100 static int wattri = 0;
101 #define WATTRINCR 10
102 #define WATTRSIZE sizeof (Gwattr_t)
103
104 static Tobj rootwo, rootbo;
105
106 static void nodeinit (int);
107 static void nodeterm (int);
108 static void rectinit (int);
109 static void rectterm (int);
110 static void rectinsert (int, Tobj, Grect_t);
111 static void rectmerge (int, Tobj, Grect_t);
112 static Tobj rectfind (int, Gpoint_t);
113 static void rectdelete (int, Tobj);
114 static void rectprune (int);
115 static void menuinsert (int, Tobj, long, int);
116 static int menufind (int, Tobj, long);
117 static void menuprune (int);
118 static int scanhsv (char *, float *, float *, float *);
119 static void hsv2rgb (float, float, float, Gcolor_t *);
120
121 static int getwattr (Tobj, int *);
122 static int getgattr (Tobj, Ggattr_t *);
123 static int getrect (Tobj, Grect_t *);
124 static int getxy (Tobj, Gxy_t *);
125 static int getint (Tobj, int *);
126 static int getdouble (Tobj, double *);
127 static int getstr (Tobj, char **);
128 static int getcolor (Tobj, Tobj, Gcolor_t *);
129
GFXinit(void)130 void GFXinit (void) {
131 int ni;
132
133 Tinss (root, "widgets", (rootwo = Ttable (100)));
134 Tinss (root, "bitmaps", (rootbo = Ttable (100)));
135 gfxnodes = Marrayalloc ((long) GFXNODEINCR * GFXNODESIZE);
136 gfxnoden = GFXNODEINCR;
137 for (ni = 0; ni < gfxnoden; ni++)
138 gfxnodes[ni].inuse = FALSE;
139 ni = 0;
140 gpp = Marrayalloc ((long) GPINCR * GPSIZE);
141 gpn = GPINCR;
142 wattrp = Marrayalloc ((long) WATTRINCR * WATTRSIZE);
143 wattrn = WATTRINCR, wattri = 0;
144 }
145
GFXterm(void)146 void GFXterm (void) {
147 int ni;
148
149 Marrayfree (wattrp), wattrp = NULL, wattrn = 0;
150 Marrayfree (gpp), gpp = NULL, gpn = 0;
151 for (ni = 0; ni < gfxnoden; ni++) {
152 if (gfxnodes[ni].inuse) {
153 Gdestroywidget (gfxnodes[ni].wi);
154 nodeterm (ni);
155 gfxnodes[ni].inuse = FALSE;
156 }
157 }
158 Marrayfree (gfxnodes), gfxnodes = NULL, gfxnoden = 0;
159 Tdels (root, "bitmaps");
160 Tdels (root, "widgets");
161 }
162
163 /* callback for mem.c module - removes dead objects from gfxnodes */
GFXprune(void)164 void GFXprune (void) {
165 gfxnode_t *np;
166 int ni, ki;
167
168 for (ni = 0; ni < gfxnoden; ni++) {
169 np = &gfxnodes[ni];
170 if (np->inuse) {
171 rectprune (ni), menuprune (ni);
172 if (np->plvo && !M_AREAOF (np->plvo))
173 np->plvo = 0;
174 if (np->pmvo && !M_AREAOF (np->pmvo))
175 np->pmvo = 0;
176 if (np->prvo && !M_AREAOF (np->prvo))
177 np->prvo = 0;
178 if (np->pb3vo && !M_AREAOF (np->pb3vo))
179 np->pb3vo = 0;
180 if (np->pb4vo && !M_AREAOF (np->pb4vo))
181 np->pb4vo = 0;
182 for (ki = 0; ki < 256; ki++)
183 if (np->pkvo[ki] && !M_AREAOF (np->pkvo[ki]))
184 np->pkvo[ki] = 0;
185 }
186 }
187 }
188
189 /* callback for g.c module - calls the appropriate lefty function */
GFXlabelcb(Gevent_t * evp)190 void GFXlabelcb (Gevent_t *evp) {
191 Tobj fo, to, co, wo;
192 char *fn;
193 char s[2];
194 long fm;
195
196 fn = NULL;
197 wo = Tfindi (rootwo, evp->wi);
198 switch (evp->type) {
199 case G_MOUSE:
200 switch (evp->data) {
201 case G_LEFT:
202 fn = (evp->code == G_UP) ? "leftup" : "leftdown";
203 break;
204 case G_MIDDLE:
205 fn = (evp->code == G_UP) ? "middleup" : "middledown";
206 break;
207 case G_RIGHT:
208 fn = (evp->code == G_UP) ? "rightup" : "rightdown";
209 break;
210 }
211 break;
212 case G_KEYBD:
213 fn = (evp->code == G_UP) ? "keyup" : "keydown";
214 break;
215 }
216 if (!wo || !(fo = Tfinds (wo, fn)) || Tgettype (fo) != T_CODE)
217 if (!(fo = Tfinds (root, fn)) || Tgettype (fo) != T_CODE)
218 return;
219 fm = Mpushmark (fo);
220 to = Ttable (4);
221 Mpushmark (to);
222 Tinss (to, "widget", Tinteger (evp->wi));
223 if (evp->type == G_KEYBD)
224 s[0] = evp->data, s[1] = '\000', Tinss (to, "key", Tstring (s));
225 if ((co = Pfcall (fo, to)))
226 Eunit (co);
227 Mpopmark (fm);
228 }
229
230 /* callback for g.c module - calls the appropriate lefty function */
GFXviewcb(Gevent_t * evp)231 void GFXviewcb (Gevent_t *evp) {
232 Tobj fo, to, co, wo;
233 char *fn;
234 long fm;
235
236 wo = Tfindi (rootwo, evp->wi);
237 fn = "closeview";
238 if (!wo || !(fo = Tfinds (wo, fn)) || Tgettype (fo) != T_CODE)
239 if (!(fo = Tfinds (root, fn)) || Tgettype (fo) != T_CODE)
240 exit (0);
241 fm = Mpushmark (fo);
242 to = Ttable (2);
243 Mpushmark (to);
244 Tinss (to, "widget", Tinteger (evp->wi));
245 if ((co = Pfcall (fo, to)))
246 Eunit (co);
247 Mpopmark (fm);
248 }
249
250 /* callback for g.c module - calls the appropriate lefty function */
GFXevent(Gevent_t * evp)251 void GFXevent (Gevent_t *evp) {
252 Tobj vo, pvo, fo, to, po, co, wo;
253 gfxnode_t *np;
254 Gpoint_t pp;
255 char *fn;
256 char s[2];
257 long fm;
258 int ni;
259
260 pp.x = pp.y = 0;
261 pvo = NULL;
262 fn = NULL;
263 ni = Gwidgets[evp->wi].udata;
264 np = &gfxnodes[ni];
265 wo = Tfindi (rootwo, evp->wi);
266 if (!(vo = rectfind (ni, evp->p)))
267 vo = null;
268 switch (evp->type) {
269 case G_MOUSE:
270 switch (evp->data) {
271 case G_LEFT:
272 if (evp->code == G_UP)
273 fn = "leftup", pvo = np->plvo, pp = np->plp, np->ls = 0;
274 else
275 fn = "leftdown", np->plvo = vo, np->plp = evp->p, np->ls = 1;
276 break;
277 case G_MIDDLE:
278 if (evp->code == G_UP)
279 fn = "middleup", pvo = np->pmvo, pp = np->pmp, np->ms = 0;
280 else
281 fn = "middledown", np->pmvo = vo, np->pmp = evp->p, np->ms = 1;
282 break;
283 case G_RIGHT:
284 if (evp->code == G_UP)
285 fn = "rightup", pvo = np->prvo, pp = np->prp, np->rs = 0;
286 else
287 fn = "rightdown", np->prvo = vo, np->prp = evp->p, np->rs = 1;
288 break;
289 case G_BUTTON3:
290 if (evp->code == G_UP) {
291 fn = "button3up";
292 pvo = np->pb3vo, pp = np->pb3p, np->b3s = 0;
293 } else {
294 fn = "button4down";
295 np->pb3vo = vo, np->pb3p = evp->p, np->b3s = 1;
296 }
297 break;
298 case G_BUTTON4:
299 if (evp->code == G_UP) {
300 fn = "button4up";
301 pvo = np->pb4vo, pp = np->pb4p, np->b4s = 0;
302 } else {
303 fn = "button4down";
304 np->pb4vo = vo, np->pb4p = evp->p, np->b4s = 1;
305 }
306 break;
307 }
308 break;
309 case G_KEYBD:
310 if (evp->code == G_UP) {
311 fn = "keyup";
312 pvo = np->pkvo[evp->data];
313 pp = np->pkp[evp->data];
314 np->ks[evp->data] = 0;
315 } else {
316 fn = "keydown";
317 np->pkvo[evp->data] = vo;
318 np->pkp[evp->data] = evp->p;
319 np->ks[evp->data] = 1;
320 }
321 break;
322 }
323 if (!wo || !(fo = Tfinds (wo, fn)) || Tgettype (fo) != T_CODE)
324 if (!(fo = Tfinds (root, fn)) || Tgettype (fo) != T_CODE)
325 return;
326
327 fm = Mpushmark (fo);
328 to = Ttable (4);
329 Mpushmark (to);
330 Tinss (to, "widget", Tinteger (evp->wi));
331 Tinss (to, "obj", vo);
332 Tinss (to, "pos", (po = Ttable (2)));
333 Tinss (po, "x", Treal (evp->p.x));
334 Tinss (po, "y", Treal (evp->p.y));
335 if (evp->code == G_UP) {
336 Tinss (to, "pobj", pvo);
337 Tinss (to, "ppos", (po = Ttable (2)));
338 Tinss (po, "x", Treal (pp.x));
339 Tinss (po, "y", Treal (pp.y));
340 }
341 if (evp->type == G_KEYBD)
342 s[0] = evp->data, s[1] = '\000', Tinss (to, "key", Tstring (s));
343 if ((co = Pfcall (fo, to)))
344 Eunit (co);
345 Mpopmark (fm);
346 }
347
348 /* called directly from lefty.c, when any button is held down */
GFXmove(void)349 void GFXmove (void) {
350 gfxnode_t *np;
351 char *fn[5];
352 Tobj vo[5], fo, to, po, co, wo;
353 Gpoint_t cp, pp[5];
354 long fm;
355 int count, i, ni;
356
357 for (ni = 0; ni < gfxnoden; ni++) {
358 np = &gfxnodes[ni];
359 if (
360 !np->inuse || !ISACANVAS (np->wi) ||
361 !Gwidgets[np->wi].u.c->buttonsdown
362 )
363 continue;
364 wo = Tfindi (rootwo, np->wi);
365 Ggetmousecoords (np->wi, &cp, &count);
366 if (!count) {
367 Gresetbstate (np->wi);
368 continue;
369 }
370 if (np->ls)
371 fn[0] = "leftmove", pp[0] = np->plp, vo[0] = np->plvo;
372 else
373 fn[0] = NULL;
374 if (np->ms)
375 fn[1] = "middlemove", pp[1] = np->pmp, vo[1] = np->pmvo;
376 else
377 fn[1] = NULL;
378 if (np->rs)
379 fn[2] = "rightmove", pp[2] = np->prp, vo[2] = np->prvo;
380 else
381 fn[2] = NULL;
382 if (np->b3s)
383 fn[3] = "button3move", pp[3] = np->pb3p, vo[3] = np->pb3vo;
384 else
385 fn[3] = NULL;
386 if (np->b4s)
387 fn[4] = "button4move", pp[4] = np->pb4p, vo[4] = np->pb4vo;
388 else
389 fn[4] = NULL;
390 for (i = 0; i < 5; i++) {
391 if (!fn[i])
392 continue;
393 if (!wo || !(fo = Tfinds (wo, fn[i])) || Tgettype (fo) != T_CODE)
394 fo = Tfinds (root, fn[i]);
395 if (fo && Tgettype (fo) == T_CODE) {
396 fm = Mpushmark (fo);
397 to = Ttable (4);
398 Mpushmark (to);
399 Tinss (to, "widget", Tinteger (np->wi));
400 Tinss (to, "obj", vo[i]);
401 Tinss (to, "pos", (po = Ttable (2)));
402 Tinss (po, "x", Treal (cp.x));
403 Tinss (po, "y", Treal (cp.y));
404 Tinss (to, "ppos", (po = Ttable (2)));
405 Tinss (po, "x", Treal (pp[i].x));
406 Tinss (po, "y", Treal (pp[i].y));
407 if ((co = Pfcall (fo, to)))
408 Eunit (co);
409 Mpopmark (fm);
410 }
411 }
412 }
413 }
414
415 /* called directly from lefty.c, when any canvas needs to be redrawn */
GFXredraw(void)416 void GFXredraw (void) {
417 gfxnode_t *np;
418 Tobj wo, fo, co, to;
419 long fm;
420 int ni;
421
422 for (ni = 0; ni < gfxnoden; ni++) {
423 np = &gfxnodes[ni];
424 if (
425 !np->inuse || !ISACANVAS (np->wi) ||
426 !Gwidgets[np->wi].u.c->needredraw
427 )
428 continue;
429 Gwidgets[np->wi].u.c->needredraw = FALSE;
430 wo = Tfindi (rootwo, np->wi);
431 if (!wo || !(fo = Tfinds (wo, "redraw")) || Tgettype (fo) != T_CODE)
432 if (!(fo = Tfinds (root, "redraw")) || Tgettype (fo) != T_CODE)
433 return;
434
435 fm = Mpushmark (fo);
436 to = Ttable (4);
437 Mpushmark (to);
438 Tinss (to, "widget", Tinteger (np->wi));
439 if ((co = Pfcall (fo, to)))
440 Eunit (co);
441 Mpopmark (fm);
442 }
443 }
444
GFXtextcb(int wi,char * s)445 void GFXtextcb (int wi, char *s) {
446 Tobj wo, fo, co, to;
447 long fm;
448
449 if (!(wo = Tfindi (rootwo, wi)))
450 return;
451
452 if (!(fo = Tfinds (wo, "oneline")) || Tgettype (fo) != T_CODE)
453 return;
454
455 fm = Mpushmark (fo);
456 to = Ttable (4);
457 Mpushmark (to);
458 Tinss (to, "widget", Tinteger (wi));
459 Tinss (to, "text", Tstring (s));
460 if ((co = Pfcall (fo, to)))
461 Eunit (co);
462 Mpopmark (fm);
463 }
464
GFXbuttoncb(int wi,void * data)465 void GFXbuttoncb (int wi, void *data) {
466 Tobj wo, fo, co, to;
467 long fm;
468
469 if (!(wo = Tfindi (rootwo, wi)))
470 return;
471
472 if (!(fo = Tfinds (wo, "pressed")) || Tgettype (fo) != T_CODE)
473 return;
474
475 fm = Mpushmark (fo);
476 to = Ttable (4);
477 Mpushmark (to);
478 Tinss (to, "widget", Tinteger (wi));
479 if ((co = Pfcall (fo, to)))
480 Eunit (co);
481 Mpopmark (fm);
482 }
483
GFXarrayresizecb(int wi,Gawdata_t * dp)484 void GFXarrayresizecb (int wi, Gawdata_t *dp) {
485 Tobj wo, fo, co, so, to, lrtno, sxo, syo;
486 Tkvindex_t tkvi;
487 Gawcarray_t *cp;
488 int sx, sy, csx, csy, ci;
489 long fm;
490
491 if (!(wo = Tfindi (rootwo, wi)))
492 return;
493
494 if (!(fo = Tfinds (wo, "resize")) || Tgettype (fo) != T_CODE) {
495 Gawdefcoordscb (wi, dp);
496 return;
497 }
498
499 fm = Mpushmark (fo);
500 to = Ttable (4);
501 Mpushmark (to);
502 Tinss (to, "widget", Tinteger (wi));
503 Tinss (to, "size", (so = Ttable (2)));
504 Tinss (so, "x", Treal ((double) dp->sx));
505 Tinss (so, "y", Treal ((double) dp->sy));
506
507 lrtno = NULL;
508 if ((co = Pfcall (fo, to)))
509 lrtno = Eunit (co);
510 Mpopmark (fm);
511 if (!lrtno) {
512 Gawdefcoordscb (wi, dp);
513 return;
514 }
515 for (Tgetfirst (lrtno, &tkvi); tkvi.kvp; Tgetnext (&tkvi)) {
516 if (!T_ISNUMBER (tkvi.kvp->ko) || !T_ISTABLE ((so = tkvi.kvp->vo)))
517 continue;
518 wi = Tgetnumber (tkvi.kvp->ko);
519 if (!ISAWIDGET (wi))
520 continue;
521 for (ci = 0; ci < dp->cj; ci++) {
522 cp = &dp->carray[ci];
523 if (!cp->flag || cp->w != Gwidgets[wi].w)
524 continue;
525 if ((sxo = Tfinds (so, "x")) && T_ISNUMBER (sxo))
526 cp->sx = Tgetnumber (sxo);
527 if ((syo = Tfinds (so, "y")) && T_ISNUMBER (syo))
528 cp->sy = Tgetnumber (syo);
529 break;
530 }
531 }
532 sx = dp->sx, sy = dp->sy;
533 csx = csy = 0;
534 for (ci = 0; ci < dp->cj; ci++) {
535 cp = &dp->carray[ci];
536 if (!cp->flag)
537 continue;
538 cp->ox = csx, cp->oy = csy;
539 if (dp->type == G_AWVARRAY)
540 cp->sx = sx - 2 * cp->bs, csy += cp->sy + 2 * cp->bs;
541 else
542 cp->sy = sy - 2 * cp->bs, csx += cp->sx + 2 * cp->bs;
543 }
544 if (dp->type == G_AWVARRAY)
545 dp->sy = csy;
546 else
547 dp->sx = csx;
548 }
549
550 /* callback for when there is input on some file descriptor */
GFXmonitorfile(int fd)551 void GFXmonitorfile (int fd) {
552 Tobj fo, to, co;
553 long fm, tm;
554
555 if (!(fo = Tfinds (root, "monitorfile")) || Tgettype (fo) != T_CODE)
556 return;
557
558 fm = Mpushmark (fo);
559 to = Ttable (4);
560 tm = Mpushmark (to);
561 Tinss (to, "fd", Tinteger (fd));
562 if ((co = Pfcall (fo, to)))
563 Eunit (co);
564 Mpopmark (tm);
565 Mpopmark (fm);
566 }
567
568 /* callback for when there is no X event and no file input */
GFXidle(void)569 void GFXidle (void) {
570 Tobj fo, to, co;
571 long fm, tm;
572
573 if (!(fo = Tfinds (root, "idle")) || Tgettype (fo) != T_CODE)
574 return;
575
576 fm = Mpushmark (fo);
577 to = Ttable (4);
578 tm = Mpushmark (to);
579 if ((co = Pfcall (fo, to)))
580 Eunit (co);
581 Mpopmark (tm);
582 Mpopmark (fm);
583 }
584
585 /* LEFTY builtin */
GFXcreatewidget(int argc,lvar_t * argv)586 int GFXcreatewidget (int argc, lvar_t *argv) {
587 Tobj pwo, cwo, cho;
588 long rtnm;
589 int type, pwi, wi, ni;
590
591 type = -1;
592 if (getint (argv[0].o, &pwi) == -1 || getwattr (argv[1].o, &type) == -1)
593 return L_FAILURE;
594 if (type != G_VIEWWIDGET && type != G_PCANVASWIDGET && !ISAWIDGET (pwi))
595 return L_FAILURE;
596 if (type == G_CANVASWIDGET || type == G_LABELWIDGET) {
597 for (ni = 0; ni < gfxnoden; ni++)
598 if (!gfxnodes[ni].inuse)
599 break;
600 if (ni == gfxnoden) {
601 gfxnodes = Marraygrow (
602 gfxnodes, (long) (ni + GFXNODEINCR) * GFXNODESIZE
603 );
604 for (ni = gfxnoden; ni < gfxnoden + GFXNODEINCR; ni++)
605 gfxnodes[ni].inuse = FALSE;
606 ni = gfxnoden, gfxnoden += GFXNODEINCR;
607 }
608 nodeinit (ni);
609 if (wattri >= wattrn) {
610 wattrp = Marraygrow (
611 wattrp, (long) (wattrn + WATTRINCR) * WATTRSIZE
612 );
613 wattrn += WATTRINCR;
614 }
615 switch (type) {
616 case G_CANVASWIDGET:
617 wattrp[wattri].id = G_ATTRUSERDATA;
618 wattrp[wattri].u.u = ni, wattri++;
619 break;
620 case G_LABELWIDGET:
621 wattrp[wattri].id = G_ATTRUSERDATA;
622 wattrp[wattri].u.u = ni, wattri++;
623 break;
624 }
625 wi = gfxnodes[ni].wi = Gcreatewidget (pwi, type, wattri, wattrp);
626 gfxnodes[ni].inuse = TRUE;
627 goto done;
628 }
629 wi = Gcreatewidget (pwi, type, wattri, wattrp);
630
631 done:
632 Tinsi (rootwo, wi, (cwo = Ttable (4)));
633 rtno = Tinteger (wi);
634 rtnm = Mpushmark (rtno);
635 if (pwi != -1) {
636 Tinss (cwo, "parent", Tinteger (pwi));
637 if ((pwo = Tfindi (rootwo, pwi))) {
638 if (!(cho = Tfinds (pwo, "children")))
639 Tinss (pwo, "children", (cho = Ttable (2)));
640 Tinsi (cho, wi, Tinteger (pwi));
641 }
642 }
643 Mpopmark (rtnm);
644 return L_SUCCESS;
645 }
646
647 /* LEFTY builtin */
GFXsetwidgetattr(int argc,lvar_t * argv)648 int GFXsetwidgetattr (int argc, lvar_t *argv) {
649 int wi, type, rtn;
650
651 if (getint (argv[0].o, &wi) == -1 || !ISAWIDGET (wi))
652 return L_FAILURE;
653 type = Gwidgets[wi].type;
654 if ((rtn = getwattr (argv[1].o, &type)) == -1)
655 return L_FAILURE;
656 Gsetwidgetattr (wi, wattri, wattrp);
657 rtno = Tinteger (rtn);
658 return L_SUCCESS;
659 }
660
661 /* LEFTY builtin */
GFXgetwidgetattr(int argc,lvar_t * argv)662 int GFXgetwidgetattr (int argc, lvar_t *argv) {
663 Tkvindex_t tkvi;
664 Tobj po, so, ro, co, co2;
665 Gwattrmap_t *mapp;
666 int *ap;
667 int li, ai, type, color, wattri2, wi;
668 long rtnm;
669
670 wattri = 0;
671 if (
672 getint (argv[0].o, &wi) == -1 || !ISAWIDGET (wi) ||
673 !T_ISTABLE (argv[1].o)
674 )
675 return L_FAILURE;
676 type = Gwidgets[wi].type;
677 for (ap = NULL, li = 0; Gwlist[li].wname; li++) {
678 if (type == Gwlist[li].wid) {
679 ap = Gwlist[li].attrid;
680 break;
681 }
682 }
683 if (!ap)
684 return L_FAILURE;
685 for (Tgetfirst (argv[1].o, &tkvi); tkvi.kvp; Tgetnext (&tkvi)) {
686 if (!T_ISSTRING (tkvi.kvp->vo))
687 continue;
688 for (ai = 0; ap[ai] != -1; ai++) {
689 if (
690 strcmp (Gwattrmap[ap[ai]].name,
691 Tgetstring (tkvi.kvp->vo)) == 0
692 ) {
693 if (wattri >= wattrn) {
694 wattrp = Marraygrow (
695 wattrp, (long) (wattrn + WATTRINCR) * WATTRSIZE
696 );
697 wattrn += WATTRINCR;
698 }
699 if (ap[ai] == G_ATTRCOLOR) {
700 for (color = 0; color < G_MAXCOLORS; color++) {
701 if (wattri >= wattrn) {
702 wattrp = Marraygrow (
703 wattrp, (long) (wattrn + WATTRINCR) * WATTRSIZE
704 );
705 wattrn += WATTRINCR;
706 }
707 wattrp[wattri].u.c.index = color;
708 wattrp[wattri++].id = ap[ai];
709 }
710 } else
711 wattrp[wattri++].id = ap[ai];
712 break;
713 }
714 }
715 }
716 if (Ggetwidgetattr (wi, wattri, wattrp) == -1)
717 return L_FAILURE;
718 rtno = Ttable (wattri);
719 rtnm = Mpushmark (rtno);
720 for (wattri2 = 0; wattri2 < wattri; wattri2++) {
721 mapp = &Gwattrmap[wattrp[wattri2].id];
722 switch (mapp->type) {
723 case G_ATTRTYPEPOINT:
724 Tinss (rtno, mapp->name, (po = Ttable (2)));
725 Tinss (po, "x", Treal (wattrp[wattri2].u.p.x));
726 Tinss (po, "y", Treal (wattrp[wattri2].u.p.y));
727 break;
728 case G_ATTRTYPESIZE:
729 Tinss (rtno, mapp->name, (so = Ttable (2)));
730 Tinss (so, "x", Treal (wattrp[wattri2].u.s.x));
731 Tinss (so, "y", Treal (wattrp[wattri2].u.s.y));
732 break;
733 case G_ATTRTYPERECT:
734 Tinss (rtno, mapp->name, (ro = Ttable (2)));
735 Tinsi (ro, 0, (po = Ttable (2)));
736 Tinss (po, "x", Treal (wattrp[wattri2].u.r.o.x));
737 Tinss (po, "y", Treal (wattrp[wattri2].u.r.o.y));
738 Tinsi (ro, 1, (po = Ttable (2)));
739 Tinss (po, "x", Treal (wattrp[wattri2].u.r.c.x));
740 Tinss (po, "y", Treal (wattrp[wattri2].u.r.c.y));
741 break;
742 case G_ATTRTYPETEXT:
743 Tinss (rtno, mapp->name, Tstring (wattrp[wattri2].u.t));
744 break;
745 case G_ATTRTYPEINT:
746 Tinss (rtno, mapp->name, Tinteger (wattrp[wattri2].u.i));
747 break;
748 case G_ATTRTYPECOLOR:
749 Tinss (rtno, mapp->name, (co = Ttable (G_MAXCOLORS)));
750 for (color = 0; color < G_MAXCOLORS; color++) {
751 Tinsi (co, color, (co2 = Ttable (3)));
752 Tinss (co2, "r", Treal (wattrp[wattri2 + color].u.c.r));
753 Tinss (co2, "g", Treal (wattrp[wattri2 + color].u.c.g));
754 Tinss (co2, "b", Treal (wattrp[wattri2 + color].u.c.g));
755 }
756 wattri2 += (G_MAXCOLORS - 1);
757 break;
758 }
759 }
760 Mpopmark (rtnm);
761 return L_SUCCESS;
762 }
763
764 /* LEFTY builtin */
GFXdestroywidget(int argc,lvar_t * argv)765 int GFXdestroywidget (int argc, lvar_t *argv) {
766 Tkvindex_t tkvi;
767 Tobj wo, cho, pwio, pwo;
768 lvar_t argv2[1];
769 int wi;
770
771 if (getint (argv[0].o, &wi) == -1 || !ISAWIDGET (wi))
772 return L_FAILURE;
773
774 wo = Tfindi (rootwo, wi);
775 if ((cho = Tfinds (wo, "children"))) {
776 while (Tgettablen (cho) > 0) {
777 Tgetfirst (cho, &tkvi);
778 argv2[0].o = tkvi.kvp->ko;
779 GFXdestroywidget (1, argv2);
780 }
781 }
782 if ((pwio = Tfinds (wo, "parent"))) {
783 pwo = Tfindi (rootwo, Tgetinteger (pwio));
784 cho = Tfinds (pwo, "children");
785 Tdeli (cho, wi);
786 }
787 if (ISACANVAS (wi) || ISALABEL (wi)) {
788 nodeterm (NODEID (wi));
789 gfxnodes[NODEID (wi)].inuse = FALSE;
790 }
791 Gdestroywidget (wi);
792 Tdeli (rootwo, wi);
793 return L_SUCCESS;
794 }
795
796 /* LEFTY builtin */
GFXclear(int argc,lvar_t * argv)797 int GFXclear (int argc, lvar_t *argv) {
798 int wi;
799
800 if (getint (argv[0].o, &wi) == -1 || !ISAWIDGET (wi))
801 return L_FAILURE;
802 Gcanvasclear (wi);
803 if (ISACANVAS (wi))
804 rectterm (NODEID (wi)), rectinit (NODEID (wi));
805 return L_SUCCESS;
806 }
807
808 /* LEFTY builtin */
GFXsetgfxattr(int argc,lvar_t * argv)809 int GFXsetgfxattr (int argc, lvar_t *argv) {
810 Ggattr_t gattr;
811 int wi;
812
813 if (
814 getint (argv[0].o, &wi) == -1 || !ISAWIDGET (wi) ||
815 getgattr (argv[1].o, &gattr) == -1
816 )
817 return L_FAILURE;
818 Gsetgfxattr (wi, &gattr);
819 return L_SUCCESS;
820 }
821
822 /* LEFTY builtin */
GFXgetgfxattr(int argc,lvar_t * argv)823 int GFXgetgfxattr (int argc, lvar_t *argv) {
824 Tkvindex_t tkvi;
825 Ggattr_t gattr;
826 long rtnm;
827 int wi;
828 char *s;
829
830 gattr.flags = 0;
831 if (
832 getint (argv[0].o, &wi) == -1 || !ISAWIDGET (wi) ||
833 !T_ISTABLE (argv[1].o)
834 )
835 return L_FAILURE;
836
837 s = NULL;
838 for (Tgetfirst (argv[1].o, &tkvi); tkvi.kvp; Tgetnext (&tkvi)) {
839 if (!T_ISSTRING (tkvi.kvp->vo))
840 continue;
841 s = Tgetstring (tkvi.kvp->vo);
842 if (strcmp (s, "color") == 0)
843 gattr.flags |= G_GATTRCOLOR;
844 else if (strcmp (s, "width") == 0)
845 gattr.flags |= G_GATTRWIDTH;
846 else if (strcmp (s, "mode") == 0)
847 gattr.flags |= G_GATTRMODE;
848 else if (strcmp (s, "fill") == 0)
849 gattr.flags |= G_GATTRFILL;
850 else if (strcmp (s, "style") == 0)
851 gattr.flags |= G_GATTRSTYLE;
852 }
853 if (Ggetgfxattr (wi, &gattr) == -1)
854 return L_FAILURE;
855 rtno = Ttable (wattri);
856 rtnm = Mpushmark (rtno);
857 if (gattr.flags & G_GATTRCOLOR) {
858 Tinss (rtno, "color", Tinteger (gattr.color));
859 } else if (gattr.flags & G_GATTRWIDTH) {
860 Tinss (rtno, "width", Tinteger (gattr.width));
861 } else if (gattr.flags & G_GATTRMODE) {
862 s = (gattr.mode == G_SRC) ? "src" : "xor";
863 Tinss (rtno, "mode", Tstring (s));
864 } else if (gattr.flags & G_GATTRFILL) {
865 s = (gattr.fill) ? "on" : "off";
866 Tinss (rtno, "fill", Tstring (s));
867 } else if (gattr.flags & G_GATTRSTYLE) {
868 switch (gattr.style) {
869 case G_SOLID: s = "solid"; break;
870 case G_DASHED: s = "dashed"; break;
871 case G_DOTTED: s = "dotted"; break;
872 case G_LONGDASHED: s = "longdashed"; break;
873 case G_SHORTDASHED: s = "shortdashed"; break;
874 }
875 Tinss (rtno, "style", Tstring (s));
876 }
877 Mpopmark (rtnm);
878 return L_SUCCESS;
879 }
880
881 /* LEFTY builtin */
GFXarrow(int argc,lvar_t * argv)882 int GFXarrow (int argc, lvar_t *argv) {
883 Ggattr_t gattr;
884 Gpoint_t p0, p1;
885 int wi;
886
887 if (
888 getint (argv[0].o, &wi) == -1 || !ISAWIDGET (wi) || !ISACANVAS2 (wi) ||
889 getxy (argv[2].o, &p0) == -1 || getxy (argv[3].o, &p1) == -1 ||
890 getgattr ((argc == 5) ? argv[4].o : NULL, &gattr) == -1
891 )
892 return L_FAILURE;
893 Garrow (wi, p0, p1, &gattr);
894 return L_SUCCESS;
895 }
896
897 /* LEFTY builtin */
GFXline(int argc,lvar_t * argv)898 int GFXline (int argc, lvar_t *argv) {
899 Ggattr_t gattr;
900 Gpoint_t p0, p1;
901 int wi;
902
903 if (
904 getint (argv[0].o, &wi) == -1 || !ISAWIDGET (wi) || !ISACANVAS2 (wi) ||
905 getxy (argv[2].o, &p0) == -1 || getxy (argv[3].o, &p1) == -1 ||
906 getgattr ((argc == 5) ? argv[4].o : NULL, &gattr) == -1
907 )
908 return L_FAILURE;
909 Gline (wi, p0, p1, &gattr);
910 return L_SUCCESS;
911 }
912
913 /* LEFTY builtin */
GFXbox(int argc,lvar_t * argv)914 int GFXbox (int argc, lvar_t *argv) {
915 Ggattr_t gattr;
916 Grect_t r;
917 int wi, rtn;
918
919 if (
920 getint (argv[0].o, &wi) == -1 || !ISAWIDGET (wi) || !ISACANVAS2 (wi) ||
921 getrect (argv[2].o, &r) == -1 ||
922 getgattr ((argc == 4) ? argv[3].o : NULL, &gattr) == -1
923 )
924 return L_FAILURE;
925 rtn = Gbox (wi, r, &gattr);
926 if (rtn == 0 && argv[1].o != null && ISACANVAS (wi))
927 rectmerge (NODEID (wi), argv[1].o, r);
928 return L_SUCCESS;
929 }
930
931 /* LEFTY builtin */
GFXpolygon(int argc,lvar_t * argv)932 int GFXpolygon (int argc, lvar_t *argv) {
933 Tobj po;
934 Ggattr_t gattr;
935 long i, pn;
936 int wi;
937
938 if (
939 getint (argv[0].o, &wi) == -1 || !ISAWIDGET (wi) || !ISACANVAS2 (wi) ||
940 getgattr ((argc == 4) ? argv[3].o : NULL, &gattr) == -1
941 )
942 return L_FAILURE;
943 po = argv[2].o;
944 if ((pn = Tgettablen (po)) > gpn) {
945 gpp = Marraygrow (gpp, (long) pn * GPSIZE);
946 gpn = pn;
947 }
948 for (i = 0; i < pn; i++)
949 if (getxy (Tfindi (po, i), &gpp[i]) == -1)
950 return L_FAILURE;
951 Gpolygon (wi, pn, gpp, &gattr);
952 return L_SUCCESS;
953 }
954
955 /* LEFTY builtin */
GFXsplinegon(int argc,lvar_t * argv)956 int GFXsplinegon (int argc, lvar_t *argv) {
957 Tobj po;
958 Ggattr_t gattr;
959 long i, pn;
960 int wi;
961
962 if (
963 getint (argv[0].o, &wi) == -1 || !ISAWIDGET (wi) || !ISACANVAS2 (wi) ||
964 getgattr ((argc == 4) ? argv[3].o : NULL, &gattr) == -1
965 )
966 return L_FAILURE;
967 po = argv[2].o;
968 if ((pn = Tgettablen (po)) > gpn) {
969 gpp = Marraygrow (gpp, (long) pn * GPSIZE);
970 gpn = pn;
971 }
972 for (i = 0; i < pn; i++)
973 if (getxy (Tfindi (po, i), &gpp[i]) == -1)
974 return L_FAILURE;
975 Gsplinegon (wi, pn, gpp, &gattr);
976 return L_SUCCESS;
977 }
978
979 /* LEFTY builtin */
GFXarc(int argc,lvar_t * argv)980 int GFXarc (int argc, lvar_t *argv) {
981 Ggattr_t gattr;
982 Grect_t r;
983 Gpoint_t op;
984 Gsize_t sp;
985 int wi, rtn;
986
987 if (
988 getint (argv[0].o, &wi) == -1 || !ISAWIDGET (wi) || !ISACANVAS2 (wi) ||
989 getxy (argv[2].o, &op) == -1 || getxy (argv[3].o, &sp) == -1 ||
990 getgattr ((argc == 5) ? argv[4].o : NULL, &gattr) == -1
991 )
992 return L_FAILURE;
993 rtn = Garc (wi, op, sp, (double) 0, (double) 360, &gattr);
994 if (rtn == 0 && argv[1].o != null && ISACANVAS (wi)) {
995 r.o.x = op.x - sp.x, r.o.y = op.y - sp.y;
996 r.c.x = op.x + sp.x, r.c.y = op.y + sp.y;
997 rectmerge (NODEID (wi), argv[1].o, r);
998 }
999 return L_SUCCESS;
1000 }
1001
1002 /* LEFTY builtin */
GFXtext(int argc,lvar_t * argv)1003 int GFXtext (int argc, lvar_t *argv) {
1004 Ggattr_t gattr;
1005 Gpoint_t p;
1006 char *s, *fn, *justs;
1007 double fs;
1008 int wi;
1009
1010 if (
1011 getint (argv[0].o, &wi) == -1 || !ISAWIDGET (wi) || !ISACANVAS2 (wi) ||
1012 getxy (argv[2].o, &p) == -1 || getstr (argv[3].o, &s) == -1 ||
1013 getstr (argv[4].o, &fn) == -1 || getdouble (argv[5].o, &fs) == -1 ||
1014 getstr (argv[6].o, &justs) == -1 ||
1015 getgattr ((argc == 8) ? argv[7].o : NULL, &gattr) == -1
1016 )
1017 return L_FAILURE;
1018 Gtext (wi, s, p, fn, fs, justs, &gattr);
1019 return L_SUCCESS;
1020 }
1021
1022 /* LEFTY builtin */
GFXtextsize(int argc,lvar_t * argv)1023 int GFXtextsize (int argc, lvar_t *argv) {
1024 Gsize_t sp;
1025 double fs;
1026 char *s, *fn;
1027 long m;
1028 int wi;
1029
1030 if (
1031 getint (argv[0].o, &wi) == -1 || !ISAWIDGET (wi) || !ISACANVAS (wi) ||
1032 getstr (argv[1].o, &s) == -1 || getstr (argv[2].o, &fn) == -1 ||
1033 getdouble (argv[3].o, &fs) == -1
1034 )
1035 return L_FAILURE;
1036 if (Ggettextsize (wi, s, fn, fs, &sp) == -1)
1037 return L_FAILURE;
1038 m = Mpushmark ((rtno = Ttable (2)));
1039 Tinss (rtno, "x", Treal (sp.x)), Tinss (rtno, "y", Treal (sp.y));
1040 Mpopmark (m);
1041 return L_SUCCESS;
1042 }
1043
1044 /* LEFTY builtin */
GFXcreatebitmap(int argc,lvar_t * argv)1045 int GFXcreatebitmap (int argc, lvar_t *argv) {
1046 Tobj bo, so;
1047 Gsize_t s;
1048 long rtnm;
1049 int wi, bi;
1050
1051 if (
1052 getint (argv[0].o, &wi) == -1 || !ISAWIDGET (wi) || !ISACANVAS2 (wi) ||
1053 getxy (argv[1].o, &s) == -1
1054 )
1055 return L_FAILURE;
1056 if ((bi = Gcreatebitmap (wi, s)) == -1)
1057 return L_FAILURE;
1058 Tinsi (rootbo, bi, (bo = Ttable (4)));
1059 rtno = Tinteger (bi);
1060 rtnm = Mpushmark (rtno);
1061 Tinss (bo, "canvas", Tinteger (bi));
1062 Tinss (bo, "size", (so = Ttable (2)));
1063 Tinss (so, "x", Tinteger ((long) Gbitmaps[bi].size.x));
1064 Tinss (so, "y", Tinteger ((long) Gbitmaps[bi].size.y));
1065 Mpopmark (rtnm);
1066 return L_SUCCESS;
1067 }
1068
1069 /* LEFTY builtin */
GFXdestroybitmap(int argc,lvar_t * argv)1070 int GFXdestroybitmap (int argc, lvar_t *argv) {
1071 int bi;
1072
1073 if (getint (argv[0].o, &bi) == -1 || !ISABITMAP (bi))
1074 return L_FAILURE;
1075 Gdestroybitmap (bi);
1076 Tdeli (rootbo, bi);
1077 return L_SUCCESS;
1078 }
1079
1080 /* LEFTY builtin */
GFXreadbitmap(int argc,lvar_t * argv)1081 int GFXreadbitmap (int argc, lvar_t *argv) {
1082 Tobj bo, so;
1083 long rtnm;
1084 int wi, bi, ioi;
1085
1086 if (
1087 getint (argv[0].o, &wi) == -1 || !ISAWIDGET (wi) || !ISACANVAS2 (wi) ||
1088 getint (argv[1].o, &ioi) == -1 || ioi < 0 || ioi > ion ||
1089 !iop[ioi].inuse
1090 )
1091 return L_FAILURE;
1092 if ((bi = Greadbitmap (wi, iop[ioi].ifp)) == -1)
1093 return L_FAILURE;
1094 Tinsi (rootbo, bi, (bo = Ttable (4)));
1095 rtno = Tinteger (bi);
1096 rtnm = Mpushmark (rtno);
1097 Tinss (bo, "canvas", Tinteger (bi));
1098 Tinss (bo, "size", (so = Ttable (2)));
1099 Tinss (so, "x", Tinteger ((long) Gbitmaps[bi].size.x));
1100 Tinss (so, "y", Tinteger ((long) Gbitmaps[bi].size.y));
1101 Mpopmark (rtnm);
1102 return L_SUCCESS;
1103 }
1104
1105 /* LEFTY builtin */
GFXwritebitmap(int argc,lvar_t * argv)1106 int GFXwritebitmap (int argc, lvar_t *argv) {
1107 int bi, ioi;
1108
1109 if (
1110 getint (argv[0].o, &ioi) == -1 || ioi < 0 || ioi > ion ||
1111 !iop[ioi].inuse || getint (argv[1].o, &bi) == -1 || !ISABITMAP (bi)
1112 )
1113 return L_FAILURE;
1114 Gwritebitmap (iop[ioi].ofp, bi);
1115 return L_SUCCESS;
1116 }
1117
1118 /* LEFTY builtin */
GFXbitblt(int argc,lvar_t * argv)1119 int GFXbitblt (int argc, lvar_t *argv) {
1120 Ggattr_t gattr;
1121 Grect_t r;
1122 Gpoint_t p;
1123 char *mode;
1124 int wi, bi, rtn;
1125
1126 if (
1127 getint (argv[0].o, &wi) == -1 || !ISAWIDGET (wi) || !ISACANVAS2 (wi) ||
1128 getxy (argv[2].o, &p) == -1 || getrect (argv[3].o, &r) == -1 ||
1129 getint (argv[4].o, &bi) == -1 || getstr (argv[5].o, &mode) == -1 ||
1130 getgattr ((argc == 7) ? argv[6].o : NULL, &gattr) == -1
1131 )
1132 return L_FAILURE;
1133 rtn = Gbitblt (wi, p, r, bi, mode, &gattr);
1134 if (
1135 rtn == 0 && argv[1].o != null && ISACANVAS (wi) &&
1136 strcmp (mode, "b2c") == 0
1137 )
1138 rectmerge (NODEID (wi), argv[1].o, r);
1139 return L_SUCCESS;
1140 }
1141
1142 /* LEFTY builtin */
GFXclearpick(int argc,lvar_t * argv)1143 int GFXclearpick (int argc, lvar_t *argv) {
1144 int wi;
1145
1146 if (getint (argv[0].o, &wi) == -1 || !ISAWIDGET (wi) || !ISACANVAS (wi))
1147 return L_FAILURE;
1148 if (argv[1].o != null)
1149 rectdelete (NODEID (wi), argv[1].o);
1150 return L_SUCCESS;
1151 }
1152
1153 /* LEFTY builtin */
GFXsetpick(int argc,lvar_t * argv)1154 int GFXsetpick (int argc, lvar_t *argv) {
1155 Grect_t r;
1156 int wi;
1157
1158 if (
1159 getint (argv[0].o, &wi) == -1 || !ISAWIDGET (wi) || !ISACANVAS (wi) ||
1160 getrect (argv[2].o, &r) == -1
1161 )
1162 return L_FAILURE;
1163 if (argv[1].o != null)
1164 rectinsert (NODEID (wi), argv[1].o, r);
1165 return L_SUCCESS;
1166 }
1167
1168 /* LEFTY builtin */
GFXdisplaymenu(int argc,lvar_t * argv)1169 int GFXdisplaymenu (int argc, lvar_t *argv) {
1170 Tobj mo, meo;
1171 char buf[50];
1172 char *entries[1];
1173 int wi, mi, mei;
1174 int rtn;
1175
1176 if (
1177 getint (argv[0].o, &wi) == -1 || !ISAWIDGET (wi) ||
1178 !(ISACANVAS (wi) || ISALABEL (wi))
1179 )
1180 return L_FAILURE;
1181 mo = argv[1].o;
1182 if ((mi = menufind (NODEID (wi), mo, Tgettime (mo))) != -1) {
1183 if ((rtn = Gmenudisplay (wi, mi)) == -1)
1184 rtno = NULL;
1185 else
1186 rtno = Tinteger (rtn);
1187 return L_SUCCESS;
1188 }
1189 wattri = 0;
1190 mi = Gcreatewidget (wi, G_MENUWIDGET, wattri, wattrp);
1191 mei = 0;
1192 while ((meo = Tfindi (mo, mei))) {
1193 switch (Tgettype (meo)) {
1194 case T_STRING:
1195 entries[0] = Tgetstring (meo);
1196 break;
1197 case T_INTEGER:
1198 sprintf (buf, "%d", (int) Tgetnumber (meo));
1199 entries[0] = &buf[0];
1200 break;
1201 case T_REAL:
1202 sprintf (buf, "%f", Tgetnumber (meo));
1203 entries[0] = &buf[0];
1204 break;
1205 }
1206 Gmenuaddentries (mi, 1, &entries[0]);
1207 mei++;
1208 }
1209 menuinsert (NODEID (wi), mo, Tgettime (mo), mi);
1210 Ttime++;
1211 if ((rtn = Gmenudisplay (wi, mi)) == -1)
1212 rtno = NULL;
1213 else
1214 rtno = Tinteger (rtn);
1215 return L_SUCCESS;
1216 }
1217
1218 /* LEFTY builtin */
GFXcolormap(int argc,lvar_t * argv)1219 int GFXcolormap (int argc, lvar_t *argv) {
1220 char *cs;
1221 int cni;
1222 long rtnm;
1223
1224 if (getstr (argv[0].o, &cs) == -1)
1225 return L_FAILURE;
1226 rtno = NULL;
1227 for (cni = 0; cni < sizeof (colornames) / sizeof (colorname_t); cni++) {
1228 if (strcmp (colornames[cni].name, cs) != 0)
1229 continue;
1230 rtno = Ttable (4);
1231 rtnm = Mpushmark (rtno);
1232 Tinss (rtno, "r", Tinteger (colornames[cni].r));
1233 Tinss (rtno, "g", Tinteger (colornames[cni].g));
1234 Tinss (rtno, "b", Tinteger (colornames[cni].b));
1235 Mpopmark (rtnm);
1236 break;
1237 }
1238 return L_SUCCESS;
1239 }
1240
getwattr(Tobj ao,int * type)1241 static int getwattr (Tobj ao, int *type) {
1242 Tkvindex_t tkvi;
1243 Tobj co;
1244 int *ap;
1245 char *ts;
1246 int li, ai;
1247
1248 wattri = 0;
1249 if (!ao && Tgettype (ao) != T_TABLE)
1250 return -1;
1251 if (*type == -1) {
1252 if (getstr (Tfinds (ao, "type"), &ts) == -1)
1253 return -1;
1254 for (ap = NULL, li = 0; Gwlist[li].wname; li++) {
1255 if (strcmp (ts, Gwlist[li].wname) == 0) {
1256 *type = Gwlist[li].wid;
1257 ap = Gwlist[li].attrid;
1258 break;
1259 }
1260 }
1261 if (*type == -1)
1262 return -1;
1263 if (wattri >= wattrn) {
1264 wattrp = Marraygrow (
1265 wattrp, (long) (wattrn + WATTRINCR) * WATTRSIZE
1266 );
1267 wattrn += WATTRINCR;
1268 }
1269 switch (*type) {
1270 case G_TEXTWIDGET:
1271 wattrp[wattri].id = G_ATTRNEWLINECB;
1272 wattrp[wattri].u.func = GFXtextcb, wattri++;
1273 break;
1274 case G_ARRAYWIDGET:
1275 wattrp[wattri].id = G_ATTRRESIZECB;
1276 wattrp[wattri].u.func = GFXarrayresizecb, wattri++;
1277 break;
1278 case G_BUTTONWIDGET:
1279 wattrp[wattri].id = G_ATTRBUTTONCB;
1280 wattrp[wattri].u.func = GFXbuttoncb, wattri++;
1281 break;
1282 case G_LABELWIDGET:
1283 wattrp[wattri].id = G_ATTREVENTCB;
1284 wattrp[wattri].u.func = GFXlabelcb, wattri++;
1285 break;
1286 case G_CANVASWIDGET:
1287 wattrp[wattri].id = G_ATTREVENTCB;
1288 wattrp[wattri].u.func = GFXevent, wattri++;
1289 break;
1290 case G_VIEWWIDGET:
1291 wattrp[wattri].id = G_ATTREVENTCB;
1292 wattrp[wattri].u.func = GFXviewcb, wattri++;
1293 break;
1294 }
1295 } else {
1296 for (ap = NULL, li = 0; Gwlist[li].wname; li++) {
1297 if (*type == Gwlist[li].wid) {
1298 ap = Gwlist[li].attrid;
1299 break;
1300 }
1301 }
1302 }
1303 for (ai = 0; ap[ai] != -1; ai++) {
1304 if (wattri >= wattrn) {
1305 wattrp = Marraygrow (
1306 wattrp, (long) (wattrn + WATTRINCR) * WATTRSIZE
1307 );
1308 wattrn += WATTRINCR;
1309 }
1310 wattrp[wattri].id = ap[ai];
1311 switch (Gwattrmap[ap[ai]].type) {
1312 case G_ATTRTYPEPOINT:
1313 getwpointnset (Tfinds (ao, Gwattrmap[ap[ai]].name));
1314 break;
1315 case G_ATTRTYPESIZE:
1316 getwsizenset (Tfinds (ao, Gwattrmap[ap[ai]].name));
1317 break;
1318 case G_ATTRTYPERECT:
1319 getwrectnset (Tfinds (ao, Gwattrmap[ap[ai]].name));
1320 break;
1321 case G_ATTRTYPETEXT:
1322 getwstrnset (Tfinds (ao, Gwattrmap[ap[ai]].name));
1323 break;
1324 case G_ATTRTYPEINT:
1325 getwintnset (Tfinds (ao, Gwattrmap[ap[ai]].name));
1326 break;
1327 case G_ATTRTYPECOLOR:
1328 if ((co = Tfinds (
1329 ao, Gwattrmap[ap[ai]].name
1330 )) && Tgettype (co) == T_TABLE) {
1331 for (Tgetfirst (co, &tkvi); tkvi.kvp; Tgetnext (&tkvi)) {
1332 if (wattri >= wattrn) {
1333 wattrp = Marraygrow (
1334 wattrp, (long) (wattrn + WATTRINCR) * WATTRSIZE
1335 );
1336 wattrn += WATTRINCR;
1337 }
1338 wattrp[wattri].id = ap[ai];
1339 getwcolornset (tkvi.kvp->ko, tkvi.kvp->vo);
1340 }
1341 }
1342 break;
1343 }
1344 }
1345 return wattri;
1346 }
1347
getgattr(Tobj ao,Ggattr_t * dp)1348 static int getgattr (Tobj ao, Ggattr_t *dp) {
1349 Tkvindex_t tkvi;
1350 char *s, *s2;
1351
1352 dp->flags = 0;
1353 if (!ao)
1354 return 0;
1355 if (Tgettype (ao) != T_TABLE)
1356 return -1;
1357 for (Tgetfirst (ao, &tkvi); tkvi.kvp; Tgetnext (&tkvi)) {
1358 if (Tgettype (tkvi.kvp->ko) != T_STRING)
1359 continue;
1360 s = Tgetstring (tkvi.kvp->ko);
1361 if (strcmp (s, "color") == 0) {
1362 getaintnset (tkvi.kvp->vo, dp->color, G_GATTRCOLOR);
1363 } else if (strcmp (s, "width") == 0) {
1364 getaintnset (tkvi.kvp->vo, dp->width, G_GATTRWIDTH);
1365 } else if (strcmp (s, "mode") == 0) {
1366 getastrnset (tkvi.kvp->vo, s2, G_GATTRMODE);
1367 if (dp->flags & G_GATTRMODE) {
1368 if (strcmp (s2, "src") == 0)
1369 dp->mode = G_SRC;
1370 else if (strcmp (s2, "xor") == 0)
1371 dp->mode = G_XOR;
1372 else
1373 dp->flags &= ~G_GATTRMODE;
1374 }
1375 } else if (strcmp (s, "fill") == 0) {
1376 getastrnset (tkvi.kvp->vo, s2, G_GATTRFILL);
1377 if (dp->flags & G_GATTRFILL) {
1378 if (strcmp (s2, "on") == 0)
1379 dp->fill = 1;
1380 else if (strcmp (s2, "off") == 0)
1381 dp->fill = 0;
1382 else
1383 dp->flags &= ~G_GATTRFILL;
1384 }
1385 } else if (strcmp (s, "style") == 0) {
1386 getastrnset (tkvi.kvp->vo, s2, G_GATTRSTYLE);
1387 if (dp->flags & G_GATTRSTYLE) {
1388 if (strcmp (s2, "solid") == 0)
1389 dp->style = G_SOLID;
1390 else if (strcmp (s2, "dashed") == 0)
1391 dp->style = G_DASHED;
1392 else if (strcmp (s2, "dotted") == 0)
1393 dp->style = G_DOTTED;
1394 else if (strcmp (s2, "longdashed") == 0)
1395 dp->style = G_LONGDASHED;
1396 else if (strcmp (s2, "shortdashed") == 0)
1397 dp->style = G_SHORTDASHED;
1398 else
1399 dp->flags &= ~G_GATTRSTYLE;
1400 }
1401 }
1402 }
1403 return 0;
1404 }
1405
getrect(Tobj ro,Grect_t * rp)1406 static int getrect (Tobj ro, Grect_t *rp) {
1407 if (ro && Tgettype (ro) == T_TABLE)
1408 if (
1409 getxy (Tfindi (ro, 0), &rp->o) != -1 &&
1410 getxy (Tfindi (ro, 1), &rp->c) != -1
1411 )
1412 return 0;
1413 return -1;
1414 }
1415
getxy(Tobj po,Gxy_t * xyp)1416 static int getxy (Tobj po, Gxy_t *xyp) {
1417 Tobj xo, yo;
1418
1419 if (po && Tgettype (po) == T_TABLE) {
1420 xo = Tfinds (po, "x"), yo = Tfinds (po, "y");
1421 if (xo && T_ISNUMBER (xo) && yo && T_ISNUMBER (yo)) {
1422 xyp->x = Tgetnumber (xo), xyp->y = Tgetnumber (yo);
1423 return 0;
1424 }
1425 }
1426 return -1;
1427 }
1428
getint(Tobj to,int * ip)1429 static int getint (Tobj to, int *ip) {
1430 if (to && T_ISNUMBER (to)) {
1431 *ip = Tgetnumber (to);
1432 return 0;
1433 }
1434 return -1;
1435 }
1436
getdouble(Tobj to,double * dp)1437 static int getdouble (Tobj to, double *dp) {
1438 if (to && T_ISNUMBER (to)) {
1439 *dp = Tgetnumber (to);
1440 return 0;
1441 }
1442 return -1;
1443 }
1444
getstr(Tobj so,char ** s)1445 static int getstr (Tobj so, char **s) {
1446 if (so && T_ISSTRING (so)) {
1447 *s = Tgetstring (so);
1448 return 0;
1449 }
1450 return -1;
1451 }
1452
getcolor(Tobj ko,Tobj co,Gcolor_t * cp)1453 static int getcolor (Tobj ko, Tobj co, Gcolor_t *cp) {
1454 Tobj ro, go, bo, ho, so, vo;
1455 char *s, *s1, *s2;
1456 float hc, sc, vc;
1457 int cni;
1458 int r, g, b, a;
1459
1460 if (ko && T_ISNUMBER (ko))
1461 cp->index = Tgetnumber (ko);
1462 else
1463 return -1;
1464 if (!co || !(T_ISSTRING (co) || T_ISTABLE (co)))
1465 return -1;
1466 if (T_ISSTRING (co)) {
1467 s = Tgetstring (co);
1468 while (*s == ' ')
1469 s++; /* skip over any leading spaces */
1470 if (*s == '#' && sscanf (s, "#%2x%2x%2x%2x", &r, &g, &b, &a) >= 3) {
1471 cp->r = r;
1472 cp->g = g;
1473 cp->b = b;
1474 return 0;
1475 }
1476 if ((isdigit (*s) || *s == '.') && scanhsv (s, &hc, &sc, &vc)) {
1477 hsv2rgb (hc, sc, vc, cp);
1478 return 0;
1479 }
1480 for (cni = 0; cni < sizeof (colornames) / sizeof (colorname_t); cni++) {
1481 for (s1 = colornames[cni].name, s2 = s; *s1 && *s2; s1++, s2++) {
1482 if (*s2 == ' ' || *s2 == '_')
1483 s2++;
1484 else if (*s1 != *s2)
1485 break;
1486 }
1487 if (*s1 != *s2)
1488 continue;
1489 cp->r = colornames[cni].r;
1490 cp->g = colornames[cni].g;
1491 cp->b = colornames[cni].b;
1492 return 0;
1493 }
1494 return -1;
1495 } else {
1496 ro = Tfinds (co, "r");
1497 go = Tfinds (co, "g");
1498 bo = Tfinds (co, "b");
1499 if (
1500 ro && T_ISNUMBER (ro) && go && T_ISNUMBER (go) &&
1501 bo && T_ISNUMBER (bo)
1502 ) {
1503 cp->r = Tgetnumber (ro);
1504 cp->g = Tgetnumber (go);
1505 cp->b = Tgetnumber (bo);
1506 return 0;
1507 } else {
1508 ho = Tfinds (co, "h");
1509 so = Tfinds (co, "s");
1510 vo = Tfinds (co, "v");
1511 if (
1512 ho && T_ISNUMBER (ho) && so && T_ISNUMBER (so) &&
1513 vo && T_ISNUMBER (vo)
1514 ) {
1515 hc = Tgetnumber (ho);
1516 sc = Tgetnumber (so);
1517 vc = Tgetnumber (vo);
1518 hsv2rgb (hc, sc, vc, cp);
1519 return 0;
1520 } else
1521 return -1;
1522 }
1523 }
1524 return -1;
1525 }
1526
nodeinit(int ni)1527 static void nodeinit (int ni) {
1528 int li, ki;
1529
1530 for (li = 0; li < LISTSIZE; li++)
1531 gfxnodes[ni].rect[li] = NULL, gfxnodes[ni].menu[li] = NULL;
1532 gfxnodes[ni].ls = gfxnodes[ni].ms = gfxnodes[ni].rs = 0;
1533 for (ki = 0; ki < 256; ki++)
1534 gfxnodes[ni].ks[ki] = 0;
1535 gfxnodes[ni].plvo = gfxnodes[ni].pmvo = gfxnodes[ni].prvo = 0;
1536 gfxnodes[ni].pb3vo = gfxnodes[ni].pb4vo = 0;
1537 for (ki = 0; ki < 256; ki++)
1538 gfxnodes[ni].pkvo[ki] = 0;
1539 }
1540
nodeterm(int ni)1541 static void nodeterm (int ni) {
1542 gfxrect_t **rp;
1543 gfxrect_t *crp, *nrp;
1544 gfxmenu_t **mp;
1545 gfxmenu_t *cmp, *nmp;
1546 int li;
1547
1548 for (li = 0; li < LISTSIZE; li++) {
1549 rp = &gfxnodes[ni].rect[li];
1550 for (crp = *rp; crp; crp = nrp)
1551 nrp = crp->next, free (crp);
1552 *rp = NULL;
1553 mp = &gfxnodes[ni].menu[li];
1554 for (cmp = *mp; cmp; cmp = nmp)
1555 nmp = cmp->next, free (cmp);
1556 *mp = NULL;
1557 }
1558 }
1559
rectinit(int ni)1560 static void rectinit (int ni) {
1561 int li;
1562
1563 for (li = 0; li < LISTSIZE; li++)
1564 gfxnodes[ni].rect[li] = NULL;
1565 }
1566
rectterm(int ni)1567 static void rectterm (int ni) {
1568 gfxrect_t **rp;
1569 gfxrect_t *crp, *nrp;
1570 int li;
1571
1572 for (li = 0; li < LISTSIZE; li++) {
1573 rp = &gfxnodes[ni].rect[li];
1574 for (crp = *rp; crp; crp = nrp)
1575 nrp = crp->next, free (crp);
1576 *rp = NULL;
1577 }
1578 }
1579
rectinsert(int ni,Tobj ko,Grect_t r)1580 static void rectinsert (int ni, Tobj ko, Grect_t r) {
1581 gfxrect_t **rp;
1582 gfxrect_t *crp;
1583
1584 rp = &gfxnodes[ni].rect[(uint64_t) ko % LISTSIZE];
1585 for (crp = *rp; crp; crp = crp->next)
1586 if (crp->ko == ko) {
1587 crp->r.o.x = min (r.o.x, r.c.x);
1588 crp->r.o.y = min (r.o.y, r.c.y);
1589 crp->r.c.x = max (r.o.x, r.c.x);
1590 crp->r.c.y = max (r.o.y, r.c.y);
1591 return;
1592 }
1593 if (!(crp = malloc (sizeof (gfxrect_t))))
1594 panic1 (POS, "rectinsert", "rect malloc failed");
1595
1596 crp->ko = ko;
1597 crp->r.o.x = min (r.o.x, r.c.x);
1598 crp->r.o.y = min (r.o.y, r.c.y);
1599 crp->r.c.x = max (r.o.x, r.c.x);
1600 crp->r.c.y = max (r.o.y, r.c.y);
1601 crp->next = *rp;
1602 *rp = crp;
1603 }
1604
rectmerge(int ni,Tobj ko,Grect_t r)1605 static void rectmerge (int ni, Tobj ko, Grect_t r) {
1606 gfxrect_t **rp;
1607 gfxrect_t *crp;
1608
1609 rp = &gfxnodes[ni].rect[(uint64_t) ko % LISTSIZE];
1610 for (crp = *rp; crp; crp = crp->next)
1611 if (crp->ko == ko) {
1612 crp->r.o.x = min (crp->r.o.x, min (r.o.x, r.c.x));
1613 crp->r.o.y = min (crp->r.o.y, min (r.o.y, r.c.y));
1614 crp->r.c.x = max (crp->r.c.x, max (r.o.x, r.c.x));
1615 crp->r.c.y = max (crp->r.c.y, max (r.o.y, r.c.y));
1616 return;
1617 }
1618 if (!(crp = malloc (sizeof (gfxrect_t))))
1619 panic1 (POS, "rectmerge", "rect malloc failed");
1620
1621 crp->ko = ko;
1622 crp->r.o.x = min (r.o.x, r.c.x);
1623 crp->r.o.y = min (r.o.y, r.c.y);
1624 crp->r.c.x = max (r.o.x, r.c.x);
1625 crp->r.c.y = max (r.o.y, r.c.y);
1626 crp->next = *rp;
1627 *rp = crp;
1628 }
1629
rectfind(int ni,Gpoint_t p)1630 static Tobj rectfind (int ni, Gpoint_t p) {
1631 gfxrect_t **rp;
1632 gfxrect_t *crp;
1633 int li;
1634
1635 for (li = 0; li < LISTSIZE; li++) {
1636 rp = &gfxnodes[ni].rect[li];
1637 for (crp = *rp; crp; crp = crp->next)
1638 if (
1639 crp->r.o.x <= p.x && crp->r.c.x >= p.x &&
1640 crp->r.o.y <= p.y && crp->r.c.y >= p.y
1641 )
1642 return crp->ko;
1643 }
1644 return NULL;
1645 }
1646
rectdelete(int ni,Tobj ko)1647 static void rectdelete (int ni, Tobj ko) {
1648 gfxrect_t **rp;
1649 gfxrect_t *crp, *prp;
1650
1651 rp = &gfxnodes[ni].rect[(uint64_t) ko % LISTSIZE];
1652 for (crp = *rp, prp = NULL; crp; prp = crp, crp = crp->next)
1653 if (crp->ko == ko) {
1654 if (crp == *rp)
1655 *rp = crp->next;
1656 else
1657 prp->next = crp->next;
1658 free (crp);
1659 return;
1660 }
1661 }
1662
rectprune(int ni)1663 static void rectprune (int ni) {
1664 gfxrect_t **rp;
1665 gfxrect_t *crp, *prp;
1666 int li;
1667
1668 for (li = 0; li < LISTSIZE; li++) {
1669 rp = &gfxnodes[ni].rect[li];
1670 for (crp = *rp, prp = NULL; crp; ) {
1671 if (!M_AREAOF (crp->ko)) {
1672 if (crp == *rp)
1673 *rp = crp->next, free (crp), crp = *rp;
1674 else
1675 prp->next = crp->next, free (crp), crp = prp->next;
1676 } else
1677 prp = crp, crp = crp->next;
1678 }
1679 }
1680 }
1681
menuinsert(int ni,Tobj ko,long time,int mi)1682 static void menuinsert (int ni, Tobj ko, long time, int mi) {
1683 gfxmenu_t **mp;
1684 gfxmenu_t *cmp;
1685
1686 mp = &gfxnodes[ni].menu[(uint64_t) ko % LISTSIZE];
1687 for (cmp = *mp; cmp; cmp = cmp->next)
1688 if (cmp->ko == ko) {
1689 cmp->time = time, cmp->mi = mi;
1690 return;
1691 }
1692 if (!(cmp = malloc (sizeof (gfxmenu_t))))
1693 panic1 (POS, "menuinsert", "menu malloc failed");
1694
1695 cmp->ko = ko;
1696 cmp->time = time;
1697 cmp->mi = mi;
1698 cmp->next = *mp;
1699 *mp = cmp;
1700 }
1701
menufind(int ni,Tobj ko,long time)1702 static int menufind (int ni, Tobj ko, long time) {
1703 gfxmenu_t **mp;
1704 gfxmenu_t *cmp;
1705
1706 mp = &gfxnodes[ni].menu[(uint64_t) ko % LISTSIZE];
1707 for (cmp = *mp; cmp; cmp = cmp->next)
1708 if (cmp->ko == ko && cmp->time == time)
1709 return cmp->mi;
1710 return -1;
1711 }
1712
menuprune(int ni)1713 static void menuprune (int ni) {
1714 gfxmenu_t **mp;
1715 gfxmenu_t *cmp, *pmp;
1716 int li;
1717
1718 for (li = 0; li < LISTSIZE; li++) {
1719 mp = &gfxnodes[ni].menu[li];
1720 for (cmp = *mp, pmp = NULL; cmp; ) {
1721 if (!M_AREAOF (cmp->ko)) {
1722 if (cmp == *mp)
1723 *mp = cmp->next, free (cmp), cmp = *mp;
1724 else
1725 pmp->next = cmp->next, free (cmp), cmp = pmp->next;
1726 } else
1727 pmp = cmp, cmp = cmp->next;
1728 }
1729 }
1730 }
1731
1732 /* scan a string for 3 floating point numbers separated by
1733 white-space or commas.
1734 */
scanhsv(char * strp,float * h,float * s,float * v)1735 static int scanhsv (char *strp, float *h, float *s, float *v) {
1736 char *endp;
1737
1738 *h = strtod (strp, &endp);
1739 if (endp == strp)
1740 return 0;
1741 strp = endp;
1742 while (*strp == ',' || isspace (*strp))
1743 strp++;
1744 *s = strtod (strp, &endp);
1745 if (endp == strp)
1746 return 0;
1747 strp = endp;
1748 while (*strp == ',' || isspace (*strp))
1749 strp++;
1750 *v = strtod (strp, &endp);
1751 if (endp == strp)
1752 return 0;
1753 return 1;
1754 }
1755
hsv2rgb(float h,float s,float v,Gcolor_t * cp)1756 static void hsv2rgb (float h, float s, float v, Gcolor_t *cp) {
1757 float r, g, b, f, p, q, t;
1758 int i;
1759
1760 /* clip to reasonable values */
1761 h = max (min (h, 1.0), 0.0);
1762 s = max (min (s, 1.0), 0.0);
1763 v = max (min (v, 1.0), 0.0);
1764 r = g = b = 0.0;
1765
1766 if (s == 0.0)
1767 r = g = b = v;
1768 else {
1769 if (h == 1.0)
1770 h = 0.0;
1771 h = h * 6.0;
1772 i = (int) h;
1773 f = h - (float) i;
1774 p = v * (1 - s);
1775 q = v * (1 - (s * f));
1776 t = v * (1 - (s * (1 - f)));
1777 switch (i) {
1778 case 0: r = v; g = t; b = p; break;
1779 case 1: r = q; g = v; b = p; break;
1780 case 2: r = p; g = v; b = t; break;
1781 case 3: r = p; g = q; b = v; break;
1782 case 4: r = t; g = p; b = v; break;
1783 case 5: r = v; g = p; b = q; break;
1784 }
1785 }
1786 cp->r = (int) (255.0 * r);
1787 cp->g = (int) (255.0 * g);
1788 cp->b = (int) (255.0 * b);
1789 }
1790