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. . . */
11 /* Modeled after demo.c in Python2.0 source Demo/embed */
12 /*--------------------------------------------------------------*/
14 #if defined(HAVE_PYTHON) && !defined(TCL_WRAPPER)
18 #include <unistd.h> /* for usleep() */
23 #include <X11/Intrinsic.h>
24 #include <X11/StringDefs.h>
26 #include "Xw/MenuBtn.h"
30 #include "lib/pixmaps/q.xpm"
35 /*----------------------------------------------------------------------*/
37 /*----------------------------------------------------------------------*/
41 #include "colordefs.h"
43 /*----------------------------------------------------------------------*/
44 /* Function prototype declarations */
45 /*----------------------------------------------------------------------*/
47 #include "prototypes.h"
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();
72 static PyObject
*xc_newtool(PyObject
*, PyObject
*);
75 int string_to_type(const char *);
77 /*----------------------------------------------------------------------*/
78 /* External variable declarations */
79 /*----------------------------------------------------------------------*/
81 extern char _STR2
[250], _STR
[150];
82 extern fontinfo
*fonts
;
83 extern short fontcount
;
84 extern XCWindowData
*areawin
;
85 extern Globaldata xobjs
;
87 extern Widget menuwidgets
[];
89 extern keybinding
*keylist
;
90 extern int number_colors
;
91 extern colorindex
*colorlist
;
92 extern ApplicationData appdata
;
94 extern Widget toolbar
;
97 /*----------------------------------------------------------------------*/
101 #define LIBOVERRIDE 1
103 #define COLOROVERRIDE 4
104 #define FONTOVERRIDE 8
105 #define KEYOVERRIDE 16
107 /*----------------------------------------------------------------*/
108 /* Similar to "PyRun_SimpleString()" but returns a PyObject value */
109 /* rather than a status word. */
110 /*----------------------------------------------------------------*/
112 PyObject
*PyRun_ObjString(char *string
)
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
);
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 /*--------------------------------------------------------------*/
129 /*--------------------------------------------------------------*/
130 /* Extract text from a popup and call the indicated python */
131 /* function. If there is no text, function is called without */
133 /*--------------------------------------------------------------*/
135 void pypromptvalue(Widget w
, char *functionptr
)
137 if (strlen(_STR2
) == 0)
138 sprintf(_STR
, "%s()\n", functionptr
);
140 sprintf(_STR
, "%s('%s')\n", functionptr
, _STR2
);
142 PyRun_SimpleString(_STR
);
143 refresh(NULL
, NULL
, NULL
);
146 /*--------------------------------------------------------------*/
147 /* Pop up a prompt, and return the value to the indicated */
148 /* python function. */
149 /*--------------------------------------------------------------*/
151 static PyObject
*pypopupprompt(PyObject
*self
, PyObject
*args
,
152 const char *dofile
, char *displaystr
)
154 const char *pfunction
= NULL
;
155 const char *prompt
= NULL
;
156 buttonsave
*savebutton
;
158 if (!PyArg_ParseTuple(args
, "ss:popupprompt", &prompt
, &pfunction
))
159 return PyInt_FromLong(-1L);
162 savebutton
= getgeneric(NULL
, NULL
, (void *)pfunction
);
163 popupprompt(areawin
->area
, (char *)prompt
, displaystr
,
164 pypromptvalue
, savebutton
, dofile
);
166 return PyInt_FromLong(0L);
169 /*--------------------------------------------------------------*/
170 /* Wrappers for pypopuprompt() */
171 /*--------------------------------------------------------------*/
173 static PyObject
*xc_popupprompt(PyObject
*self
, PyObject
*args
)
175 return pypopupprompt(self
, args
, NULL
, "");
178 static PyObject
*xc_filepopup(PyObject
*self
, PyObject
*args
)
180 return pypopupprompt(self
, args
, "", "");
183 static PyObject
*xc_simplepopup(PyObject
*self
, PyObject
*args
)
186 return pypopupprompt(self
, args
, False
, NULL
);
189 /*--------------------------------------------------------------*/
190 /* Create objects and return a handle to that object in the */
191 /* form of a Python integer Object. */
192 /*--------------------------------------------------------------*/
194 static PyObject
*xc_new(PyObject
*self
, PyObject
*args
)
201 splineptr
*newspline
;
205 objinstptr
*newobjinst
;
207 if (!PyArg_ParseTuple(args
, "s:newelement", &etype
))
210 switch(type
= string_to_type(etype
)) {
212 NEW_ARC(newarc
, topobject
);
213 arcdefaults(*newarc
, 0, 0);
214 newgen
= (genericptr
*)newarc
;
217 NEW_SPLINE(newspline
, topobject
);
218 splinedefaults(*newspline
, 0, 0);
219 newgen
= (genericptr
*)newspline
;
222 NEW_POLY(newpoly
, topobject
);
223 polydefaults(*newpoly
, 4, 0, 0);
224 newgen
= (genericptr
*)newpoly
;
227 NEW_LABEL(newlabel
, topobject
);
228 labeldefaults(*newlabel
, 0, 0, 0);
229 newgen
= (genericptr
*)newlabel
;
232 NEW_PATH(newpath
, topobject
);
233 pathdefaults(*newpath
, 0, 0);
234 newgen
= (genericptr
*)newpath
;
237 NEW_OBJINST(newobjinst
, topobject
);
238 instancedefaults(*newobjinst
, NULL
, 0, 0);
239 newgen
= (genericptr
*)newobjinst
;
242 PyErr_SetString(PyExc_TypeError
,
243 "newelement() 2nd argument must be a valid element type");
246 incr_changes(topobject
);
247 invalidate_netlist(topobject
);
249 return PyInt_FromLong((long)(*newgen
));
252 /*--------------------------------------------------------------*/
253 /* Convert object type to a string */
254 /*--------------------------------------------------------------*/
256 char *type_to_string(int type
)
263 strcpy(retstr
, "Label");
267 strcpy(retstr
, "Polygon");
271 strcpy(retstr
, "Bezier Curve");
275 strcpy(retstr
, "Object Instance");
279 strcpy(retstr
, "Path");
283 strcpy(retstr
, "Arc");
289 /*--------------------------------------------------------------*/
290 /* Convert a string to an element type */
291 /*--------------------------------------------------------------*/
293 int string_to_type(const char *etype
)
295 if (!strcmp(etype
, "Arc"))
297 else if (!strcmp(etype
, "Bezier Curve"))
299 else if (!strcmp(etype
, "Polygon"))
301 else if (!strcmp(etype
, "Label"))
303 else if (!strcmp(etype
, "Path"))
305 else if (!strcmp(etype
, "Object Instance"))
311 /*--------------------------------------------------------------*/
312 /* Convert color index to 3-tuple and vice versa */
313 /* We assume that this color exists in the color table. */
314 /*--------------------------------------------------------------*/
316 PyObject
*PyIndexToRGB(int cidx
)
321 if (cidx
< 0) { /* Handle "default color" */
322 return PyString_FromString("Default");
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)));
337 PyErr_SetString(PyExc_TypeError
, "invalid or unknown color index");
341 /*--------------------------------------------------------------*/
342 /* Convert color 3-tuple (RGB) or name to a color index */
343 /*--------------------------------------------------------------*/
345 int PyRGBToIndex(PyObject
*cobj
)
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)));
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)));
363 PyErr_SetString(PyExc_TypeError
, "tuple components must be integer or float");
366 ccolor
= rgb_alloccolor(r
, g
, b
);
368 else if (PyString_Check(cobj
)) { /* color name */
369 ccolor
= xc_alloccolor(PyString_AsString(cobj
));
371 else if (PyInt_Check(cobj
)) { /* index (for backward compatibility) */
372 ccolor
= (int)PyInt_AsLong(cobj
);
375 PyErr_SetString(PyExc_TypeError
, "argument must be a string or 3-tuple");
379 addnewcolorentry(ccolor
);
383 /*--------------------------------------------------------------*/
384 /* Convert a Python list to a stringpart* */
385 /*--------------------------------------------------------------*/
387 stringpart
*PySetStringParts(PyObject
*dval
)
389 PyObject
*lstr
, *litem
, *ditem
, *sitem
, *titem
;
391 stringpart
*strptr
, *newpart
;
394 /* If we pass a string, create a list of size 1 to hold the string. */
395 /* Otherwise, the argument must be a list. */
397 if (PyList_Check(dval
)) {
401 if (PyString_Check(dval
)) {
402 lstr
= PyList_New(1);
403 PyList_SetItem(lstr
, 0, dval
);
406 PyErr_SetString(PyExc_TypeError
, "argument must be a string or a list");
412 llen
= PyList_Size(lstr
);
413 for (i
= 0; i
< llen
; i
++) {
414 newpart
= makesegment(&strptr
, NULL
);
415 newpart
->nextpart
= NULL
;
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
));
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
;
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));
436 else if ((ditem
= PyDict_GetItemString(litem
, "Color")) != NULL
) {
437 newpart
->type
= FONT_COLOR
;
438 newpart
->data
.color
= PyRGBToIndex(ditem
);
440 else if ((ditem
= PyDict_GetItemString(litem
, "Font Scale")) != NULL
) {
441 newpart
->type
= FONT_SCALE
;
442 newpart
->data
.scale
= (float)PyFloat_AsDouble(ditem
);
444 else if ((ditem
= PyDict_GetItemString(litem
, "Text")) != NULL
) {
445 newpart
->type
= TEXT_STRING
;
446 newpart
->data
.string
= strdup(PyString_AsString(ditem
));
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
;
455 else if (!strcmp(string
, "Tab Stop")) {
456 newpart
->type
= TABSTOP
;
458 else if (!strcmp(string
, "Tab Forward")) {
459 newpart
->type
= TABFORWARD
;
461 else if (!strcmp(string
, "Tab Backward")) {
462 newpart
->type
= TABBACKWARD
;
464 else if (!strcmp(string
, "Return")) {
465 newpart
->type
= RETURN
;
467 else if (!strcmp(string
, "Subscript")) {
468 newpart
->type
= SUBSCRIPT
;
470 else if (!strcmp(string
, "Superscript")) {
471 newpart
->type
= SUPERSCRIPT
;
473 else if (!strcmp(string
, "Normalscript")) {
474 newpart
->type
= NORMALSCRIPT
;
476 else if (!strcmp(string
, "Underline")) {
477 newpart
->type
= UNDERLINE
;
479 else if (!strcmp(string
, "Overline")) {
480 newpart
->type
= OVERLINE
;
482 else if (!strcmp(string
, "No Line")) {
483 newpart
->type
= NOLINE
;
485 else if (!strcmp(string
, "Half Space")) {
486 newpart
->type
= HALFSPACE
;
488 else if (!strcmp(string
, "Quarter Space")) {
489 newpart
->type
= QTRSPACE
;
492 newpart
->type
= TEXT_STRING
;
493 newpart
->data
.string
= strdup(string
);
500 /*--------------------------------------------------------------*/
501 /* Convert a stringpart* to a Python list */
502 /*--------------------------------------------------------------*/
504 PyObject
*PyGetStringParts(stringpart
*thisstring
)
506 PyObject
*lstr
, *sdict
, *stup
;
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
) {
516 sdict
= PyDict_New();
517 PyDict_SetItem(sdict
, PyString_FromString("Text"),
518 PyString_FromString(strptr
->data
.string
));
519 PyList_SetItem(lstr
, i
, sdict
);
522 sdict
= PyDict_New();
523 PyDict_SetItem(sdict
, PyString_FromString("Parameter"),
524 PyString_FromString(strptr
->data
.string
));
525 PyList_SetItem(lstr
, i
, sdict
);
528 PyList_SetItem(lstr
, i
, PyString_FromString("End Parameter"));
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
);
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
);
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
);
551 stup
= PyIndexToRGB(strptr
->data
.color
);
553 sdict
= PyDict_New();
554 PyDict_SetItem(sdict
, PyString_FromString("Color"), stup
);
555 PyList_SetItem(lstr
, i
, sdict
);
559 PyList_SetItem(lstr
, i
, PyString_FromString("Tab Stop"));
562 PyList_SetItem(lstr
, i
, PyString_FromString("Tab Forward"));
565 PyList_SetItem(lstr
, i
, PyString_FromString("Tab Backward"));
568 PyList_SetItem(lstr
, i
, PyString_FromString("Return"));
571 PyList_SetItem(lstr
, i
, PyString_FromString("Subscript"));
574 PyList_SetItem(lstr
, i
, PyString_FromString("Superscript"));
577 PyList_SetItem(lstr
, i
, PyString_FromString("Normalscript"));
580 PyList_SetItem(lstr
, i
, PyString_FromString("Underline"));
583 PyList_SetItem(lstr
, i
, PyString_FromString("Overline"));
586 PyList_SetItem(lstr
, i
, PyString_FromString("No Line"));
589 PyList_SetItem(lstr
, i
, PyString_FromString("Half Space"));
592 PyList_SetItem(lstr
, i
, PyString_FromString("Quarter Space"));
599 /*--------------------------------------------------------------*/
600 /* Check if the handle (integer) is an existing element */
601 /*--------------------------------------------------------------*/
603 genericptr
*CheckHandle(PyObject
*ehandle
)
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
;
616 /* Okay, it isn't in topobject. Try all other pages. */
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
;
625 /* Still not found? Maybe in a library */
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
;
636 /* Either in the delete list (where we don't want to go) or */
637 /* is an invalid number. */
644 /*--------------------------------------------------------------*/
645 /* Check if the handle (integer) is an existing page */
646 /*--------------------------------------------------------------*/
648 objectptr
CheckPageHandle(PyObject
*ehandle
)
653 eaddr
= PyInt_AsLong(ehandle
);
654 pageno
= is_page((objectptr
)eaddr
);
655 if (pageno
< 0) return NULL
;
656 return (objectptr
)eaddr
;
659 /*--------------------------------------------------------------*/
660 /* Form a 2-tuple from a pair of integers. */
661 /*--------------------------------------------------------------*/
663 static PyObject
*make_pair(XPoint
*thispoint
)
667 dtup
= PyTuple_New(2);
669 PyTuple_SetItem(dtup
, 0,
670 PyInt_FromLong((long)(thispoint
->x
)));
671 PyTuple_SetItem(dtup
, 1,
672 PyInt_FromLong((long)(thispoint
->y
)));
676 /*--------------------------------------------------------------*/
677 /* Get the properties of a page (returned as a dictionary) */
678 /*--------------------------------------------------------------*/
680 static PyObject
*xc_getpage(PyObject
*self
, PyObject
*args
)
683 PyObject
*rdict
, *dlist
;
684 int pageno
= areawin
->page
+ 1, i
;
686 if (!PyArg_ParseTuple(args
, "|d:getpage", &pageno
))
689 if (pageno
<= 0 || pageno
> xobjs
.pages
) return NULL
;
692 thispage
= xobjs
.pagelist
[pageno
];
694 rdict
= PyDict_New();
696 PyDict_SetItem(rdict
, PyString_FromString("filename"),
697 PyString_FromString(thispage
->filename
));
699 PyDict_SetItem(rdict
, PyString_FromString("page label"),
700 PyString_FromString(thispage
->pageinst
->thisobject
->name
));
702 PyDict_SetItem(rdict
, PyString_FromString("output scale"),
703 PyFloat_FromDouble((double)thispage
->outscale
));
705 /* To be done: change these from internal units to "natural" units */
707 PyDict_SetItem(rdict
, PyString_FromString("grid space"),
708 PyFloat_FromDouble((double)thispage
->gridspace
));
710 PyDict_SetItem(rdict
, PyString_FromString("snap space"),
711 PyFloat_FromDouble((double)thispage
->snapspace
));
713 PyDict_SetItem(rdict
, PyString_FromString("orientation"),
714 PyInt_FromLong((long)thispage
->orient
));
716 PyDict_SetItem(rdict
, PyString_FromString("output mode"),
717 PyInt_FromLong((long)thispage
->pmode
));
719 PyDict_SetItem(rdict
, PyString_FromString("coordinate style"),
720 PyInt_FromLong((long)thispage
->coordstyle
));
722 PyDict_SetItem(rdict
, PyString_FromString("page size"),
723 make_pair(&(thispage
->pagesize
)));
725 PyDict_SetItem(rdict
, PyString_FromString("drawing scale"),
726 make_pair(&(thispage
->drawingscale
)));
731 /*--------------------------------------------------------------*/
732 /* Get the properties of a library (returned as a dictionary) */
733 /*--------------------------------------------------------------*/
735 static PyObject
*xc_getlibrary(PyObject
*self
, PyObject
*args
)
737 PyObject
*rdict
, *dlist
;
738 const char *lname
= NULL
;
739 objectptr
*curlib
= NULL
, thisobj
;
744 if (!PyArg_ParseTuple(args
, "s:getlibrary", &lname
))
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
;
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
;
758 else if (!strncmp(xobjs
.libtop
[lpage
+ LIBRARY
]->thisobject
->name
,
760 if (!strcmp(lname
, xobjs
.libtop
[lpage
+ LIBRARY
]->thisobject
->name
+ 9)) {
761 curlib
= xobjs
.userlibs
[lpage
- 1].library
;
768 if (curlib
== NULL
) {
769 PyErr_SetString(PyExc_TypeError
,
770 "getlibrary() 2nd argument must be a library page or name");
773 curobjs
= xobjs
.userlibs
[lpage
- 1].number
;
775 /* Argument to getlibrary() can be a library name or library page # */
777 rdict
= PyDict_New();
779 PyDict_SetItem(rdict
, PyString_FromString("name"),
780 PyString_FromString(xobjs
.libtop
[lpage
+ LIBRARY
]->thisobject
->name
));
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
));
788 PyDict_SetItem(rdict
, PyString_FromString("objects"), dlist
);
793 /*--------------------------------------------------------------*/
794 /* Get the properties of an object (returned as a dictionary) */
795 /*--------------------------------------------------------------*/
797 static PyObject
*xc_getobject(PyObject
*self
, PyObject
*args
)
799 objectptr thisobj
= NULL
, *libobj
;
801 PyObject
*rdict
, *dlist
, *tpos
;
805 if (!PyArg_ParseTuple(args
, "s:getobject", &oname
))
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
)) {
816 if (thisobj
!= NULL
) break;
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
))
825 if (k
== xobjs
.pages
) return NULL
; /* not found */
828 /* return all the object's properties as a dictionary */
830 rdict
= PyDict_New();
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
)));
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
);
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
);
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
);
856 nparam
= get_num_params(thisobj
);
858 dlist
= PyList_New(nparam
);
860 for (ops
= thisobj
->params
; ops
!= NULL
; ops
= ops
->next
) {
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
));
870 PyDict_SetItem(rdict
, PyString_FromString("parameters"), dlist
);
875 /*--------------------------------------------------------------*/
876 /* Reset the current page */
877 /*--------------------------------------------------------------*/
879 static PyObject
*xc_reset()
881 resetbutton(NULL
, (pointertype
)0, NULL
);
882 return PyInt_FromLong(0L);
885 /*--------------------------------------------------------------*/
887 /*--------------------------------------------------------------*/
889 extern PyObject
*pyglobals(objectptr
);
890 extern PyObject
*pytoplevel(objectptr
);
892 static PyObject
*xc_netlist()
894 PyObject
*rdict
= NULL
;
896 if (updatenets(areawin
->topinstance
, FALSE
) <= 0) {
897 PyErr_SetString(PyExc_TypeError
, "Error: Check circuit for infinite recursion.");
901 rdict
= PyDict_New();
902 PyDict_SetItem(rdict
, PyString_FromString("globals"), pyglobals(topobject
));
903 PyDict_SetItem(rdict
, PyString_FromString("circuit"), pytoplevel(topobject
));
907 /*--------------------------------------------------------------*/
908 /* Load the specified file */
909 /*--------------------------------------------------------------*/
911 static PyObject
*xc_load(PyObject
*self
, PyObject
*args
)
914 int pageno
= 0, savepage
;
916 if (!PyArg_ParseTuple(args
, "s|i:load", &filename
, &pageno
))
917 return PyInt_FromLong((long)areawin
->page
);
919 if (--pageno
< 0) pageno
= areawin
->page
;
920 savepage
= areawin
->page
;
922 strcpy(_STR2
, filename
);
923 if (savepage
!= pageno
) newpage(pageno
);
925 if (savepage
!= pageno
) newpage(savepage
);
927 return PyString_FromString(filename
);
930 /*--------------------------------------------------------------*/
931 /* Go to the specified page */
932 /*--------------------------------------------------------------*/
934 static PyObject
*xc_page(PyObject
*self
, PyObject
*args
)
938 if (!PyArg_ParseTuple(args
, "i:page", &pageno
))
939 return PyInt_FromLong((long)areawin
->page
);
942 return PyInt_FromLong((long)pageno
);
945 /*--------------------------------------------------------------*/
947 /*--------------------------------------------------------------*/
949 static PyObject
*xc_zoom(PyObject
*self
, PyObject
*args
)
953 if (!PyArg_ParseTuple(args
, "f:zoom", &factor
))
957 PyErr_SetString(PyExc_TypeError
, "Argument must be positive.");
961 save
= areawin
->zoomfactor
;
964 areawin
->zoomfactor
= 1.0 / factor
;
965 zoomout(0, 0); /* Needs to be fixed---give x, y for drag fn */
968 areawin
->zoomfactor
= factor
;
969 zoomin(0, 0); /* Needs to be fixed---see above */
972 areawin
->zoomfactor
= save
;
973 return PyFloat_FromDouble((double)topobject
->viewscale
);
976 /*--------------------------------------------------------------*/
978 /*--------------------------------------------------------------*/
980 static PyObject
*xc_pan(PyObject
*self
, PyObject
*args
)
982 PyObject
*cornerpos
, *xobj
, *yobj
= NULL
, *pval
;
984 XPoint upoint
, wpoint
;
986 if (!PyArg_ParseTuple(args
, "O|O:pan", &xobj
, &yobj
))
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
);
999 upoint
.x
= PyInt_AsLong(xobj
);
1000 upoint
.y
= PyInt_AsLong(yobj
);
1003 user_to_window(upoint
, &wpoint
);
1004 panbutton((u_int
)5, wpoint
.x
, wpoint
.y
, 0.33); /* fixed fraction */
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
));
1013 /*--------------------------------------------------------------*/
1014 /* Get the window size */
1015 /*--------------------------------------------------------------*/
1017 static PyObject
*xc_getwindow()
1019 PyObject
*windowsize
;
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
));
1028 /*--------------------------------------------------------------*/
1029 /* Get the cursor position */
1030 /*--------------------------------------------------------------*/
1032 static PyObject
*xc_getcursor()
1034 PyObject
*cursorpos
;
1037 newpos
= UGetCursorPos();
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
));
1047 /*--------------------------------------------------------------*/
1048 /* Get the properties of an element (returned as a dictionary) */
1049 /*--------------------------------------------------------------*/
1051 static PyObject
*xc_getattr(PyObject
*self
, PyObject
*args
)
1054 PyObject
*ehandle
, *rdict
, *dlist
, *lstr
, *sdict
, *stup
;
1060 if (!PyArg_ParseTuple(args
, "O:getattr", &ehandle
))
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.");
1070 /* return the element's properties as a dictionary */
1072 rdict
= PyDict_New();
1073 tstr
= type_to_string((*gelem
)->type
);
1075 PyErr_SetString(PyExc_TypeError
,
1076 "Element type is unknown.");
1079 PyDict_SetItem(rdict
, PyString_FromString("type"),
1080 PyString_FromString(tstr
));
1082 lstr
= PyIndexToRGB((*gelem
)->color
);
1084 PyDict_SetItem(rdict
, PyString_FromString("color"), lstr
);
1086 switch(ELEMENTTYPE(*gelem
)) {
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
);
1100 PyDict_SetItem(rdict
, PyString_FromString("string"), lstr
);
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
])));
1111 PyDict_SetItem(rdict
, PyString_FromString("points"), dlist
);
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
)));
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
])));
1138 PyDict_SetItem(rdict
, PyString_FromString("control points"), dlist
);
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
))));
1150 PyDict_SetItem(rdict
, PyString_FromString("parts"), dlist
);
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
));
1166 /*--------------------------------------------------------------*/
1167 /* Set properties of an element (supplied as a dictionary) */
1168 /*--------------------------------------------------------------*/
1170 static PyObject
*xc_setattr(PyObject
*self
, PyObject
*args
)
1173 PyObject
*ehandle
, *attrdict
, *dval
, *pval
, *qval
;
1176 if (!PyArg_ParseTuple(args
, "OO:setattr", &ehandle
, &attrdict
))
1179 /* Check to make sure that handle exists! */
1180 if ((gelem
= CheckHandle(ehandle
)) == NULL
) return NULL
;
1182 /* Is the argument a dictionary? */
1183 if (!PyDict_Check(attrdict
)) {
1184 PyErr_SetString(PyExc_TypeError
,
1185 "setatrr() 2nd argument must be a dictionary");
1189 /* First, make sure no attempt is made to change the object type. */
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.");
1201 /* Next, look for dictionary strings containing values which apply */
1202 /* to a number of different elements (position, color, etc.) */
1204 if ((dval
= PyDict_GetItemString(attrdict
, "color")) != NULL
) {
1205 (*gelem
)->color
= (short)PyRGBToIndex(dval
);
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
)) {
1214 TOARC(gelem
)->position
.x
= xpos
;
1215 calcarc(TOARC(gelem
));
1218 TOLABEL(gelem
)->position
.x
= xpos
;
1221 TOOBJINST(gelem
)->position
.x
= xpos
;
1224 PyErr_SetString(PyExc_TypeError
,
1225 "attempt to set position on Spline, Polygon, or Path");
1229 if ((pval
= PyTuple_GetItem(dval
, 1)) != NULL
) {
1230 short ypos
= (short)PyInt_AsLong(pval
);
1231 switch(ELEMENTTYPE(*gelem
)) {
1233 TOARC(gelem
)->position
.y
= ypos
;
1234 calcarc(TOARC(gelem
));
1237 TOLABEL(gelem
)->position
.y
= ypos
;
1240 TOOBJINST(gelem
)->position
.y
= ypos
;
1243 PyErr_SetString(PyExc_TypeError
,
1244 "attempt to set position on Spline, Polygon, or Path");
1249 PyErr_SetString(PyExc_TypeError
,
1250 "position must be a tuple containing two integer values");
1254 if ((dval
= PyDict_GetItemString(attrdict
, "style")) != NULL
) {
1255 short dstyle
= (short)PyInt_AsLong(dval
);
1256 switch(ELEMENTTYPE(*gelem
)) {
1258 TOPOLY(gelem
)->style
= dstyle
;
1261 TOPATH(gelem
)->style
= dstyle
;
1264 TOARC(gelem
)->style
= dstyle
;
1267 TOSPLINE(gelem
)->style
= dstyle
;
1270 PyErr_SetString(PyExc_TypeError
,
1271 "attempt to set style on an Object Instance or Label");
1275 if ((dval
= PyDict_GetItemString(attrdict
, "linewidth")) != NULL
) {
1276 float dwidth
= (float)PyFloat_AsDouble(dval
);
1277 switch(ELEMENTTYPE(*gelem
)) {
1279 TOPOLY(gelem
)->width
= dwidth
;
1282 TOPATH(gelem
)->width
= dwidth
;
1285 TOARC(gelem
)->width
= dwidth
;
1288 TOSPLINE(gelem
)->width
= dwidth
;
1291 PyErr_SetString(PyExc_TypeError
,
1292 "attempt to set linewidth on an Object Instance or Label");
1296 if ((dval
= PyDict_GetItemString(attrdict
, "scale")) != NULL
) {
1297 float dscale
= (float)PyFloat_AsDouble(dval
);
1298 switch(ELEMENTTYPE(*gelem
)) {
1300 TOLABEL(gelem
)->scale
= dscale
;
1303 TOOBJINST(gelem
)->scale
= dscale
;
1306 PyErr_SetString(PyExc_TypeError
,
1307 "attempt to set scale on something not a Label or Object Instance");
1311 if ((dval
= PyDict_GetItemString(attrdict
, "rotation")) != NULL
) {
1312 float drot
= (float)PyFloat_AsDouble(dval
);
1313 switch(ELEMENTTYPE(*gelem
)) {
1315 TOLABEL(gelem
)->rotation
= drot
;
1318 TOOBJINST(gelem
)->rotation
= drot
;
1321 PyErr_SetString(PyExc_TypeError
,
1322 "attempt to set rotation on something not a Label or Object Instance");
1326 /* Dictionary entries specific to certain xcircuit types */
1328 switch(ELEMENTTYPE(*gelem
)) {
1330 if ((dval
= PyDict_GetItemString(attrdict
, "anchor")) != NULL
) {
1331 TOLABEL(gelem
)->anchor
= PyInt_AsLong(dval
);
1333 if ((dval
= PyDict_GetItemString(attrdict
, "string")) != NULL
) {
1334 freelabel(TOLABEL(gelem
)->string
);
1335 TOLABEL(gelem
)->string
= PySetStringParts(dval
);
1337 if ((dval
= PyDict_GetItemString(attrdict
, "pin")) != NULL
) {
1338 TOLABEL(gelem
)->pin
= PyInt_AsLong(dval
);
1342 if ((dval
= PyDict_GetItemString(attrdict
, "start angle")) != NULL
) {
1343 TOARC(gelem
)->angle1
= (float)PyFloat_AsDouble(dval
);
1345 if ((dval
= PyDict_GetItemString(attrdict
, "end angle")) != NULL
) {
1346 TOARC(gelem
)->angle2
= (float)PyFloat_AsDouble(dval
);
1348 if ((dval
= PyDict_GetItemString(attrdict
, "radius")) != NULL
) {
1349 TOARC(gelem
)->radius
= PyInt_AsLong(dval
);
1351 if ((dval
= PyDict_GetItemString(attrdict
, "minor axis")) != NULL
) {
1352 TOARC(gelem
)->yaxis
= PyInt_AsLong(dval
);
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
);
1367 PyErr_SetString(PyExc_TypeError
,
1368 "must have a tuple of 2 values per point");
1374 PyErr_SetString(PyExc_TypeError
,
1375 "must have 4 control points in a list");
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
;
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
);
1398 PyErr_SetString(PyExc_TypeError
,
1399 "must have a tuple of 2 values per point");
1405 PyErr_SetString(PyExc_TypeError
,
1406 "points must be in a list of tuples");
1413 calcbbox(areawin
->topinstance
);
1414 return PyInt_FromLong((long)(*gelem
));
1416 /*--------------------------------------------------------------*/
1417 /* Set various options through the "set" command. */
1418 /* "set <option> on|off" supercedes "enable|disable <option>" */
1419 /*--------------------------------------------------------------*/
1421 static PyObject
*xc_set(PyObject
*self
, PyObject
*args
)
1423 const char *sarg1
, *sarg2
;
1426 short cpage
= areawin
->page
;
1428 if (!PyArg_ParseTuple(args
, "ss:set", &sarg1
, &sarg2
))
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! */
1435 if (!strcmp(sarg1
, "font")) {
1436 for (i
= 0; i
< fontcount
; i
++)
1437 if (!strcmp(fonts
[i
].psname
, sarg2
)) break;
1440 loadfontfile((char *)sarg2
);
1442 /* loadfontfile() may load multiple fonts, so we have to check again */
1443 /* to see which one matches. */
1445 for (i
= 0; i
< fontcount
; i
++) {
1446 if (!strcmp(fonts
[i
].psname
, sarg2
)) {
1447 areawin
->psfont
= i
;
1448 setdefaultfontmarks();
1453 else if (!strcmp(sarg1
, "fontscale")) {
1454 sscanf(sarg2
, "%f", &areawin
->textscale
);
1456 else if (!strcmp(sarg1
, "axis") || !strcmp(sarg1
, "axes")) {
1457 areawin
->axeson
= a
;
1458 toggle(GridAxesButton
, (pointertype
)&areawin
->axeson
, NULL
);
1460 else if (!strcmp(sarg1
, "grid")) {
1461 areawin
->gridon
= a
;
1462 toggle(GridGridButton
, (pointertype
)&areawin
->gridon
, NULL
);
1464 else if (!strcmp(sarg1
, "snap") || !strcmp(sarg1
, "snap-to")) {
1465 areawin
->snapto
= a
;
1466 toggle(SnaptoSnaptoButton
, (pointertype
)&areawin
->snapto
, NULL
);
1468 else if (!strcmp(sarg1
, "gridspace")) {
1469 sscanf(sarg2
, "%f", &xobjs
.pagelist
[cpage
]->gridspace
);
1471 else if (!strcmp(sarg1
, "snapspace")) {
1472 sscanf(sarg2
, "%f", &xobjs
.pagelist
[cpage
]->snapspace
);
1474 else if (!strcmp(sarg1
, "pagestyle")) {
1475 if (!strcmp(sarg2
, "encapsulated") || !strcmp(sarg2
, "eps"))
1476 xobjs
.pagelist
[cpage
]->pmode
= 0;
1478 xobjs
.pagelist
[cpage
]->pmode
= 1;
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
);
1487 else if (!strcmp(sarg1
, "linewidth")) {
1488 sscanf(sarg2
, "%f", &areawin
->linewidth
);
1490 else if (!strcmp(sarg1
, "colorscheme")) {
1491 if (!strcmp(sarg2
, "inverse"))
1492 areawin
->invert
= False
;
1493 inversecolor(NULL
, (pointertype
)&areawin
->invert
, NULL
);
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
);
1503 else if (!strcmp(sarg1
, "orient")) { /* "orient" or "orientation" */
1504 if (!strcmp(sarg2
, "landscape"))
1505 xobjs
.pagelist
[cpage
]->orient
= 90; /* Landscape */
1507 xobjs
.pagelist
[cpage
]->orient
= 0; /* Portrait */
1510 else if (!strcmp(sarg1
, "xschema") || !strcmp(sarg1
, "schema")) {
1511 /* Do nothing---retained for backward compatibility only */
1514 else if (!strcmp(sarg1
, "toolbar")) {
1515 areawin
->toolbar_on
= a
;
1516 dotoolbar(OptionsDisableToolbarButton
, NULL
, NULL
);
1520 return PyString_FromString(sarg2
);
1523 /*--------------------------------------------------------------*/
1525 static PyObject
*xc_override(PyObject
*self
, PyObject
*args
)
1529 if (!PyArg_ParseTuple(args
, "s:override", &sarg1
))
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
;
1541 return PyInt_FromLong(0L);
1544 /*--------------------------------------------------------------*/
1546 static PyObject
*xc_library(PyObject
*self
, PyObject
*args
)
1548 const char *libname
;
1551 if (!PyArg_ParseTuple(args
, "s|i:library", &libname
, &libnum
))
1554 /* if loading of default libraries is not overridden, load them first */
1556 if (!(flags
& (LIBOVERRIDE
| LIBLOADED
))) {
1558 flags
|= LIBLOADED
; /* Pass through a Python variable? */
1561 if (libnum
>= xobjs
.numlibs
|| libnum
< 0)
1562 libnum
= createlibrary(FALSE
);
1564 libnum
+= LIBRARY
- 1;
1566 strcpy(_STR
, libname
);
1567 loadlibrary(libnum
);
1568 return PyInt_FromLong((long)libnum
);
1571 /*--------------------------------------------------------------*/
1573 static PyObject
*xc_font(PyObject
*self
, PyObject
*args
)
1575 const char *fontname
;
1577 if (!PyArg_ParseTuple(args
, "s:font", &fontname
))
1580 if (!(flags
& FONTOVERRIDE
)) {
1581 loadfontfile("Helvetica");
1582 flags
|= FONTOVERRIDE
;
1584 loadfontfile((char *)fontname
);
1585 return PyString_FromString(fontname
);
1588 /*--------------------------------------------------------------*/
1590 static PyObject
*xc_color(PyObject
*self
, PyObject
*args
)
1595 if (!PyArg_ParseTuple(args
, "O:color", &pcolor
))
1598 cidx
= PyRGBToIndex(pcolor
);
1599 return PyIndexToRGB(cidx
);
1602 /*--------------------------------------------------------------*/
1604 static PyObject
*xc_bind(PyObject
*self
, PyObject
*args
)
1606 const char *keyname
= NULL
;
1607 const char *function
= NULL
;
1611 if (!PyArg_ParseTuple(args
, "|ss:bind", &keyname
, &function
))
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
;
1622 /* No arguments? Return a dictionary of bound pairs */
1624 PyObject
*key
, *value
;
1625 char *keyname
, *funcname
;
1626 keybinding
*ksearch
;
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
),
1637 funcname
= func_to_string(ksearch
->function
);
1638 key
= PyString_FromString(keyname
);
1639 value
= PyString_FromString(funcname
);
1640 PyDict_SetItem(retobj
, key
, value
);
1642 if (ksearch
->value
>= 0) free(funcname
);
1645 /* One argument? Argument is a key or a function */
1646 else if (!function
) {
1649 keywstate
= string_to_key(keyname
);
1650 if (keywstate
== 0) { /* first argument (keyname) is function? */
1652 func
= string_to_func(keyname
, NULL
);
1654 if (keywstate
== -1)
1655 binding
= function_binding_to_string(0, func
);
1657 binding
= key_binding_to_string(0, keywstate
);
1658 retobj
= PyString_FromString(binding
);
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
);
1668 retobj
= PyString_FromString(keyname
);
1673 /*--------------------------------------------------------------*/
1675 static PyObject
*xc_unbind(PyObject
*self
, PyObject
*args
)
1677 const char *keyname
= NULL
;
1678 const char *function
= NULL
;
1680 if (!PyArg_ParseTuple(args
, "ss:unbind", &keyname
, &function
))
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
;
1691 remove_keybinding(areawin
->area
, keyname
, function
);
1692 return PyString_FromString(keyname
);
1695 /*--------------------------------------------------------------*/
1697 /*--------------------------------------------------------------*/
1699 static PyObject
*xc_pause(PyObject
*self
, PyObject
*args
)
1703 if (!PyArg_ParseTuple(args
, "f:pause", &delay
))
1706 usleep((int)(1e6
* delay
));
1707 return PyInt_FromLong((int)(1e6
* delay
));
1710 /*--------------------------------------------------------------*/
1711 /* active refresh */
1712 /*--------------------------------------------------------------*/
1714 static PyObject
*xc_refresh(PyObject
*self
, PyObject
*args
)
1718 if (!PyArg_ParseTuple(args
, ":refresh"))
1721 refresh(NULL
, NULL
, NULL
);
1723 while (XCheckWindowEvent(dpy
, areawin
->window
, ~NoEventMask
, &event
))
1724 XtDispatchEvent(&event
);
1726 return PyInt_FromLong(0L);
1729 /*--------------------------------------------------------------*/
1730 /* Callback procedure for Python-generated buttons */
1731 /*--------------------------------------------------------------*/
1733 int pybutton(Widget w
, caddr_t clientdata
, caddr_t calldata
)
1737 sprintf(_STR2
, "buttondict[%ld]()\n", (long int)w
);
1738 status
= PyRun_SimpleString(_STR2
);
1739 refresh(NULL
, NULL
, NULL
);
1743 /*--------------------------------------------------------------*/
1744 /* Add a new button to the specified (by name) cascade menu */
1745 /*--------------------------------------------------------------*/
1747 static PyObject
*xc_newbutton(PyObject
*self
, PyObject
*args
)
1749 const char *pname
= NULL
;
1750 const char *newbname
= NULL
;
1751 const char *pfunction
= NULL
;
1755 Widget newbutton
, cascade
, tbutton
;
1757 if (!PyArg_ParseTuple(args
, "sss:newbutton", &pname
, &newbname
, &pfunction
))
1760 for (i
= 0; i
< MaxMenuWidgets
; i
++) {
1761 tbutton
= menuwidgets
[i
];
1762 cascade
= XtParent(tbutton
);
1763 if (!strcmp(XtName(cascade
), pname
)) break;
1765 if (i
== MaxMenuWidgets
) {
1766 Wprintf("Cannot find specified menu.");
1770 XtnSetArg(XtNfont
, appdata
.xcfont
);
1771 newbutton
= XtCreateWidget(newbname
, XwmenubuttonWidgetClass
,
1774 XtAddCallback (newbutton
, XtNselect
, (XtCallbackProc
)pybutton
, newbutton
);
1775 XtManageChild(newbutton
);
1777 sprintf(_STR2
, "buttondict[%ld] = %s\n", (long int)newbutton
, pfunction
);
1778 status
= PyRun_SimpleString(_STR2
);
1779 return PyInt_FromLong((long)status
);
1784 /*--------------------------------------------------------------*/
1785 /* Callback procedure for Python-generated toolbar tool */
1786 /*--------------------------------------------------------------*/
1788 int pytool(Widget w
, caddr_t clientdata
, caddr_t calldata
)
1792 sprintf(_STR2
, "tooldict[%ld]()\n", (long int)w
);
1793 status
= PyRun_SimpleString(_STR2
);
1794 refresh(NULL
, NULL
, NULL
);
1798 /*--------------------------------------------------------------*/
1799 /* Add a new tool to the toolbar */
1800 /*--------------------------------------------------------------*/
1802 static PyObject
*xc_newtool(PyObject
*self
, PyObject
*args
)
1804 const char *thint
= NULL
;
1805 const char *pixfile
= NULL
;
1806 const char *newtname
= NULL
;
1807 const char *pfunction
= NULL
;
1811 Widget newtool
, cascade
, tbutton
;
1815 attr
.valuemask
= XpmSize
| XpmCloseness
;
1816 attr
.closeness
= 65536;
1818 if (!PyArg_ParseTuple(args
, "sss|s:newtool", &newtname
, &pfunction
, &pixfile
,
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
);
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
);
1837 newtool
= XtCreateWidget(newtname
, XwmenubuttonWidgetClass
, toolbar
, wargs
, n
);
1839 XtAddCallback (newtool
, XtNselect
, (XtCallbackProc
)pybutton
, newtool
);
1840 XtManageChild(newtool
);
1842 sprintf(_STR2
, "tooldict[%ld] = %s\n", (long int)newtool
, pfunction
);
1843 status
= PyRun_SimpleString(_STR2
);
1844 return PyInt_FromLong((long)status
);
1847 /*------------------------------------------------------------------*/
1848 /* Return a list of the widgets in tooldict */
1849 /* (memory for list is allocated here and must be free'd elsewhere) */
1850 /*------------------------------------------------------------------*/
1852 Widget
*pytoolbuttons(int *num_tools
)
1858 if (xcmod
== NULL
) {
1862 rval
= PyRun_ObjString("len(tooldict)");
1867 *num_tools
= (int)PyInt_AsLong(rval
);
1869 /* fprintf(stderr, "num_tools = %d\n", *num_tools); */
1871 if (*num_tools
<= 0) return NULL
;
1873 ptools
= (Widget
*)malloc(*num_tools
* sizeof(Widget
));
1875 for (i
= 0; i
< *num_tools
; i
++) {
1876 sprintf(_STR2
, "tooldict[%d]", i
);
1877 rval
= PyRun_ObjString(_STR2
);
1882 ptools
[i
] = (Widget
)PyInt_AsLong(rval
);
1890 /*----------------------------------------------------------------*/
1891 /* Execute a python command from the key-function pair dictionary */
1892 /*----------------------------------------------------------------*/
1894 int python_key_command(int keystate
)
1898 sprintf(_STR2
, "keydict[%d]\n", keystate
);
1899 rval
= PyRun_ObjString(_STR2
);
1906 sprintf(_STR2
, "keydict[%d]()\n", keystate
);
1907 PyRun_SimpleString(_STR2
);
1908 refresh(NULL
, NULL
, NULL
);
1912 /*--------------------------------------------------------------*/
1913 /* Declaration of the xcircuit Python functions */
1914 /*--------------------------------------------------------------*/
1916 static PyMethodDef xc_methods
[] = {
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},
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},
1944 {"newtool", xc_newtool
, 1},
1946 {"netlist", xc_netlist
, 1},
1947 {NULL
, NULL
} /* sentinel */
1950 /*--------------------------------------------------------------*/
1951 /* Initialize Python interpreter and load all xcircuit methods */
1952 /*--------------------------------------------------------------*/
1953 void init_interpreter()
1955 Py_SetProgramName("XCircuit");
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
);
1967 /*--------------------------------------------------------------*/
1968 /* Exit the Python interpreter */
1969 /*--------------------------------------------------------------*/
1971 void exit_interpreter()
1976 /*--------------------------------------------------------------*/
1977 /* Replace the functions of the simple rcfile.c interpreter. */
1978 /*--------------------------------------------------------------*/
1980 /*----------------------------------------------------------------------*/
1981 /* Execute a single command from a script or from the command line */
1982 /*----------------------------------------------------------------------*/
1984 short execcommand(short pflags
, char *cmdptr
)
1987 PyRun_SimpleString(cmdptr
);
1988 refresh(NULL
, NULL
, NULL
);
1992 /*----------------------------------------------------------------------*/
1993 /* Load the default script (like execscript() but don't allow recursive */
1994 /* loading of the startup script) */
1995 /*----------------------------------------------------------------------*/
1997 void defaultscript()
2000 char *tmp_s
= getenv((const char *)"XCIRCUIT_SRC_DIR");
2002 flags
= LIBOVERRIDE
| LIBLOADED
| FONTOVERRIDE
;
2004 if (!tmp_s
) tmp_s
= SCRIPTS_DIR
;
2005 sprintf(_STR2
, "%s/%s", tmp_s
, STARTUP_FILE
);
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
);
2014 PyRun_SimpleFile(fd
, _STR2
);
2017 /*----------------------------------------------------------------------*/
2018 /* Execute a script */
2019 /*----------------------------------------------------------------------*/
2027 xc_tilde_expand(_STR2
, 249);
2028 if ((fd
= fopen(_STR2
, "r")) != NULL
) {
2029 PyRun_SimpleFile(fd
, _STR2
);
2030 refresh(NULL
, NULL
, NULL
);
2033 Wprintf("Failed to open script file \"%s\"\n", _STR2
);
2037 /*----------------------------------------------------------------------*/
2038 /* Execute the .xcircuitrc startup script */
2039 /*----------------------------------------------------------------------*/
2043 char *userdir
= getenv((const char *)"HOME");
2047 /* Initialize flags */
2051 sprintf(_STR2
, "%s", USER_RC_FILE
); /* Name imported from Makefile */
2053 /* try first in current directory, then look in user's home directory */
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");
2063 PyRun_SimpleFile(fd
, _STR2
);
2065 /* Add the default font if not loaded already */
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
;
2077 if (areawin
->psfont
== -1) areawin
->psfont
= 0;
2079 setdefaultfontmarks();
2081 /* arrange the loaded libraries */
2083 if (!(flags
& (LIBOVERRIDE
| LIBLOADED
)))
2086 /* Add the default colors */
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"));
2104 /* These colors must be enabled whether or not colors are overridden, */
2105 /* because they are needed by the schematic capture system. */
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
));
2113 if (!(flags
& KEYOVERRIDE
))
2114 default_keybindings();
2118 /* #endif HAVE_PYTHON and !TCL_WRAPPER */
2119 /*--------------------------------------------------------------*/