1 /*--------------------------------------------------------------*/
2 /* python.c --- Embedded python interpreter for xcircuit	*/
3 /* Copyright (c) 2002  Tim Edwards, Johns Hopkins University    */
4 /*--------------------------------------------------------------*/
5 /* NOTE: These routines work only if python-2.0 is installed.   */
6 /*	Requires library file libpython2.0.a.  Hopefully	*/
7 /*	one day there will be a standard libpython${VERSION}.so	*/
8 /*	so that the whole thing doesn't have to be linked	*/
9 /*	into the xcircuit executable. . .			*/
10 /*								*/
11 /*	Modeled after demo.c in Python2.0 source Demo/embed	*/
12 /*--------------------------------------------------------------*/
13 
14 #if defined(HAVE_PYTHON) && !defined(TCL_WRAPPER)
15 
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <unistd.h>	/* for usleep() */
19 #include <string.h>
20 
21 #include <Python.h>
22 
23 #include <X11/Intrinsic.h>
24 #include <X11/StringDefs.h>
25 #include "Xw/Xw.h"
26 #include "Xw/MenuBtn.h"
27 
28 #ifdef HAVE_XPM
29 #include <X11/xpm.h>
30 #include "lib/pixmaps/q.xpm"
31 #endif
32 
33 PyObject *xcmod;
34 
35 /*----------------------------------------------------------------------*/
36 /* Local includes                                                       */
37 /*----------------------------------------------------------------------*/
38 
39 #include "xcircuit.h"
40 #include "menudep.h"
41 #include "colordefs.h"
42 
43 /*----------------------------------------------------------------------*/
44 /* Function prototype declarations                                      */
45 /*----------------------------------------------------------------------*/
46 
47 #include "prototypes.h"
48 
49 static PyObject *xc_new(PyObject *, PyObject *);
50 static PyObject *xc_set(PyObject *, PyObject *);
51 static PyObject *xc_override(PyObject *, PyObject *);
52 static PyObject *xc_library(PyObject *, PyObject *);
53 static PyObject *xc_font(PyObject *, PyObject *);
54 static PyObject *xc_color(PyObject *, PyObject *);
55 static PyObject *xc_pause(PyObject *, PyObject *);
56 static PyObject *xc_refresh(PyObject *, PyObject *);
57 static PyObject *xc_bind(PyObject *, PyObject *);
58 static PyObject *xc_unbind(PyObject *, PyObject *);
59 static PyObject *xc_simplepopup(PyObject *, PyObject *);
60 static PyObject *xc_popupprompt(PyObject *, PyObject *);
61 static PyObject *xc_filepopup(PyObject *, PyObject *);
62 static PyObject *xc_newbutton(PyObject *, PyObject *);
63 static PyObject *xc_page(PyObject *, PyObject *);
64 static PyObject *xc_load(PyObject *, PyObject *);
65 static PyObject *xc_pan(PyObject *, PyObject *);
66 static PyObject *xc_zoom(PyObject *, PyObject *);
67 static PyObject *xc_getcursor();
68 static PyObject *xc_getwindow();
69 static PyObject *xc_reset();
70 static PyObject *xc_netlist();
71 #ifdef HAVE_XPM
72 static PyObject *xc_newtool(PyObject *, PyObject *);
73 #endif
74 
75 int string_to_type(const char *);
76 
77 /*----------------------------------------------------------------------*/
78 /* External variable declarations                                       */
79 /*----------------------------------------------------------------------*/
80 
81 extern char _STR2[250], _STR[150];
82 extern fontinfo *fonts;
83 extern short fontcount;
84 extern XCWindowData *areawin;
85 extern Globaldata xobjs;
86 extern short beeper;
87 extern Widget menuwidgets[];
88 extern Display *dpy;
89 extern keybinding *keylist;
90 extern int number_colors;
91 extern colorindex *colorlist;
92 extern ApplicationData appdata;
93 #ifdef HAVE_XPM
94 extern Widget toolbar;
95 #endif
96 
97 /*----------------------------------------------------------------------*/
98 
99 short flags = -1;
100 
101 #define LIBOVERRIDE     1
102 #define LIBLOADED       2
103 #define COLOROVERRIDE   4
104 #define FONTOVERRIDE    8
105 #define KEYOVERRIDE	16
106 
107 /*----------------------------------------------------------------*/
108 /* Similar to "PyRun_SimpleString()" but returns a PyObject value */
109 /* rather than a status word.					  */
110 /*----------------------------------------------------------------*/
111 
PyRun_ObjString(char * string)112 PyObject *PyRun_ObjString(char *string)
113 {
114    PyObject *m, *d, *v;
115    m = PyImport_AddModule("__main__");
116    if (m == NULL) return NULL;
117    d = PyModule_GetDict(m);
118    v = PyRun_String(string, Py_file_input, d, d);
119    return v;
120 }
121 
122 /*--------------------------------------------------------------*/
123 /* Define all of the xcircuit functions available to Python	*/
124 /* Currently this does the bare minimum of having Python do the	*/
125 /* argument parsing; ideally, we would like to be doing more	*/
126 /* fundamental processing here.					*/
127 /*--------------------------------------------------------------*/
128 
129 /*--------------------------------------------------------------*/
130 /* Extract text from a popup and call the indicated python	*/
131 /* function.   If there is no text, function is called without	*/
132 /* arguments.							*/
133 /*--------------------------------------------------------------*/
134 
pypromptvalue(Widget w,char * functionptr)135 void pypromptvalue(Widget w, char *functionptr)
136 {
137    if (strlen(_STR2) == 0)
138       sprintf(_STR, "%s()\n", functionptr);
139    else
140       sprintf(_STR, "%s('%s')\n", functionptr, _STR2);
141 
142    PyRun_SimpleString(_STR);
143    refresh(NULL, NULL, NULL);
144 }
145 
146 /*--------------------------------------------------------------*/
147 /* Pop up a prompt, and return the value to the indicated	*/
148 /* python function.						*/
149 /*--------------------------------------------------------------*/
150 
pypopupprompt(PyObject * self,PyObject * args,const char * dofile,char * displaystr)151 static PyObject *pypopupprompt(PyObject *self, PyObject *args,
152 	const char *dofile, char *displaystr)
153 {
154    const char *pfunction = NULL;
155    const char *prompt = NULL;
156    buttonsave *savebutton;
157 
158    if (!PyArg_ParseTuple(args, "ss:popupprompt", &prompt, &pfunction))
159       return PyInt_FromLong(-1L);
160 
161 
162    savebutton = getgeneric(NULL, NULL, (void *)pfunction);
163    popupprompt(areawin->area, (char *)prompt, displaystr,
164 		pypromptvalue, savebutton, dofile);
165 
166    return PyInt_FromLong(0L);
167 }
168 
169 /*--------------------------------------------------------------*/
170 /* Wrappers for pypopuprompt()					*/
171 /*--------------------------------------------------------------*/
172 
xc_popupprompt(PyObject * self,PyObject * args)173 static PyObject *xc_popupprompt(PyObject *self, PyObject *args)
174 {
175    return pypopupprompt(self, args, NULL, "");
176 }
177 
xc_filepopup(PyObject * self,PyObject * args)178 static PyObject *xc_filepopup(PyObject *self, PyObject *args)
179 {
180    return pypopupprompt(self, args, "", "");
181 }
182 
xc_simplepopup(PyObject * self,PyObject * args)183 static PyObject *xc_simplepopup(PyObject *self, PyObject *args)
184 {
185    _STR2[0] = '\0';
186    return pypopupprompt(self, args, False, NULL);
187 }
188 
189 /*--------------------------------------------------------------*/
190 /* Create objects and return a handle to that object in the	*/
191 /* form of a Python integer Object.				*/
192 /*--------------------------------------------------------------*/
193 
xc_new(PyObject * self,PyObject * args)194 static PyObject *xc_new(PyObject *self, PyObject *args)
195 {
196    const char *etype;
197    int type;
198 
199    genericptr *newgen;
200    arcptr *newarc;
201    splineptr *newspline;
202    polyptr *newpoly;
203    labelptr *newlabel;
204    pathptr *newpath;
205    objinstptr *newobjinst;
206 
207    if (!PyArg_ParseTuple(args, "s:newelement", &etype))
208       return NULL;
209 
210    switch(type = string_to_type(etype)) {
211       case ARC:
212          NEW_ARC(newarc, topobject);
213 	 arcdefaults(*newarc, 0, 0);
214 	 newgen = (genericptr *)newarc;
215 	 break;
216       case SPLINE:
217          NEW_SPLINE(newspline, topobject);
218 	 splinedefaults(*newspline, 0, 0);
219 	 newgen = (genericptr *)newspline;
220 	 break;
221       case POLYGON:
222          NEW_POLY(newpoly, topobject);
223 	 polydefaults(*newpoly, 4, 0, 0);
224 	 newgen = (genericptr *)newpoly;
225 	 break;
226       case LABEL:
227          NEW_LABEL(newlabel, topobject);
228 	 labeldefaults(*newlabel, 0, 0, 0);
229 	 newgen = (genericptr *)newlabel;
230 	 break;
231       case PATH:
232          NEW_PATH(newpath, topobject);
233 	 pathdefaults(*newpath, 0, 0);
234 	 newgen = (genericptr *)newpath;
235 	 break;
236       case OBJINST:
237          NEW_OBJINST(newobjinst, topobject);
238 	 instancedefaults(*newobjinst, NULL, 0, 0);
239 	 newgen = (genericptr *)newobjinst;
240 	 break;
241       default:
242          PyErr_SetString(PyExc_TypeError,
243 		"newelement() 2nd argument must be a valid element type");
244          return NULL;
245    }
246    incr_changes(topobject);
247    invalidate_netlist(topobject);
248 
249    return PyInt_FromLong((long)(*newgen));
250 }
251 
252 /*--------------------------------------------------------------*/
253 /* Convert object type to a string				*/
254 /*--------------------------------------------------------------*/
255 
type_to_string(int type)256 char *type_to_string(int type)
257 {
258    char *retstr = NULL;
259 
260    switch(type) {
261       case LABEL:
262 	 retstr = malloc(6);
263 	 strcpy(retstr, "Label");
264 	 break;
265       case POLYGON:
266 	 retstr = malloc(8);
267 	 strcpy(retstr, "Polygon");
268 	 break;
269       case SPLINE:
270 	 retstr = malloc(12);
271 	 strcpy(retstr, "Bezier Curve");
272 	 break;
273       case OBJINST:
274 	 retstr = malloc(16);
275 	 strcpy(retstr, "Object Instance");
276 	 break;
277       case PATH:
278 	 retstr = malloc(5);
279 	 strcpy(retstr, "Path");
280 	 break;
281       case ARC:
282 	 retstr = malloc(4);
283 	 strcpy(retstr, "Arc");
284 	 break;
285    }
286    return retstr;
287 }
288 
289 /*--------------------------------------------------------------*/
290 /* Convert a string to an element type				*/
291 /*--------------------------------------------------------------*/
292 
string_to_type(const char * etype)293 int string_to_type(const char *etype)
294 {
295    if (!strcmp(etype, "Arc"))
296       return ARC;
297    else if (!strcmp(etype, "Bezier Curve"))
298       return SPLINE;
299    else if (!strcmp(etype, "Polygon"))
300       return POLYGON;
301    else if (!strcmp(etype, "Label"))
302       return LABEL;
303    else if (!strcmp(etype, "Path"))
304       return PATH;
305    else if (!strcmp(etype, "Object Instance"))
306       return OBJINST;
307    else
308       return -1;
309 }
310 
311 /*--------------------------------------------------------------*/
312 /* Convert color index to 3-tuple and vice versa		*/
313 /* We assume that this color exists in the color table.		*/
314 /*--------------------------------------------------------------*/
315 
PyIndexToRGB(int cidx)316 PyObject *PyIndexToRGB(int cidx)
317 {
318    int i;
319    PyObject *RGBTuple;
320 
321    if (cidx < 0) {	/* Handle "default color" */
322       return PyString_FromString("Default");
323    }
324 
325    for (i = 0; i < number_colors; i++) {
326       if (cidx == colorlist[i].color.pixel) {
327 	 RGBTuple = PyTuple_New(3);
328 	 PyTuple_SetItem(RGBTuple, 0,
329 		PyInt_FromLong((long)(colorlist[i].color.red / 256)));
330 	 PyTuple_SetItem(RGBTuple, 1,
331 		PyInt_FromLong((long)(colorlist[i].color.green / 256)));
332 	 PyTuple_SetItem(RGBTuple, 2,
333 		PyInt_FromLong((long)(colorlist[i].color.blue / 256)));
334 	 return RGBTuple;
335       }
336    }
337    PyErr_SetString(PyExc_TypeError, "invalid or unknown color index");
338    return NULL;
339 }
340 
341 /*--------------------------------------------------------------*/
342 /* Convert color 3-tuple (RGB) or name to a color index		*/
343 /*--------------------------------------------------------------*/
344 
PyRGBToIndex(PyObject * cobj)345 int PyRGBToIndex(PyObject *cobj)
346 {
347    PyObject *tobj;
348    int ccolor, r, g, b;
349 
350    if (PyTuple_Check(cobj) && PyTuple_Size(cobj) == 3) {  /* RGB 3-tuple */
351       tobj = PyTuple_GetItem(cobj, 0);
352       if (PyFloat_Check(tobj)) {
353          r = (int)(65535 * (float)PyFloat_AsDouble(tobj));
354          g = (int)(65535 * (float)PyFloat_AsDouble(PyTuple_GetItem(cobj, 1)));
355          b = (int)(65535 * (float)PyFloat_AsDouble(PyTuple_GetItem(cobj, 2)));
356       }
357       else if (PyInt_Check(tobj)) {
358          r = (int)(256 * PyInt_AsLong(tobj));
359          g = (int)(256 * PyInt_AsLong(PyTuple_GetItem(cobj, 1)));
360          b = (int)(256 * PyInt_AsLong(PyTuple_GetItem(cobj, 2)));
361       }
362       else {
363          PyErr_SetString(PyExc_TypeError, "tuple components must be integer or float");
364          return -1;
365       }
366       ccolor = rgb_alloccolor(r, g, b);
367    }
368    else if (PyString_Check(cobj)) {  /* color name */
369       ccolor = xc_alloccolor(PyString_AsString(cobj));
370    }
371    else if (PyInt_Check(cobj)) {  /* index (for backward compatibility) */
372       ccolor = (int)PyInt_AsLong(cobj);
373    }
374    else {
375       PyErr_SetString(PyExc_TypeError, "argument must be a string or 3-tuple");
376       return -1;
377    }
378 
379    addnewcolorentry(ccolor);
380    return ccolor;
381 }
382 
383 /*--------------------------------------------------------------*/
384 /* Convert a Python list to a stringpart* 			*/
385 /*--------------------------------------------------------------*/
386 
PySetStringParts(PyObject * dval)387 stringpart *PySetStringParts(PyObject *dval)
388 {
389    PyObject *lstr, *litem, *ditem, *sitem, *titem;
390    int i, j, llen;
391    stringpart *strptr, *newpart;
392    char *string;
393 
394    /* If we pass a string, create a list of size 1 to hold the string.	*/
395    /* Otherwise, the argument must be a list.				*/
396 
397    if (PyList_Check(dval)) {
398       lstr = dval;
399    }
400    else {
401       if (PyString_Check(dval)) {
402          lstr = PyList_New(1);
403 	 PyList_SetItem(lstr, 0, dval);
404       }
405       else {
406          PyErr_SetString(PyExc_TypeError, "argument must be a string or a list");
407 	 return NULL;
408       }
409    }
410 
411    strptr = NULL;
412    llen = PyList_Size(lstr);
413    for (i = 0; i < llen; i++) {
414       newpart = makesegment(&strptr, NULL);
415       newpart->nextpart = NULL;
416 
417       litem = PyList_GetItem(lstr, i);
418       if (PyDict_Check(litem)) {
419 	 if ((ditem = PyDict_GetItemString(litem, "Parameter")) != NULL) {
420 	    newpart->type = PARAM_START;
421 	    newpart->data.string = strdup(PyString_AsString(ditem));
422 	 }
423 	 else if ((ditem = PyDict_GetItemString(litem, "Font")) != NULL) {
424 	    newpart->type = FONT_NAME;
425 	    string = PyString_AsString(ditem);
426 	    for (j = 0; j < fontcount; j++)
427 	       if (!strcmp(fonts[j].psname, string)) break;
428 	    if (j == fontcount) loadfontfile(string);
429 	    newpart->data.font = j;
430 	 }
431 	 else if ((ditem = PyDict_GetItemString(litem, "Kern")) != NULL) {
432 	    newpart->type = KERN;
433 	    newpart->data.kern[0] = (int)PyInt_AsLong(PyTuple_GetItem(ditem, 0));
434 	    newpart->data.kern[1] = (int)PyInt_AsLong(PyTuple_GetItem(ditem, 1));
435 	 }
436 	 else if ((ditem = PyDict_GetItemString(litem, "Color")) != NULL) {
437 	    newpart->type = FONT_COLOR;
438 	    newpart->data.color = PyRGBToIndex(ditem);
439 	 }
440 	 else if ((ditem = PyDict_GetItemString(litem, "Font Scale")) != NULL) {
441 	    newpart->type = FONT_SCALE;
442 	    newpart->data.scale = (float)PyFloat_AsDouble(ditem);
443 	 }
444 	 else if ((ditem = PyDict_GetItemString(litem, "Text")) != NULL) {
445 	    newpart->type = TEXT_STRING;
446 	    newpart->data.string = strdup(PyString_AsString(ditem));
447 	 }
448       }
449       else if (PyString_Check(litem)) {
450 	 string = PyString_AsString(litem);
451 	 if (!strcmp(string, "End Parameter")) {
452 	    newpart->type = PARAM_END;
453 	    newpart->data.string = (u_char *)NULL;
454 	 }
455 	 else if (!strcmp(string, "Tab Stop")) {
456 	    newpart->type = TABSTOP;
457 	 }
458 	 else if (!strcmp(string, "Tab Forward")) {
459 	    newpart->type = TABFORWARD;
460 	 }
461 	 else if (!strcmp(string, "Tab Backward")) {
462 	    newpart->type = TABBACKWARD;
463 	 }
464 	 else if (!strcmp(string, "Return")) {
465 	    newpart->type = RETURN;
466 	 }
467 	 else if (!strcmp(string, "Subscript")) {
468 	    newpart->type = SUBSCRIPT;
469 	 }
470 	 else if (!strcmp(string, "Superscript")) {
471 	    newpart->type = SUPERSCRIPT;
472 	 }
473 	 else if (!strcmp(string, "Normalscript")) {
474 	    newpart->type = NORMALSCRIPT;
475 	 }
476 	 else if (!strcmp(string, "Underline")) {
477 	    newpart->type = UNDERLINE;
478 	 }
479 	 else if (!strcmp(string, "Overline")) {
480 	    newpart->type = OVERLINE;
481 	 }
482 	 else if (!strcmp(string, "No Line")) {
483 	    newpart->type = NOLINE;
484 	 }
485 	 else if (!strcmp(string, "Half Space")) {
486 	    newpart->type = HALFSPACE;
487 	 }
488 	 else if (!strcmp(string, "Quarter Space")) {
489 	    newpart->type = QTRSPACE;
490 	 }
491 	 else {
492 	    newpart->type = TEXT_STRING;
493 	    newpart->data.string = strdup(string);
494 	 }
495       }
496    }
497    return strptr;
498 }
499 
500 /*--------------------------------------------------------------*/
501 /* Convert a stringpart* to a Python list 			*/
502 /*--------------------------------------------------------------*/
503 
PyGetStringParts(stringpart * thisstring)504 PyObject *PyGetStringParts(stringpart *thisstring)
505 {
506    PyObject *lstr, *sdict, *stup;
507    int i, llen;
508    stringpart *strptr;
509 
510    llen = stringparts(thisstring);
511    lstr = PyList_New(llen);
512    for (strptr = thisstring, i = 0; strptr != NULL;
513       strptr = strptr->nextpart, i++) {
514       switch(strptr->type) {
515 	 case TEXT_STRING:
516 	    sdict = PyDict_New();
517 	    PyDict_SetItem(sdict, PyString_FromString("Text"),
518 		  PyString_FromString(strptr->data.string));
519 	    PyList_SetItem(lstr, i, sdict);
520 	    break;
521 	 case PARAM_START:
522 	    sdict = PyDict_New();
523 	    PyDict_SetItem(sdict, PyString_FromString("Parameter"),
524 		  PyString_FromString(strptr->data.string));
525 	    PyList_SetItem(lstr, i, sdict);
526 	    break;
527 	 case PARAM_END:
528 	    PyList_SetItem(lstr, i, PyString_FromString("End Parameter"));
529 	    break;
530 	 case FONT_NAME:
531 	    sdict = PyDict_New();
532 	    PyDict_SetItem(sdict, PyString_FromString("Font"),
533 		  PyString_FromString(fonts[strptr->data.font].psname));
534 	    PyList_SetItem(lstr, i, sdict);
535 	    break;
536 	 case FONT_SCALE:
537 	    sdict = PyDict_New();
538 	    PyDict_SetItem(sdict, PyString_FromString("Font Scale"),
539 		  PyFloat_FromDouble((double)strptr->data.scale));
540 	    PyList_SetItem(lstr, i, sdict);
541 	    break;
542 	 case KERN:
543 	    sdict = PyDict_New();
544 	    stup = PyTuple_New(2);
545 	    PyTuple_SetItem(stup, 0, PyInt_FromLong((long)strptr->data.kern[0]));
546 	    PyTuple_SetItem(stup, 1, PyInt_FromLong((long)strptr->data.kern[1]));
547 	    PyDict_SetItem(sdict, PyString_FromString("Kern"), stup);
548 	    PyList_SetItem(lstr, i, sdict);
549 	    break;
550 	 case FONT_COLOR:
551 	    stup = PyIndexToRGB(strptr->data.color);
552 	    if (stup != NULL) {
553 	       sdict = PyDict_New();
554 	       PyDict_SetItem(sdict, PyString_FromString("Color"), stup);
555 	       PyList_SetItem(lstr, i, sdict);
556 	    }
557 	    break;
558 	 case TABSTOP:
559 	    PyList_SetItem(lstr, i, PyString_FromString("Tab Stop"));
560 	    break;
561 	 case TABFORWARD:
562 	    PyList_SetItem(lstr, i, PyString_FromString("Tab Forward"));
563 	    break;
564 	 case TABBACKWARD:
565 	    PyList_SetItem(lstr, i, PyString_FromString("Tab Backward"));
566 	    break;
567 	 case RETURN:
568 	    PyList_SetItem(lstr, i, PyString_FromString("Return"));
569 	    break;
570 	 case SUBSCRIPT:
571 	    PyList_SetItem(lstr, i, PyString_FromString("Subscript"));
572 	    break;
573 	 case SUPERSCRIPT:
574 	    PyList_SetItem(lstr, i, PyString_FromString("Superscript"));
575 	    break;
576 	 case NORMALSCRIPT:
577 	    PyList_SetItem(lstr, i, PyString_FromString("Normalscript"));
578 	    break;
579 	 case UNDERLINE:
580 	    PyList_SetItem(lstr, i, PyString_FromString("Underline"));
581 	    break;
582 	 case OVERLINE:
583 	    PyList_SetItem(lstr, i, PyString_FromString("Overline"));
584 	    break;
585 	 case NOLINE:
586 	    PyList_SetItem(lstr, i, PyString_FromString("No Line"));
587 	    break;
588 	 case HALFSPACE:
589 	    PyList_SetItem(lstr, i, PyString_FromString("Half Space"));
590 	    break;
591 	 case QTRSPACE:
592 	    PyList_SetItem(lstr, i, PyString_FromString("Quarter Space"));
593 	    break;
594       }
595    }
596    return lstr;
597 }
598 
599 /*--------------------------------------------------------------*/
600 /* Check if the handle (integer) is an existing element		*/
601 /*--------------------------------------------------------------*/
602 
CheckHandle(PyObject * ehandle)603 genericptr *CheckHandle(PyObject *ehandle)
604 {
605    genericptr *gelem;
606    int i, j;
607    long int eaddr;
608    objectptr thisobj;
609    Library *thislib;
610 
611    eaddr = PyInt_AsLong(ehandle);
612    for (gelem = topobject->plist; gelem < topobject->plist +
613 	topobject->parts; gelem++)
614       if ((long int)(*gelem) == eaddr) goto exists;
615 
616    /* Okay, it isn't in topobject.  Try all other pages. */
617 
618    for (i = 0; i < xobjs.pages; i++) {
619       if (xobjs.pagelist[i]->pageinst == NULL) continue;
620       thisobj = xobjs.pagelist[i]->pageinst->thisobject;
621       for (gelem = thisobj->plist; gelem < thisobj->plist + thisobj->parts; gelem++)
622          if ((long int)(*gelem) == eaddr) goto exists;
623    }
624 
625    /* Still not found?  Maybe in a library */
626 
627    for (i = 0; i < xobjs.numlibs; i++) {
628       thislib = xobjs.userlibs + i;
629       for (j = 0; j < thislib->number; j++) {
630          thisobj = thislib->library[j];
631          for (gelem = thisobj->plist; gelem < thisobj->plist + thisobj->parts; gelem++)
632             if ((long int)(*gelem) == eaddr) goto exists;
633       }
634    }
635 
636    /* Either in the delete list (where we don't want to go) or	*/
637    /* is an invalid number.					*/
638    return NULL;
639 
640 exists:
641    return gelem;
642 }
643 
644 /*--------------------------------------------------------------*/
645 /* Check if the handle (integer) is an existing page		*/
646 /*--------------------------------------------------------------*/
647 
CheckPageHandle(PyObject * ehandle)648 objectptr CheckPageHandle(PyObject *ehandle)
649 {
650    int pageno;
651    long int eaddr;
652 
653    eaddr = PyInt_AsLong(ehandle);
654    pageno = is_page((objectptr)eaddr);
655    if (pageno < 0) return NULL;
656    return (objectptr)eaddr;
657 }
658 
659 /*--------------------------------------------------------------*/
660 /* Form a 2-tuple from a pair of integers.			*/
661 /*--------------------------------------------------------------*/
662 
make_pair(XPoint * thispoint)663 static PyObject *make_pair(XPoint *thispoint)
664 {
665    PyObject *dtup;
666 
667    dtup = PyTuple_New(2);
668 
669    PyTuple_SetItem(dtup, 0,
670 		PyInt_FromLong((long)(thispoint->x)));
671    PyTuple_SetItem(dtup, 1,
672 		PyInt_FromLong((long)(thispoint->y)));
673    return dtup;
674 }
675 
676 /*--------------------------------------------------------------*/
677 /* Get the properties of a page (returned as a dictionary)	*/
678 /*--------------------------------------------------------------*/
679 
xc_getpage(PyObject * self,PyObject * args)680 static PyObject *xc_getpage(PyObject *self, PyObject *args)
681 {
682    Pagedata *thispage;
683    PyObject *rdict, *dlist;
684    int pageno = areawin->page + 1, i;
685 
686    if (!PyArg_ParseTuple(args, "|d:getpage", &pageno))
687       return NULL;
688 
689    if (pageno <= 0 || pageno > xobjs.pages) return NULL;
690    else pageno--;
691 
692    thispage = xobjs.pagelist[pageno];
693 
694    rdict = PyDict_New();
695 
696    PyDict_SetItem(rdict, PyString_FromString("filename"),
697 	PyString_FromString(thispage->filename));
698 
699    PyDict_SetItem(rdict, PyString_FromString("page label"),
700 	PyString_FromString(thispage->pageinst->thisobject->name));
701 
702    PyDict_SetItem(rdict, PyString_FromString("output scale"),
703 	PyFloat_FromDouble((double)thispage->outscale));
704 
705    /* To be done:  change these from internal units to "natural" units */
706 
707    PyDict_SetItem(rdict, PyString_FromString("grid space"),
708 	PyFloat_FromDouble((double)thispage->gridspace));
709 
710    PyDict_SetItem(rdict, PyString_FromString("snap space"),
711 	PyFloat_FromDouble((double)thispage->snapspace));
712 
713    PyDict_SetItem(rdict, PyString_FromString("orientation"),
714 	PyInt_FromLong((long)thispage->orient));
715 
716    PyDict_SetItem(rdict, PyString_FromString("output mode"),
717 	PyInt_FromLong((long)thispage->pmode));
718 
719    PyDict_SetItem(rdict, PyString_FromString("coordinate style"),
720 	PyInt_FromLong((long)thispage->coordstyle));
721 
722    PyDict_SetItem(rdict, PyString_FromString("page size"),
723 	make_pair(&(thispage->pagesize)));
724 
725    PyDict_SetItem(rdict, PyString_FromString("drawing scale"),
726 	make_pair(&(thispage->drawingscale)));
727 
728    return rdict;
729 }
730 
731 /*--------------------------------------------------------------*/
732 /* Get the properties of a library (returned as a dictionary)	*/
733 /*--------------------------------------------------------------*/
734 
xc_getlibrary(PyObject * self,PyObject * args)735 static PyObject *xc_getlibrary(PyObject *self, PyObject *args)
736 {
737    PyObject *rdict, *dlist;
738    const char *lname = NULL;
739    objectptr *curlib = NULL, thisobj;
740    char *errptr;
741    int i, lpage;
742    int curobjs;
743 
744    if (!PyArg_ParseTuple(args, "s:getlibrary", &lname))
745       return NULL;
746 
747    lpage = strtol(lname, &errptr, 10);
748    if (*lname != '\0' && *errptr == '\0' && lpage <= xobjs.numlibs &&
749 		lpage > 0) {	/* numerical */
750       curlib = xobjs.userlibs[lpage - 1].library;
751    }
752    else {
753       for (lpage = 0; lpage < xobjs.numlibs; lpage++) {
754 	 if (!strcmp(lname, xobjs.libtop[lpage + LIBRARY]->thisobject->name)) {
755 	    curlib = xobjs.userlibs[lpage - 1].library;
756 	    break;
757 	 }
758 	 else if (!strncmp(xobjs.libtop[lpage + LIBRARY]->thisobject->name,
759 			"Library: ", 9)) {
760 	    if (!strcmp(lname, xobjs.libtop[lpage + LIBRARY]->thisobject->name + 9)) {
761 	       curlib = xobjs.userlibs[lpage - 1].library;
762 	       break;
763 	    }
764 	 }
765       }
766    }
767 
768    if (curlib == NULL) {
769       PyErr_SetString(PyExc_TypeError,
770 		"getlibrary() 2nd argument must be a library page or name");
771       return NULL;
772    }
773    curobjs = xobjs.userlibs[lpage - 1].number;
774 
775    /* Argument to getlibrary() can be a library name or library page # */
776 
777    rdict = PyDict_New();
778 
779    PyDict_SetItem(rdict, PyString_FromString("name"),
780 	PyString_FromString(xobjs.libtop[lpage + LIBRARY]->thisobject->name));
781 
782    if (curobjs > 0) {
783       dlist = PyList_New(curobjs);
784       for (i = 0; i < curobjs; i++) {
785 	 thisobj = *(curlib + i);
786          PyList_SetItem(dlist, i, PyString_FromString(thisobj->name));
787       }
788       PyDict_SetItem(rdict, PyString_FromString("objects"), dlist);
789    }
790    return rdict;
791 }
792 
793 /*--------------------------------------------------------------*/
794 /* Get the properties of an object (returned as a dictionary)	*/
795 /*--------------------------------------------------------------*/
796 
xc_getobject(PyObject * self,PyObject * args)797 static PyObject *xc_getobject(PyObject *self, PyObject *args)
798 {
799    objectptr thisobj = NULL, *libobj;
800    oparamptr ops;
801    PyObject *rdict, *dlist, *tpos;
802    const char *oname;
803    int i, j, k, nparam;
804 
805    if (!PyArg_ParseTuple(args, "s:getobject", &oname))
806       return NULL;
807 
808    for (k = 0; k < xobjs.numlibs; k++) {
809       for (j = 0; j < xobjs.userlibs[k].number; j++) {
810 	 libobj = xobjs.userlibs[k].library + j;
811 	 if (!strcmp(oname, (*libobj)->name)) {
812 	    thisobj = *libobj;
813 	    break;
814 	 }
815       }
816       if (thisobj != NULL) break;
817    }
818 
819    if (thisobj == NULL) { 	/* try the page objects */
820       for (k = 0; k < xobjs.pages; k++) {
821 	 if (xobjs.pagelist[k]->pageinst != NULL)
822 	    if (!strcmp(oname, xobjs.pagelist[k]->pageinst->thisobject->name))
823 	       break;
824       }
825       if (k == xobjs.pages) return NULL;	/* not found */
826    }
827 
828    /* return all the object's properties as a dictionary */
829 
830    rdict = PyDict_New();
831 
832    PyDict_SetItem(rdict, PyString_FromString("name"),
833 	PyString_FromString(thisobj->name));
834    PyDict_SetItem(rdict, PyString_FromString("width"),
835 	PyInt_FromLong((long)(thisobj->bbox.width)));
836    PyDict_SetItem(rdict, PyString_FromString("height"),
837 	PyInt_FromLong((long)(thisobj->bbox.height)));
838    PyDict_SetItem(rdict, PyString_FromString("viewscale"),
839 	PyFloat_FromDouble((double)(thisobj->viewscale)));
840 
841    tpos = PyTuple_New(2);
842    PyTuple_SetItem(tpos, 0, PyInt_FromLong((long)thisobj->bbox.lowerleft.x));
843    PyTuple_SetItem(tpos, 1, PyInt_FromLong((long)thisobj->bbox.lowerleft.y));
844    PyDict_SetItem(rdict, PyString_FromString("boundingbox"), tpos);
845 
846    tpos = PyTuple_New(2);
847    PyTuple_SetItem(tpos, 0, PyInt_FromLong((long)thisobj->pcorner.x));
848    PyTuple_SetItem(tpos, 1, PyInt_FromLong((long)thisobj->pcorner.y));
849    PyDict_SetItem(rdict, PyString_FromString("viewcorner"), tpos);
850 
851    dlist = PyList_New(thisobj->parts);
852    for (i = 0; i < thisobj->parts; i++)
853       PyList_SetItem(dlist, i, PyInt_FromLong((long)(*(thisobj->plist + i))));
854    PyDict_SetItem(rdict, PyString_FromString("parts"), dlist);
855 
856    nparam = get_num_params(thisobj);
857    if (nparam > 0) {
858       dlist = PyList_New(nparam);
859       i = 0;
860       for (ops = thisobj->params; ops != NULL; ops = ops->next) {
861 	 i++;
862 	 if (ops->type == XC_INT)
863             PyList_SetItem(dlist, i, PyInt_FromLong((long)(ops->parameter.ivalue)));
864 	 else if (ops->type == XC_FLOAT)
865             PyList_SetItem(dlist, i,
866 		PyFloat_FromDouble((double)(ops->parameter.fvalue)));
867 	 else if (ops->type == XC_STRING)
868             PyList_SetItem(dlist, i, PyGetStringParts(ops->parameter.string));
869       }
870       PyDict_SetItem(rdict, PyString_FromString("parameters"), dlist);
871    }
872    return rdict;
873 }
874 
875 /*--------------------------------------------------------------*/
876 /* Reset the current page					*/
877 /*--------------------------------------------------------------*/
878 
xc_reset()879 static PyObject *xc_reset()
880 {
881    resetbutton(NULL, (pointertype)0, NULL);
882    return PyInt_FromLong(0L);
883 }
884 
885 /*--------------------------------------------------------------*/
886 /* Get a netlist						*/
887 /*--------------------------------------------------------------*/
888 
889 extern PyObject *pyglobals(objectptr);
890 extern PyObject *pytoplevel(objectptr);
891 
xc_netlist()892 static PyObject *xc_netlist()
893 {
894    PyObject *rdict = NULL;
895 
896    if (updatenets(areawin->topinstance, FALSE) <= 0) {
897       PyErr_SetString(PyExc_TypeError, "Error:  Check circuit for infinite recursion.");
898       return NULL;
899    }
900 
901    rdict = PyDict_New();
902    PyDict_SetItem(rdict, PyString_FromString("globals"), pyglobals(topobject));
903    PyDict_SetItem(rdict, PyString_FromString("circuit"), pytoplevel(topobject));
904    return rdict;
905 }
906 
907 /*--------------------------------------------------------------*/
908 /* Load the specified file					*/
909 /*--------------------------------------------------------------*/
910 
xc_load(PyObject * self,PyObject * args)911 static PyObject *xc_load(PyObject *self, PyObject *args)
912 {
913    char *filename;
914    int pageno = 0, savepage;
915 
916    if (!PyArg_ParseTuple(args, "s|i:load", &filename, &pageno))
917       return PyInt_FromLong((long)areawin->page);
918 
919    if (--pageno < 0) pageno = areawin->page;
920    savepage = areawin->page;
921 
922    strcpy(_STR2, filename);
923    if (savepage != pageno) newpage(pageno);
924    startloadfile(-1);
925    if (savepage != pageno) newpage(savepage);
926 
927    return PyString_FromString(filename);
928 }
929 
930 /*--------------------------------------------------------------*/
931 /* Go to the specified page					*/
932 /*--------------------------------------------------------------*/
933 
xc_page(PyObject * self,PyObject * args)934 static PyObject *xc_page(PyObject *self, PyObject *args)
935 {
936    int pageno;
937 
938    if (!PyArg_ParseTuple(args, "i:page", &pageno))
939       return PyInt_FromLong((long)areawin->page);
940 
941    newpage(pageno - 1);
942    return PyInt_FromLong((long)pageno);
943 }
944 
945 /*--------------------------------------------------------------*/
946 /* Zoom								*/
947 /*--------------------------------------------------------------*/
948 
xc_zoom(PyObject * self,PyObject * args)949 static PyObject *xc_zoom(PyObject *self, PyObject *args)
950 {
951    float factor, save;
952 
953    if (!PyArg_ParseTuple(args, "f:zoom", &factor))
954       return NULL;
955 
956    if (factor <= 0) {
957       PyErr_SetString(PyExc_TypeError, "Argument must be positive.");
958       return NULL;
959    }
960 
961    save = areawin->zoomfactor;
962 
963    if (factor < 1.0) {
964       areawin->zoomfactor = 1.0 / factor;
965       zoomout(0, 0);	/* Needs to be fixed---give x, y for drag fn */
966    }
967    else {
968       areawin->zoomfactor = factor;
969       zoomin(0, 0);	/* Needs to be fixed---see above */
970    }
971 
972    areawin->zoomfactor = save;
973    return PyFloat_FromDouble((double)topobject->viewscale);
974 }
975 
976 /*--------------------------------------------------------------*/
977 /* Pan								*/
978 /*--------------------------------------------------------------*/
979 
xc_pan(PyObject * self,PyObject * args)980 static PyObject *xc_pan(PyObject *self, PyObject *args)
981 {
982    PyObject *cornerpos, *xobj, *yobj = NULL, *pval;
983    int x, y;
984    XPoint upoint, wpoint;
985 
986    if (!PyArg_ParseTuple(args, "O|O:pan", &xobj, &yobj))
987       return NULL;
988 
989    if (yobj == NULL) {
990       if (PyTuple_Check(xobj) && PyTuple_Size(xobj) == 2) {
991          if ((pval = PyTuple_GetItem(xobj, 0)) != NULL)
992             upoint.x = PyInt_AsLong(pval);
993          if ((pval = PyTuple_GetItem(xobj, 1)) != NULL)
994             upoint.y = PyInt_AsLong(pval);
995       }
996       else return NULL;
997    }
998    else {
999       upoint.x = PyInt_AsLong(xobj);
1000       upoint.y = PyInt_AsLong(yobj);
1001    }
1002 
1003    user_to_window(upoint, &wpoint);
1004    panbutton((u_int)5, wpoint.x, wpoint.y, 0.33);  /* fixed fraction */
1005 
1006    cornerpos = PyTuple_New(2);
1007    PyTuple_SetItem(cornerpos, 0, PyInt_FromLong((long)areawin->pcorner.x));
1008    PyTuple_SetItem(cornerpos, 1, PyInt_FromLong((long)areawin->pcorner.y));
1009 
1010    return cornerpos;
1011 }
1012 
1013 /*--------------------------------------------------------------*/
1014 /* Get the window size						*/
1015 /*--------------------------------------------------------------*/
1016 
xc_getwindow()1017 static PyObject *xc_getwindow()
1018 {
1019    PyObject *windowsize;
1020 
1021    windowsize = PyTuple_New(2);
1022    PyTuple_SetItem(windowsize, 0, PyInt_FromLong((long)areawin->width));
1023    PyTuple_SetItem(windowsize, 1, PyInt_FromLong((long)areawin->height));
1024 
1025    return windowsize;
1026 }
1027 
1028 /*--------------------------------------------------------------*/
1029 /* Get the cursor position					*/
1030 /*--------------------------------------------------------------*/
1031 
xc_getcursor()1032 static PyObject *xc_getcursor()
1033 {
1034    PyObject *cursorpos;
1035    XPoint newpos;
1036 
1037    newpos = UGetCursorPos();
1038    u2u_snap(&newpos);
1039 
1040    cursorpos = PyTuple_New(2);
1041    PyTuple_SetItem(cursorpos, 0, PyInt_FromLong((long)newpos.x));
1042    PyTuple_SetItem(cursorpos, 1, PyInt_FromLong((long)newpos.y));
1043 
1044    return cursorpos;
1045 }
1046 
1047 /*--------------------------------------------------------------*/
1048 /* Get the properties of an element (returned as a dictionary)	*/
1049 /*--------------------------------------------------------------*/
1050 
xc_getattr(PyObject * self,PyObject * args)1051 static PyObject *xc_getattr(PyObject *self, PyObject *args)
1052 {
1053    genericptr *gelem;
1054    PyObject *ehandle, *rdict, *dlist, *lstr, *sdict, *stup;
1055    int i, llen;
1056    char *tstr;
1057    stringpart *strptr;
1058 
1059 
1060    if (!PyArg_ParseTuple(args, "O:getattr", &ehandle))
1061       return NULL;
1062 
1063    /* Check to make sure that handle exists! */
1064    if ((gelem = CheckHandle(ehandle)) == NULL) {
1065       PyErr_SetString(PyExc_TypeError,
1066 		"Argument must be a valid handle to an element.");
1067       return NULL;
1068    }
1069 
1070    /* return the element's properties as a dictionary	*/
1071 
1072    rdict = PyDict_New();
1073    tstr = type_to_string((*gelem)->type);
1074    if (tstr == NULL) {
1075       PyErr_SetString(PyExc_TypeError,
1076 		"Element type is unknown.");
1077       return NULL;
1078    }
1079    PyDict_SetItem(rdict, PyString_FromString("type"),
1080         PyString_FromString(tstr));
1081    free(tstr);
1082    lstr = PyIndexToRGB((*gelem)->color);
1083    if (lstr != NULL)
1084       PyDict_SetItem(rdict, PyString_FromString("color"), lstr);
1085 
1086    switch(ELEMENTTYPE(*gelem)) {
1087       case LABEL:
1088 	 PyDict_SetItem(rdict, PyString_FromString("position"),
1089 		make_pair(&(TOLABEL(gelem)->position)));
1090 	 PyDict_SetItem(rdict, PyString_FromString("rotation"),
1091 		PyFloat_FromDouble((double)TOLABEL(gelem)->rotation));
1092 	 PyDict_SetItem(rdict, PyString_FromString("scale"),
1093 		PyFloat_FromDouble((double)TOLABEL(gelem)->scale));
1094 	 PyDict_SetItem(rdict, PyString_FromString("anchor"),
1095 		PyInt_FromLong((long)TOLABEL(gelem)->anchor));
1096 	 PyDict_SetItem(rdict, PyString_FromString("pin"),
1097 		PyInt_FromLong((long)TOLABEL(gelem)->pin));
1098 	 lstr = PyGetStringParts(TOLABEL(gelem)->string);
1099 
1100 	 PyDict_SetItem(rdict, PyString_FromString("string"), lstr);
1101 	 break;
1102       case POLYGON:
1103 	 PyDict_SetItem(rdict, PyString_FromString("style"),
1104 		PyInt_FromLong((long)TOPOLY(gelem)->style));
1105 	 PyDict_SetItem(rdict, PyString_FromString("linewidth"),
1106 		PyFloat_FromDouble((double)TOPOLY(gelem)->width));
1107 	 dlist = PyList_New(TOPOLY(gelem)->number);
1108 	 for (i = 0; i < TOPOLY(gelem)->number; i++) {
1109 	    PyList_SetItem(dlist, i, make_pair(&(TOPOLY(gelem)->points[i])));
1110 	 }
1111 	 PyDict_SetItem(rdict, PyString_FromString("points"), dlist);
1112 	 break;
1113       case ARC:
1114 	 PyDict_SetItem(rdict, PyString_FromString("style"),
1115 		PyInt_FromLong((long)TOARC(gelem)->style));
1116 	 PyDict_SetItem(rdict, PyString_FromString("linewidth"),
1117 		PyFloat_FromDouble((double)TOARC(gelem)->width));
1118 	 PyDict_SetItem(rdict, PyString_FromString("radius"),
1119 		PyInt_FromLong((long)TOARC(gelem)->radius));
1120 	 PyDict_SetItem(rdict, PyString_FromString("minor axis"),
1121 		PyInt_FromLong((long)TOARC(gelem)->yaxis));
1122 	 PyDict_SetItem(rdict, PyString_FromString("start angle"),
1123 		PyFloat_FromDouble((double)TOARC(gelem)->angle1));
1124 	 PyDict_SetItem(rdict, PyString_FromString("end angle"),
1125 		PyFloat_FromDouble((double)TOARC(gelem)->angle2));
1126 	 PyDict_SetItem(rdict, PyString_FromString("position"),
1127 		make_pair(&(TOARC(gelem)->position)));
1128 	 break;
1129       case SPLINE:
1130 	 PyDict_SetItem(rdict, PyString_FromString("style"),
1131 		PyInt_FromLong((long)TOSPLINE(gelem)->style));
1132 	 PyDict_SetItem(rdict, PyString_FromString("linewidth"),
1133 		PyFloat_FromDouble((double)TOSPLINE(gelem)->width));
1134 	 dlist = PyList_New(4);
1135 	 for (i = 0; i < 4; i++) {
1136 	    PyList_SetItem(dlist, i, make_pair(&(TOSPLINE(gelem)->ctrl[i])));
1137 	 }
1138 	 PyDict_SetItem(rdict, PyString_FromString("control points"), dlist);
1139 	 break;
1140       case PATH:
1141 	 PyDict_SetItem(rdict, PyString_FromString("style"),
1142 		PyInt_FromLong((long)TOPATH(gelem)->style));
1143 	 PyDict_SetItem(rdict, PyString_FromString("linewidth"),
1144 		PyFloat_FromDouble((double)TOPATH(gelem)->width));
1145 	 dlist = PyList_New(TOPATH(gelem)->parts);
1146 	 for (i = 0; i < TOPATH(gelem)->parts; i++) {
1147 	    PyList_SetItem(dlist, i,
1148 		PyInt_FromLong((long)(*(TOPATH(gelem)->plist + i))));
1149 	 }
1150 	 PyDict_SetItem(rdict, PyString_FromString("parts"), dlist);
1151 	 break;
1152       case OBJINST:
1153 	 PyDict_SetItem(rdict, PyString_FromString("position"),
1154 		make_pair(&(TOOBJINST(gelem)->position)));
1155 	 PyDict_SetItem(rdict, PyString_FromString("rotation"),
1156 		PyFloat_FromDouble((double)TOOBJINST(gelem)->rotation));
1157 	 PyDict_SetItem(rdict, PyString_FromString("scale"),
1158 		PyFloat_FromDouble((double)TOOBJINST(gelem)->scale));
1159 	 PyDict_SetItem(rdict, PyString_FromString("name"),
1160 		PyString_FromString(TOOBJINST(gelem)->thisobject->name));
1161 	 break;
1162    }
1163    return rdict;
1164 }
1165 
1166 /*--------------------------------------------------------------*/
1167 /* Set properties of an element (supplied as a dictionary)	*/
1168 /*--------------------------------------------------------------*/
1169 
xc_setattr(PyObject * self,PyObject * args)1170 static PyObject *xc_setattr(PyObject *self, PyObject *args)
1171 {
1172    genericptr *gelem;
1173    PyObject *ehandle, *attrdict, *dval, *pval, *qval;
1174    int i;
1175 
1176    if (!PyArg_ParseTuple(args, "OO:setattr", &ehandle, &attrdict))
1177       return NULL;
1178 
1179    /* Check to make sure that handle exists! */
1180    if ((gelem = CheckHandle(ehandle)) == NULL) return NULL;
1181 
1182    /* Is the argument a dictionary? */
1183    if (!PyDict_Check(attrdict)) {
1184       PyErr_SetString(PyExc_TypeError,
1185 		"setatrr() 2nd argument must be a dictionary");
1186       return NULL;
1187    }
1188 
1189    /* First, make sure no attempt is made to change the object type. */
1190 
1191    if ((dval = PyDict_GetItemString(attrdict, "type")) != NULL) {
1192       int dtype = string_to_type(PyString_AsString(dval));
1193       if (dtype < 0) return NULL;
1194       if (dtype != ELEMENTTYPE(*gelem)) {
1195          PyErr_SetString(PyExc_TypeError,
1196 		"Attempt to change the type of an object.");
1197          return NULL;
1198       }
1199    }
1200 
1201    /* Next, look for dictionary strings containing values which apply */
1202    /* to a number of different elements (position, color, etc.)	      */
1203 
1204    if ((dval = PyDict_GetItemString(attrdict, "color")) != NULL) {
1205       (*gelem)->color = (short)PyRGBToIndex(dval);
1206    }
1207 
1208    if ((dval = PyDict_GetItemString(attrdict, "position")) != NULL) {
1209       if (PyTuple_Check(dval) && PyTuple_Size(dval) == 2) {
1210          if ((pval = PyTuple_GetItem(dval, 0)) != NULL) {
1211             short xpos = (short)PyInt_AsLong(pval);
1212             switch(ELEMENTTYPE(*gelem)) {
1213 	       case ARC:
1214 	          TOARC(gelem)->position.x = xpos;
1215 	          calcarc(TOARC(gelem));
1216 	          break;
1217 	       case LABEL:
1218 	          TOLABEL(gelem)->position.x = xpos;
1219 	          break;
1220 	       case OBJINST:
1221 	          TOOBJINST(gelem)->position.x = xpos;
1222 	          break;
1223                default:
1224 	          PyErr_SetString(PyExc_TypeError,
1225 		      "attempt to set position on Spline, Polygon, or Path");
1226 	    }
1227          }
1228 
1229          if ((pval = PyTuple_GetItem(dval, 1)) != NULL) {
1230             short ypos = (short)PyInt_AsLong(pval);
1231             switch(ELEMENTTYPE(*gelem)) {
1232 	       case ARC:
1233 	          TOARC(gelem)->position.y = ypos;
1234 	          calcarc(TOARC(gelem));
1235 	          break;
1236 	       case LABEL:
1237 	          TOLABEL(gelem)->position.y = ypos;
1238 	          break;
1239 	       case OBJINST:
1240 	          TOOBJINST(gelem)->position.y = ypos;
1241 	          break;
1242                default:
1243 	          PyErr_SetString(PyExc_TypeError,
1244 		      "attempt to set position on Spline, Polygon, or Path");
1245 	    }
1246          }
1247       }
1248       else {
1249          PyErr_SetString(PyExc_TypeError,
1250 		"position must be a tuple containing two integer values");
1251       }
1252    }
1253 
1254    if ((dval = PyDict_GetItemString(attrdict, "style")) != NULL) {
1255       short dstyle = (short)PyInt_AsLong(dval);
1256       switch(ELEMENTTYPE(*gelem)) {
1257          case POLYGON:
1258 	    TOPOLY(gelem)->style = dstyle;
1259 	    break;
1260          case PATH:
1261 	    TOPATH(gelem)->style = dstyle;
1262 	    break;
1263          case ARC:
1264 	    TOARC(gelem)->style = dstyle;
1265 	    break;
1266          case SPLINE:
1267 	    TOSPLINE(gelem)->style = dstyle;
1268 	    break;
1269          default:
1270             PyErr_SetString(PyExc_TypeError,
1271 		"attempt to set style on an Object Instance or Label");
1272       }
1273    }
1274 
1275    if ((dval = PyDict_GetItemString(attrdict, "linewidth")) != NULL) {
1276       float dwidth = (float)PyFloat_AsDouble(dval);
1277       switch(ELEMENTTYPE(*gelem)) {
1278          case POLYGON:
1279 	    TOPOLY(gelem)->width = dwidth;
1280 	    break;
1281          case PATH:
1282 	    TOPATH(gelem)->width = dwidth;
1283 	    break;
1284          case ARC:
1285 	    TOARC(gelem)->width = dwidth;
1286 	    break;
1287          case SPLINE:
1288 	    TOSPLINE(gelem)->width = dwidth;
1289 	    break;
1290          default:
1291             PyErr_SetString(PyExc_TypeError,
1292 		"attempt to set linewidth on an Object Instance or Label");
1293       }
1294    }
1295 
1296    if ((dval = PyDict_GetItemString(attrdict, "scale")) != NULL) {
1297       float dscale = (float)PyFloat_AsDouble(dval);
1298       switch(ELEMENTTYPE(*gelem)) {
1299          case LABEL:
1300 	    TOLABEL(gelem)->scale = dscale;
1301 	    break;
1302          case OBJINST:
1303 	    TOOBJINST(gelem)->scale = dscale;
1304 	    break;
1305          default:
1306             PyErr_SetString(PyExc_TypeError,
1307 		"attempt to set scale on something not a Label or Object Instance");
1308       }
1309    }
1310 
1311    if ((dval = PyDict_GetItemString(attrdict, "rotation")) != NULL) {
1312       float drot = (float)PyFloat_AsDouble(dval);
1313       switch(ELEMENTTYPE(*gelem)) {
1314          case LABEL:
1315 	    TOLABEL(gelem)->rotation = drot;
1316 	    break;
1317          case OBJINST:
1318 	    TOOBJINST(gelem)->rotation = drot;
1319 	    break;
1320          default:
1321             PyErr_SetString(PyExc_TypeError,
1322 		"attempt to set rotation on something not a Label or Object Instance");
1323       }
1324    }
1325 
1326    /* Dictionary entries specific to certain xcircuit types */
1327 
1328    switch(ELEMENTTYPE(*gelem)) {
1329       case LABEL:
1330 	 if ((dval = PyDict_GetItemString(attrdict, "anchor")) != NULL) {
1331 	    TOLABEL(gelem)->anchor = PyInt_AsLong(dval);
1332 	 }
1333 	 if ((dval = PyDict_GetItemString(attrdict, "string")) != NULL) {
1334 	    freelabel(TOLABEL(gelem)->string);
1335 	    TOLABEL(gelem)->string = PySetStringParts(dval);
1336 	 }
1337 	 if ((dval = PyDict_GetItemString(attrdict, "pin")) != NULL) {
1338 	    TOLABEL(gelem)->pin = PyInt_AsLong(dval);
1339 	 }
1340 	 break;
1341       case ARC:
1342 	 if ((dval = PyDict_GetItemString(attrdict, "start angle")) != NULL) {
1343 	    TOARC(gelem)->angle1 = (float)PyFloat_AsDouble(dval);
1344 	 }
1345 	 if ((dval = PyDict_GetItemString(attrdict, "end angle")) != NULL) {
1346 	    TOARC(gelem)->angle2 = (float)PyFloat_AsDouble(dval);
1347 	 }
1348 	 if ((dval = PyDict_GetItemString(attrdict, "radius")) != NULL) {
1349 	    TOARC(gelem)->radius = PyInt_AsLong(dval);
1350 	 }
1351 	 if ((dval = PyDict_GetItemString(attrdict, "minor axis")) != NULL) {
1352 	    TOARC(gelem)->yaxis = PyInt_AsLong(dval);
1353 	 }
1354 	 break;
1355       case SPLINE:
1356 	 if ((dval = PyDict_GetItemString(attrdict, "control points")) != NULL) {
1357             if (PyList_Check(dval) && PyList_Size(dval) == 4) {
1358 	       for (i = 0; i < 4; i++) {
1359 		  pval = PyList_GetItem(dval, i);
1360 		  if (PyTuple_Check(pval) && PyTuple_Size(pval) == 2) {
1361 		     qval = PyTuple_GetItem(pval, 0);
1362 		     TOSPLINE(gelem)->ctrl[i].x = (short)PyInt_AsLong(qval);
1363 		     qval = PyTuple_GetItem(pval, 1);
1364 		     TOSPLINE(gelem)->ctrl[i].y = (short)PyInt_AsLong(qval);
1365 		  }
1366 		  else {
1367                      PyErr_SetString(PyExc_TypeError,
1368 				"must have a tuple of 2 values per point");
1369 	             break;
1370 		  }
1371 	       }
1372 	    }
1373 	    else {
1374                PyErr_SetString(PyExc_TypeError,
1375 			"must have 4 control points in a list");
1376 	       break;
1377 	    }
1378 	 }
1379 	 break;
1380       case POLYGON:
1381 	 if ((dval = PyDict_GetItemString(attrdict, "points")) != NULL) {
1382             if (PyList_Check(dval)) {
1383 	       int number = PyList_Size(dval);
1384 	       if (TOPOLY(gelem)->number != number) {
1385 		  TOPOLY(gelem)->points = (pointlist)realloc(
1386 			TOPOLY(gelem)->points, number * sizeof(XPoint));
1387 		  TOPOLY(gelem)->number = number;
1388 	       }
1389 	       for (i = 0; i < number; i++) {
1390 		  pval = PyList_GetItem(dval, i);
1391 		  if (PyTuple_Check(pval) && PyTuple_Size(pval) == 2) {
1392 		     qval = PyTuple_GetItem(pval, 0);
1393 		     TOPOLY(gelem)->points[i].x = (short)PyInt_AsLong(qval);
1394 		     qval = PyTuple_GetItem(pval, 1);
1395 		     TOPOLY(gelem)->points[i].y = (short)PyInt_AsLong(qval);
1396 		  }
1397 		  else {
1398                      PyErr_SetString(PyExc_TypeError,
1399 				"must have a tuple of 2 values per point");
1400 	             break;
1401 		  }
1402 	       }
1403 	    }
1404 	    else {
1405                PyErr_SetString(PyExc_TypeError,
1406 			"points must be in a list of tuples");
1407 	       break;
1408 	    }
1409 	 }
1410 	 break;
1411    }
1412 
1413    calcbbox(areawin->topinstance);
1414    return PyInt_FromLong((long)(*gelem));
1415 }
1416 /*--------------------------------------------------------------*/
1417 /* Set various options through the "set" command.		*/
1418 /* "set <option> on|off" supercedes "enable|disable <option>"	*/
1419 /*--------------------------------------------------------------*/
1420 
xc_set(PyObject * self,PyObject * args)1421 static PyObject *xc_set(PyObject *self, PyObject *args)
1422 {
1423    const char *sarg1, *sarg2;
1424    int i;
1425    Boolean a = True;
1426    short cpage = areawin->page;
1427 
1428    if (!PyArg_ParseTuple(args, "ss:set", &sarg1, &sarg2))
1429       return NULL;
1430 
1431    if (!strcmp(sarg2, "On") || !strcmp(sarg2, "on") || !strcmp(sarg2, "True")
1432 	|| !strcmp(sarg2, "true"))
1433       a = False;     /* has to be backwards; toggle() inverts the value! */
1434 
1435    if (!strcmp(sarg1, "font")) {
1436       for (i = 0; i < fontcount; i++)
1437 	 if (!strcmp(fonts[i].psname, sarg2)) break;
1438 
1439       if (i == fontcount)
1440 	 loadfontfile((char *)sarg2);
1441 
1442       /* loadfontfile() may load multiple fonts, so we have to check again */
1443       /* to see which one matches.					   */
1444 
1445       for (i = 0; i < fontcount; i++) {
1446 	 if (!strcmp(fonts[i].psname, sarg2)) {
1447             areawin->psfont = i;
1448             setdefaultfontmarks();
1449 	    break;
1450 	 }
1451       }
1452    }
1453    else if (!strcmp(sarg1, "fontscale")) {
1454       sscanf(sarg2, "%f", &areawin->textscale);
1455    }
1456    else if (!strcmp(sarg1, "axis") || !strcmp(sarg1, "axes")) {
1457       areawin->axeson = a;
1458       toggle(GridAxesButton, (pointertype)&areawin->axeson, NULL);
1459    }
1460    else if (!strcmp(sarg1, "grid")) {
1461       areawin->gridon = a;
1462       toggle(GridGridButton, (pointertype)&areawin->gridon, NULL);
1463    }
1464    else if (!strcmp(sarg1, "snap") || !strcmp(sarg1, "snap-to")) {
1465       areawin->snapto = a;
1466       toggle(SnaptoSnaptoButton, (pointertype)&areawin->snapto, NULL);
1467    }
1468    else if (!strcmp(sarg1, "gridspace")) {
1469       sscanf(sarg2, "%f", &xobjs.pagelist[cpage]->gridspace);
1470    }
1471    else if (!strcmp(sarg1, "snapspace")) {
1472       sscanf(sarg2, "%f", &xobjs.pagelist[cpage]->snapspace);
1473    }
1474    else if (!strcmp(sarg1, "pagestyle")) {
1475       if (!strcmp(sarg2, "encapsulated") || !strcmp(sarg2, "eps"))
1476 	 xobjs.pagelist[cpage]->pmode = 0;
1477       else
1478 	 xobjs.pagelist[cpage]->pmode = 1;
1479    }
1480    else if (!strcmp(sarg1, "boxedit")) {
1481       if (!strcmp(sarg2, "rhomboid-x")) boxedit(NULL, RHOMBOIDX, NULL);
1482       else if (!strcmp(sarg2, "rhomboid-y")) boxedit(NULL, RHOMBOIDY, NULL);
1483       else if (!strcmp(sarg2, "rhomboid-a")) boxedit(NULL, RHOMBOIDA, NULL);
1484       else if (!strcmp(sarg2, "manhattan")) boxedit(NULL, MANHATTAN, NULL);
1485       else if (!strcmp(sarg2, "normal")) boxedit(NULL, NORMAL, NULL);
1486    }
1487    else if (!strcmp(sarg1, "linewidth")) {
1488       sscanf(sarg2, "%f", &areawin->linewidth);
1489    }
1490    else if (!strcmp(sarg1, "colorscheme")) {
1491       if (!strcmp(sarg2, "inverse"))
1492          areawin->invert = False;
1493       inversecolor(NULL, (pointertype)&areawin->invert, NULL);
1494    }
1495    else if (!strcmp(sarg1, "coordstyle")) {
1496       if (!strcmp(sarg2, "cm") || !strcmp(sarg2, "centimeters")) {
1497          xobjs.pagelist[cpage]->coordstyle = CM;
1498          xobjs.pagelist[cpage]->pagesize.x = 595;  /* A4 size */
1499          xobjs.pagelist[cpage]->pagesize.y = 842;
1500          togglegrid((u_short)xobjs.pagelist[cpage]->coordstyle);
1501       }
1502    }
1503    else if (!strcmp(sarg1, "orient")) {   /* "orient" or "orientation" */
1504       if (!strcmp(sarg2, "landscape"))
1505          xobjs.pagelist[cpage]->orient = 90; /* Landscape */
1506       else
1507          xobjs.pagelist[cpage]->orient = 0;  /* Portrait */
1508    }
1509 
1510    else if (!strcmp(sarg1, "xschema") || !strcmp(sarg1, "schema")) {
1511       /* Do nothing---retained for backward compatibility only */
1512    }
1513 #ifdef HAVE_XPM
1514    else if (!strcmp(sarg1, "toolbar")) {
1515       areawin->toolbar_on = a;
1516       dotoolbar(OptionsDisableToolbarButton, NULL, NULL);
1517     }
1518 #endif
1519 
1520    return PyString_FromString(sarg2);
1521 }
1522 
1523 /*--------------------------------------------------------------*/
1524 
xc_override(PyObject * self,PyObject * args)1525 static PyObject *xc_override(PyObject *self, PyObject *args)
1526 {
1527    const char *sarg1;
1528 
1529    if (!PyArg_ParseTuple(args, "s:override", &sarg1))
1530       return NULL;
1531 
1532    if (!strcmp(sarg1, "library") || !strcmp(sarg1, "libraries"))
1533       flags |= LIBOVERRIDE;
1534    else if (!strcmp(sarg1, "color") || !strcmp(sarg1, "colors"))
1535       flags |= COLOROVERRIDE;
1536    else if (!strcmp(sarg1, "font") || !strcmp(sarg1, "fonts"))
1537       flags |= FONTOVERRIDE;
1538    if (!strcmp(sarg1, "key") || !strcmp(sarg1, "keybindings"))
1539       flags |= KEYOVERRIDE;
1540 
1541    return PyInt_FromLong(0L);
1542 }
1543 
1544 /*--------------------------------------------------------------*/
1545 
xc_library(PyObject * self,PyObject * args)1546 static PyObject *xc_library(PyObject *self, PyObject *args)
1547 {
1548    const char *libname;
1549    int libnum = 1;
1550 
1551    if (!PyArg_ParseTuple(args, "s|i:library", &libname, &libnum))
1552       return NULL;
1553 
1554    /* if loading of default libraries is not overridden, load them first */
1555 
1556    if (!(flags & (LIBOVERRIDE | LIBLOADED))) {
1557       defaultscript();
1558       flags |= LIBLOADED;   /* Pass through a Python variable? */
1559    }
1560 
1561    if (libnum >= xobjs.numlibs || libnum < 0)
1562       libnum = createlibrary(FALSE);
1563    else
1564       libnum += LIBRARY - 1;
1565 
1566    strcpy(_STR, libname);
1567    loadlibrary(libnum);
1568    return PyInt_FromLong((long)libnum);
1569 }
1570 
1571 /*--------------------------------------------------------------*/
1572 
xc_font(PyObject * self,PyObject * args)1573 static PyObject *xc_font(PyObject *self, PyObject *args)
1574 {
1575    const char *fontname;
1576 
1577    if (!PyArg_ParseTuple(args, "s:font", &fontname))
1578       return NULL;
1579 
1580    if (!(flags & FONTOVERRIDE)) {
1581       loadfontfile("Helvetica");
1582       flags |= FONTOVERRIDE;
1583    }
1584    loadfontfile((char *)fontname);
1585    return PyString_FromString(fontname);
1586 }
1587 
1588 /*--------------------------------------------------------------*/
1589 
xc_color(PyObject * self,PyObject * args)1590 static PyObject *xc_color(PyObject *self, PyObject *args)
1591 {
1592    PyObject *pcolor;
1593    int cidx;
1594 
1595    if (!PyArg_ParseTuple(args, "O:color", &pcolor))
1596       return NULL;
1597 
1598    cidx = PyRGBToIndex(pcolor);
1599    return PyIndexToRGB(cidx);
1600 }
1601 
1602 /*--------------------------------------------------------------*/
1603 
xc_bind(PyObject * self,PyObject * args)1604 static PyObject *xc_bind(PyObject *self, PyObject *args)
1605 {
1606    const char *keyname = NULL;
1607    const char *function = NULL;
1608    PyObject *retobj;
1609    int keywstate;
1610 
1611    if (!PyArg_ParseTuple(args, "|ss:bind", &keyname, &function))
1612       return NULL;
1613 
1614    /* If we're in .xcircuitrc and we're not overriding the key	    */
1615    /* bindings, then the first binding function should precipitate  */
1616    /* calling the defaults, then specify the bindings as overridden */
1617    if (!(flags & KEYOVERRIDE)) {
1618       default_keybindings();
1619       flags |= KEYOVERRIDE;
1620    }
1621 
1622    /* No arguments?  Return a dictionary of bound pairs */
1623    if (!keyname) {
1624       PyObject *key, *value;
1625       char *keyname, *funcname;
1626       keybinding *ksearch;
1627 
1628       retobj = PyDict_New();
1629       for (ksearch = keylist; ksearch != NULL; ksearch = ksearch->nextbinding) {
1630 	 keyname = key_to_string(ksearch->keywstate);
1631 	 if (ksearch->value >= 0) {
1632 	    funcname = malloc(strlen(func_to_string(ksearch->function)) + 5);
1633 	    sprintf(funcname, "%s %d", func_to_string(ksearch->function),
1634 		ksearch->value);
1635 	 }
1636 	 else
1637 	    funcname = func_to_string(ksearch->function);
1638 	 key = PyString_FromString(keyname);
1639 	 value = PyString_FromString(funcname);
1640 	 PyDict_SetItem(retobj, key, value);
1641 	 free(keyname);
1642 	 if (ksearch->value >= 0) free(funcname);
1643       }
1644    }
1645    /* One argument?  Argument is a key or a function */
1646    else if (!function) {
1647       char *binding;
1648       int func = -1;
1649       keywstate = string_to_key(keyname);
1650       if (keywstate == 0) { /* first argument (keyname) is function? */
1651 	 keywstate = -1;
1652 	 func = string_to_func(keyname, NULL);
1653       }
1654       if (keywstate == -1)
1655          binding = function_binding_to_string(0, func);
1656       else
1657          binding = key_binding_to_string(0, keywstate);
1658       retobj = PyString_FromString(binding);
1659       free(binding);
1660    }
1661    else {
1662       if (add_keybinding(0, keyname, function) < 0) {
1663 	 /* Function may be a Python function, not a C function */
1664          keywstate = string_to_key(keyname);
1665 	 sprintf(_STR2, "keydict[%d] = %s\n", keywstate, function);
1666 	 PyRun_SimpleString(_STR2);
1667       }
1668       retobj = PyString_FromString(keyname);
1669    }
1670    return retobj;
1671 }
1672 
1673 /*--------------------------------------------------------------*/
1674 
xc_unbind(PyObject * self,PyObject * args)1675 static PyObject *xc_unbind(PyObject *self, PyObject *args)
1676 {
1677    const char *keyname = NULL;
1678    const char *function = NULL;
1679 
1680    if (!PyArg_ParseTuple(args, "ss:unbind", &keyname, &function))
1681       return NULL;
1682 
1683    /* If we're in .xcircuitrc and we're not overriding the key	    */
1684    /* bindings, then the first binding function should precipitate  */
1685    /* calling the defaults, then specify the bindings as overridden */
1686    if (!(flags & KEYOVERRIDE)) {
1687       default_keybindings();
1688       flags |= KEYOVERRIDE;
1689    }
1690 
1691    remove_keybinding(areawin->area, keyname, function);
1692    return PyString_FromString(keyname);
1693 }
1694 
1695 /*--------------------------------------------------------------*/
1696 /* active delay 						*/
1697 /*--------------------------------------------------------------*/
1698 
xc_pause(PyObject * self,PyObject * args)1699 static PyObject *xc_pause(PyObject *self, PyObject *args)
1700 {
1701    float delay;
1702 
1703    if (!PyArg_ParseTuple(args, "f:pause", &delay))
1704       return NULL;
1705 
1706    usleep((int)(1e6 * delay));
1707    return PyInt_FromLong((int)(1e6 * delay));
1708 }
1709 
1710 /*--------------------------------------------------------------*/
1711 /* active refresh						*/
1712 /*--------------------------------------------------------------*/
1713 
xc_refresh(PyObject * self,PyObject * args)1714 static PyObject *xc_refresh(PyObject *self, PyObject *args)
1715 {
1716    XEvent event;
1717 
1718    if (!PyArg_ParseTuple(args, ":refresh"))
1719       return NULL;
1720 
1721    refresh(NULL, NULL, NULL);
1722 
1723    while (XCheckWindowEvent(dpy, areawin->window, ~NoEventMask, &event))
1724          XtDispatchEvent(&event);
1725 
1726    return PyInt_FromLong(0L);
1727 }
1728 
1729 /*--------------------------------------------------------------*/
1730 /* Callback procedure for Python-generated buttons		*/
1731 /*--------------------------------------------------------------*/
1732 
pybutton(Widget w,caddr_t clientdata,caddr_t calldata)1733 int pybutton(Widget w, caddr_t clientdata, caddr_t calldata)
1734 {
1735    int status;
1736 
1737    sprintf(_STR2, "buttondict[%ld]()\n", (long int)w);
1738    status = PyRun_SimpleString(_STR2);
1739    refresh(NULL, NULL, NULL);
1740    return status;
1741 }
1742 
1743 /*--------------------------------------------------------------*/
1744 /* Add a new button to the specified (by name) cascade menu	*/
1745 /*--------------------------------------------------------------*/
1746 
xc_newbutton(PyObject * self,PyObject * args)1747 static PyObject *xc_newbutton(PyObject *self, PyObject *args)
1748 {
1749    const char *pname = NULL;
1750    const char *newbname = NULL;
1751    const char *pfunction = NULL;
1752    int status;
1753    Arg	wargs[1];
1754    int  i, n = 0;
1755    Widget newbutton, cascade, tbutton;
1756 
1757    if (!PyArg_ParseTuple(args, "sss:newbutton", &pname, &newbname, &pfunction))
1758       return NULL;
1759 
1760    for (i = 0; i < MaxMenuWidgets; i++) {
1761       tbutton = menuwidgets[i];
1762       cascade = XtParent(tbutton);
1763       if (!strcmp(XtName(cascade), pname)) break;
1764    }
1765    if (i == MaxMenuWidgets) {
1766       Wprintf("Cannot find specified menu.");
1767       return NULL;
1768    }
1769 
1770    XtnSetArg(XtNfont, appdata.xcfont);
1771    newbutton = XtCreateWidget(newbname, XwmenubuttonWidgetClass,
1772 	 cascade, wargs, n);
1773 
1774    XtAddCallback (newbutton, XtNselect, (XtCallbackProc)pybutton, newbutton);
1775    XtManageChild(newbutton);
1776 
1777    sprintf(_STR2, "buttondict[%ld] = %s\n", (long int)newbutton, pfunction);
1778    status = PyRun_SimpleString(_STR2);
1779    return PyInt_FromLong((long)status);
1780 }
1781 
1782 #ifdef HAVE_XPM
1783 
1784 /*--------------------------------------------------------------*/
1785 /* Callback procedure for Python-generated toolbar tool		*/
1786 /*--------------------------------------------------------------*/
1787 
pytool(Widget w,caddr_t clientdata,caddr_t calldata)1788 int pytool(Widget w, caddr_t clientdata, caddr_t calldata)
1789 {
1790    int status;
1791 
1792    sprintf(_STR2, "tooldict[%ld]()\n", (long int)w);
1793    status = PyRun_SimpleString(_STR2);
1794    refresh(NULL, NULL, NULL);
1795    return status;
1796 }
1797 
1798 /*--------------------------------------------------------------*/
1799 /* Add a new tool to the toolbar				*/
1800 /*--------------------------------------------------------------*/
1801 
xc_newtool(PyObject * self,PyObject * args)1802 static PyObject *xc_newtool(PyObject *self, PyObject *args)
1803 {
1804    const char *thint = NULL;
1805    const char *pixfile = NULL;
1806    const char *newtname = NULL;
1807    const char *pfunction = NULL;
1808    int status;
1809    Arg	wargs[8];
1810    int  i, n = 0;
1811    Widget newtool, cascade, tbutton;
1812    XImage *iret;
1813    XpmAttributes attr;
1814 
1815    attr.valuemask = XpmSize | XpmCloseness;
1816    attr.closeness = 65536;
1817 
1818    if (!PyArg_ParseTuple(args, "sss|s:newtool", &newtname, &pfunction, &pixfile,
1819 		&thint))
1820       return NULL;
1821 
1822    if (XpmReadFileToImage(dpy, (char *)pixfile, &iret, NULL, &attr) < 0) {
1823       Wprintf("Cannot find or open pixmap file \'%s\'", pixfile);
1824       XpmCreateImageFromData(dpy, q_xpm, &iret, NULL, &attr);
1825    }
1826 
1827    XtnSetArg(XtNlabelType, XwIMAGE);
1828    XtnSetArg(XtNlabelImage, iret);
1829    XtnSetArg(XtNwidth, attr.width + 4);
1830    XtnSetArg(XtNheight, attr.height + 4);
1831    XtnSetArg(XtNborderWidth, TBBORDER);
1832    XtnSetArg(XtNnoPad, True);
1833    if (thint != NULL) {
1834       XtnSetArg(XtNhint, thint);
1835       XtnSetArg(XtNhintProc, Wprintf);
1836    }
1837    newtool = XtCreateWidget(newtname, XwmenubuttonWidgetClass, toolbar, wargs, n);
1838 
1839    XtAddCallback (newtool, XtNselect, (XtCallbackProc)pybutton, newtool);
1840    XtManageChild(newtool);
1841 
1842    sprintf(_STR2, "tooldict[%ld] = %s\n", (long int)newtool, pfunction);
1843    status = PyRun_SimpleString(_STR2);
1844    return PyInt_FromLong((long)status);
1845 }
1846 
1847 /*------------------------------------------------------------------*/
1848 /* Return a list of the widgets in tooldict			    */
1849 /* (memory for list is allocated here and must be free'd elsewhere) */
1850 /*------------------------------------------------------------------*/
1851 
pytoolbuttons(int * num_tools)1852 Widget *pytoolbuttons(int *num_tools)
1853 {
1854    Widget *ptools;
1855    PyObject *rval;
1856    int i;
1857 
1858    if (xcmod == NULL) {
1859       *num_tools = 0;
1860       return NULL;
1861    }
1862    rval = PyRun_ObjString("len(tooldict)");
1863    if (!rval) {
1864       PyErr_Clear();
1865       return NULL;
1866    }
1867    *num_tools = (int)PyInt_AsLong(rval);
1868    Py_DECREF(rval);
1869    /* fprintf(stderr, "num_tools = %d\n", *num_tools); */
1870 
1871    if (*num_tools <= 0) return NULL;
1872 
1873    ptools = (Widget *)malloc(*num_tools * sizeof(Widget));
1874 
1875    for (i = 0; i < *num_tools; i++) {
1876       sprintf(_STR2, "tooldict[%d]", i);
1877       rval = PyRun_ObjString(_STR2);
1878       if (!rval) {
1879          PyErr_Clear();
1880 	 return NULL;
1881       }
1882       ptools[i] = (Widget)PyInt_AsLong(rval);
1883       Py_DECREF(rval);
1884    }
1885    return ptools;
1886 }
1887 
1888 #endif
1889 
1890 /*----------------------------------------------------------------*/
1891 /* Execute a python command from the key-function pair dictionary */
1892 /*----------------------------------------------------------------*/
1893 
python_key_command(int keystate)1894 int python_key_command(int keystate)
1895 {
1896    PyObject *rval;
1897    int status;
1898    sprintf(_STR2, "keydict[%d]\n", keystate);
1899    rval = PyRun_ObjString(_STR2);
1900    if (!rval) {
1901       PyErr_Clear();
1902       return -1;
1903    }
1904    Py_DECREF(rval);
1905 
1906    sprintf(_STR2, "keydict[%d]()\n", keystate);
1907    PyRun_SimpleString(_STR2);
1908    refresh(NULL, NULL, NULL);
1909    return 0;
1910 }
1911 
1912 /*--------------------------------------------------------------*/
1913 /* Declaration of the xcircuit Python functions			*/
1914 /*--------------------------------------------------------------*/
1915 
1916 static PyMethodDef xc_methods[] = {
1917    {"set",		xc_set,		1},
1918    {"override",		xc_override,	1},
1919    {"library",		xc_library,	1},
1920    {"font",		xc_font,	1},
1921    {"color",		xc_color,	1},
1922    {"newelement",	xc_new,		1},
1923    {"getpage",		xc_getpage,	1},
1924    {"getlibrary",	xc_getlibrary,	1},
1925    {"getobject",	xc_getobject,	1},
1926    {"getattr",		xc_getattr,	1},
1927    {"setattr",		xc_setattr,	1},
1928    {"refresh",		xc_refresh,	1},
1929    {"pause",		xc_pause,	1},
1930    {"bind",		xc_bind,	1},
1931    {"unbind",		xc_unbind,	1},
1932    {"getcursor",	xc_getcursor,	1},
1933    {"getwindow",	xc_getwindow,	1},
1934    {"zoom",		xc_zoom,	1},
1935    {"pan",		xc_pan,		1},
1936    {"popupprompt",	xc_popupprompt, 1},
1937    {"filepopup",	xc_filepopup,	1},
1938    {"simplepopup",	xc_simplepopup,	1},
1939    {"newbutton",	xc_newbutton,	1},
1940    {"reset",		xc_reset,	1},
1941    {"page",		xc_page,	1},
1942    {"load",		xc_load,	1},
1943 #ifdef HAVE_XPM
1944    {"newtool",		xc_newtool,	1},
1945 #endif
1946    {"netlist",		xc_netlist,	1},
1947    {NULL,	NULL}			/* sentinel */
1948 };
1949 
1950 /*--------------------------------------------------------------*/
1951 /* Initialize Python interpreter and load all xcircuit methods 	*/
1952 /*--------------------------------------------------------------*/
init_interpreter()1953 void init_interpreter()
1954 {
1955    Py_SetProgramName("XCircuit");
1956    Py_Initialize();
1957    PyImport_AddModule("xc");
1958    xcmod = Py_InitModule("xc", xc_methods);
1959    PyRun_SimpleString("from xc import *\n");
1960    PyRun_SimpleString("keydict = {}\n");	/* initialize key/function pairs */
1961    PyRun_SimpleString("buttondict = {}\n");  /* initialize button/function pairs */
1962    PyRun_SimpleString("tooldict = {}\n");  /* initialize tool/function pairs */
1963    sprintf(_STR, "xc_version = %s\n", PROG_VERSION);
1964    PyRun_SimpleString(_STR);
1965 }
1966 
1967 /*--------------------------------------------------------------*/
1968 /* Exit the Python interpreter					*/
1969 /*--------------------------------------------------------------*/
1970 
exit_interpreter()1971 void exit_interpreter()
1972 {
1973    Py_Exit(0);
1974 }
1975 
1976 /*--------------------------------------------------------------*/
1977 /* Replace the functions of the simple rcfile.c	interpreter.	*/
1978 /*--------------------------------------------------------------*/
1979 
1980 /*----------------------------------------------------------------------*/
1981 /* Execute a single command from a script or from the command line      */
1982 /*----------------------------------------------------------------------*/
1983 
execcommand(short pflags,char * cmdptr)1984 short execcommand(short pflags, char *cmdptr)
1985 {
1986    flags = pflags;
1987    PyRun_SimpleString(cmdptr);
1988    refresh(NULL, NULL, NULL);
1989    return flags;
1990 }
1991 
1992 /*----------------------------------------------------------------------*/
1993 /* Load the default script (like execscript() but don't allow recursive */
1994 /* loading of the startup script)                                       */
1995 /*----------------------------------------------------------------------*/
1996 
defaultscript()1997 void defaultscript()
1998 {
1999    FILE *fd;
2000    char *tmp_s = getenv((const char *)"XCIRCUIT_SRC_DIR");
2001 
2002    flags = LIBOVERRIDE | LIBLOADED | FONTOVERRIDE;
2003 
2004    if (!tmp_s) tmp_s = SCRIPTS_DIR;
2005    sprintf(_STR2, "%s/%s", tmp_s, STARTUP_FILE);
2006 
2007    if ((fd = fopen(_STR2, "r")) == NULL) {
2008       sprintf(_STR2, "%s/%s", SCRIPTS_DIR, STARTUP_FILE);
2009       if ((fd = fopen(_STR2, "r")) == NULL) {
2010          Wprintf("Failed to open startup script \"%s\"\n", STARTUP_FILE);
2011 	 return;
2012       }
2013    }
2014    PyRun_SimpleFile(fd, _STR2);
2015 }
2016 
2017 /*----------------------------------------------------------------------*/
2018 /* Execute a script                                                     */
2019 /*----------------------------------------------------------------------*/
2020 
execscript()2021 void execscript()
2022 {
2023    FILE *fd;
2024 
2025    flags = 0;
2026 
2027    xc_tilde_expand(_STR2, 249);
2028    if ((fd = fopen(_STR2, "r")) != NULL) {
2029       PyRun_SimpleFile(fd, _STR2);
2030       refresh(NULL, NULL, NULL);
2031    }
2032    else {
2033       Wprintf("Failed to open script file \"%s\"\n", _STR2);
2034    }
2035 }
2036 
2037 /*----------------------------------------------------------------------*/
2038 /* Execute the .xcircuitrc startup script                               */
2039 /*----------------------------------------------------------------------*/
2040 
loadrcfile()2041 void loadrcfile()
2042 {
2043    char *userdir = getenv((const char *)"HOME");
2044    FILE *fd;
2045    short i;
2046 
2047    /* Initialize flags */
2048 
2049    flags = 0;
2050 
2051    sprintf(_STR2, "%s", USER_RC_FILE);     /* Name imported from Makefile */
2052 
2053    /* try first in current directory, then look in user's home directory */
2054 
2055    xc_tilde_expand(_STR2, 249);
2056    if ((fd = fopen(_STR2, "r")) == NULL) {
2057       if (userdir != NULL) {
2058          sprintf(_STR2, "%s/%s", userdir, USER_RC_FILE);
2059          fd = fopen(_STR2, "r");
2060       }
2061    }
2062    if (fd != NULL)
2063       PyRun_SimpleFile(fd, _STR2);
2064 
2065    /* Add the default font if not loaded already */
2066 
2067    if (!(flags & FONTOVERRIDE)) {
2068       loadfontfile("Helvetica");
2069       if (areawin->psfont == -1)
2070          for (i = 0; i < fontcount; i++)
2071 	    if (!strcmp(fonts[i].psname, "Helvetica")) {
2072 	       areawin->psfont = i;
2073 	       break;
2074 	    }
2075    }
2076 
2077    if (areawin->psfont == -1) areawin->psfont = 0;
2078 
2079    setdefaultfontmarks();
2080 
2081    /* arrange the loaded libraries */
2082 
2083    if (!(flags & (LIBOVERRIDE | LIBLOADED)))
2084       defaultscript();
2085 
2086    /* Add the default colors */
2087 
2088    if (!(flags & COLOROVERRIDE)) {
2089       addnewcolorentry(xc_alloccolor("Gray40"));
2090       addnewcolorentry(xc_alloccolor("Gray60"));
2091       addnewcolorentry(xc_alloccolor("Gray80"));
2092       addnewcolorentry(xc_alloccolor("Gray90"));
2093       addnewcolorentry(xc_alloccolor("Red"));
2094       addnewcolorentry(xc_alloccolor("Blue"));
2095       addnewcolorentry(xc_alloccolor("Green2"));
2096       addnewcolorentry(xc_alloccolor("Yellow"));
2097       addnewcolorentry(xc_alloccolor("Purple"));
2098       addnewcolorentry(xc_alloccolor("SteelBlue2"));
2099       addnewcolorentry(xc_alloccolor("Red3"));
2100       addnewcolorentry(xc_alloccolor("Tan"));
2101       addnewcolorentry(xc_alloccolor("Brown"));
2102    }
2103 
2104    /* These colors must be enabled whether or not colors are overridden, */
2105    /* because they are needed by the schematic capture system.		 */
2106 
2107    addnewcolorentry(xc_getlayoutcolor(LOCALPINCOLOR));
2108    addnewcolorentry(xc_getlayoutcolor(GLOBALPINCOLOR));
2109    addnewcolorentry(xc_getlayoutcolor(INFOLABELCOLOR));
2110    addnewcolorentry(xc_getlayoutcolor(RATSNESTCOLOR));
2111    addnewcolorentry(xc_getlayoutcolor(BBOXCOLOR));
2112 
2113    if (!(flags & KEYOVERRIDE))
2114       default_keybindings();
2115 }
2116 
2117 #endif
2118 /* #endif HAVE_PYTHON and !TCL_WRAPPER */
2119 /*--------------------------------------------------------------*/
2120