/*--------------------------------------------------------------*/ /* python.c --- Embedded python interpreter for xcircuit */ /* Copyright (c) 2002 Tim Edwards, Johns Hopkins University */ /*--------------------------------------------------------------*/ /* NOTE: These routines work only if python-2.0 is installed. */ /* Requires library file libpython2.0.a. Hopefully */ /* one day there will be a standard libpython${VERSION}.so */ /* so that the whole thing doesn't have to be linked */ /* into the xcircuit executable. . . */ /* */ /* Modeled after demo.c in Python2.0 source Demo/embed */ /*--------------------------------------------------------------*/ #if defined(HAVE_PYTHON) && !defined(TCL_WRAPPER) #include #include #include /* for usleep() */ #include #include #include #include #include "Xw/Xw.h" #include "Xw/MenuBtn.h" #ifdef HAVE_XPM #include #include "lib/pixmaps/q.xpm" #endif PyObject *xcmod; /*----------------------------------------------------------------------*/ /* Local includes */ /*----------------------------------------------------------------------*/ #include "xcircuit.h" #include "menudep.h" #include "colordefs.h" /*----------------------------------------------------------------------*/ /* Function prototype declarations */ /*----------------------------------------------------------------------*/ #include "prototypes.h" static PyObject *xc_new(PyObject *, PyObject *); static PyObject *xc_set(PyObject *, PyObject *); static PyObject *xc_override(PyObject *, PyObject *); static PyObject *xc_library(PyObject *, PyObject *); static PyObject *xc_font(PyObject *, PyObject *); static PyObject *xc_color(PyObject *, PyObject *); static PyObject *xc_pause(PyObject *, PyObject *); static PyObject *xc_refresh(PyObject *, PyObject *); static PyObject *xc_bind(PyObject *, PyObject *); static PyObject *xc_unbind(PyObject *, PyObject *); static PyObject *xc_simplepopup(PyObject *, PyObject *); static PyObject *xc_popupprompt(PyObject *, PyObject *); static PyObject *xc_filepopup(PyObject *, PyObject *); static PyObject *xc_newbutton(PyObject *, PyObject *); static PyObject *xc_page(PyObject *, PyObject *); static PyObject *xc_load(PyObject *, PyObject *); static PyObject *xc_pan(PyObject *, PyObject *); static PyObject *xc_zoom(PyObject *, PyObject *); static PyObject *xc_getcursor(); static PyObject *xc_getwindow(); static PyObject *xc_reset(); static PyObject *xc_netlist(); #ifdef HAVE_XPM static PyObject *xc_newtool(PyObject *, PyObject *); #endif int string_to_type(const char *); /*----------------------------------------------------------------------*/ /* External variable declarations */ /*----------------------------------------------------------------------*/ extern char _STR2[250], _STR[150]; extern fontinfo *fonts; extern short fontcount; extern XCWindowData *areawin; extern Globaldata xobjs; extern short beeper; extern Widget menuwidgets[]; extern Display *dpy; extern keybinding *keylist; extern int number_colors; extern colorindex *colorlist; extern ApplicationData appdata; #ifdef HAVE_XPM extern Widget toolbar; #endif /*----------------------------------------------------------------------*/ short flags = -1; #define LIBOVERRIDE 1 #define LIBLOADED 2 #define COLOROVERRIDE 4 #define FONTOVERRIDE 8 #define KEYOVERRIDE 16 /*----------------------------------------------------------------*/ /* Similar to "PyRun_SimpleString()" but returns a PyObject value */ /* rather than a status word. */ /*----------------------------------------------------------------*/ PyObject *PyRun_ObjString(char *string) { PyObject *m, *d, *v; m = PyImport_AddModule("__main__"); if (m == NULL) return NULL; d = PyModule_GetDict(m); v = PyRun_String(string, Py_file_input, d, d); return v; } /*--------------------------------------------------------------*/ /* Define all of the xcircuit functions available to Python */ /* Currently this does the bare minimum of having Python do the */ /* argument parsing; ideally, we would like to be doing more */ /* fundamental processing here. */ /*--------------------------------------------------------------*/ /*--------------------------------------------------------------*/ /* Extract text from a popup and call the indicated python */ /* function. If there is no text, function is called without */ /* arguments. */ /*--------------------------------------------------------------*/ void pypromptvalue(Widget w, char *functionptr) { if (strlen(_STR2) == 0) sprintf(_STR, "%s()\n", functionptr); else sprintf(_STR, "%s('%s')\n", functionptr, _STR2); PyRun_SimpleString(_STR); refresh(NULL, NULL, NULL); } /*--------------------------------------------------------------*/ /* Pop up a prompt, and return the value to the indicated */ /* python function. */ /*--------------------------------------------------------------*/ static PyObject *pypopupprompt(PyObject *self, PyObject *args, const char *dofile, char *displaystr) { const char *pfunction = NULL; const char *prompt = NULL; buttonsave *savebutton; if (!PyArg_ParseTuple(args, "ss:popupprompt", &prompt, &pfunction)) return PyInt_FromLong(-1L); savebutton = getgeneric(NULL, NULL, (void *)pfunction); popupprompt(areawin->area, (char *)prompt, displaystr, pypromptvalue, savebutton, dofile); return PyInt_FromLong(0L); } /*--------------------------------------------------------------*/ /* Wrappers for pypopuprompt() */ /*--------------------------------------------------------------*/ static PyObject *xc_popupprompt(PyObject *self, PyObject *args) { return pypopupprompt(self, args, NULL, ""); } static PyObject *xc_filepopup(PyObject *self, PyObject *args) { return pypopupprompt(self, args, "", ""); } static PyObject *xc_simplepopup(PyObject *self, PyObject *args) { _STR2[0] = '\0'; return pypopupprompt(self, args, False, NULL); } /*--------------------------------------------------------------*/ /* Create objects and return a handle to that object in the */ /* form of a Python integer Object. */ /*--------------------------------------------------------------*/ static PyObject *xc_new(PyObject *self, PyObject *args) { const char *etype; int type; genericptr *newgen; arcptr *newarc; splineptr *newspline; polyptr *newpoly; labelptr *newlabel; pathptr *newpath; objinstptr *newobjinst; if (!PyArg_ParseTuple(args, "s:newelement", &etype)) return NULL; switch(type = string_to_type(etype)) { case ARC: NEW_ARC(newarc, topobject); arcdefaults(*newarc, 0, 0); newgen = (genericptr *)newarc; break; case SPLINE: NEW_SPLINE(newspline, topobject); splinedefaults(*newspline, 0, 0); newgen = (genericptr *)newspline; break; case POLYGON: NEW_POLY(newpoly, topobject); polydefaults(*newpoly, 4, 0, 0); newgen = (genericptr *)newpoly; break; case LABEL: NEW_LABEL(newlabel, topobject); labeldefaults(*newlabel, 0, 0, 0); newgen = (genericptr *)newlabel; break; case PATH: NEW_PATH(newpath, topobject); pathdefaults(*newpath, 0, 0); newgen = (genericptr *)newpath; break; case OBJINST: NEW_OBJINST(newobjinst, topobject); instancedefaults(*newobjinst, NULL, 0, 0); newgen = (genericptr *)newobjinst; break; default: PyErr_SetString(PyExc_TypeError, "newelement() 2nd argument must be a valid element type"); return NULL; } incr_changes(topobject); invalidate_netlist(topobject); return PyInt_FromLong((long)(*newgen)); } /*--------------------------------------------------------------*/ /* Convert object type to a string */ /*--------------------------------------------------------------*/ char *type_to_string(int type) { char *retstr = NULL; switch(type) { case LABEL: retstr = malloc(6); strcpy(retstr, "Label"); break; case POLYGON: retstr = malloc(8); strcpy(retstr, "Polygon"); break; case SPLINE: retstr = malloc(12); strcpy(retstr, "Bezier Curve"); break; case OBJINST: retstr = malloc(16); strcpy(retstr, "Object Instance"); break; case PATH: retstr = malloc(5); strcpy(retstr, "Path"); break; case ARC: retstr = malloc(4); strcpy(retstr, "Arc"); break; } return retstr; } /*--------------------------------------------------------------*/ /* Convert a string to an element type */ /*--------------------------------------------------------------*/ int string_to_type(const char *etype) { if (!strcmp(etype, "Arc")) return ARC; else if (!strcmp(etype, "Bezier Curve")) return SPLINE; else if (!strcmp(etype, "Polygon")) return POLYGON; else if (!strcmp(etype, "Label")) return LABEL; else if (!strcmp(etype, "Path")) return PATH; else if (!strcmp(etype, "Object Instance")) return OBJINST; else return -1; } /*--------------------------------------------------------------*/ /* Convert color index to 3-tuple and vice versa */ /* We assume that this color exists in the color table. */ /*--------------------------------------------------------------*/ PyObject *PyIndexToRGB(int cidx) { int i; PyObject *RGBTuple; if (cidx < 0) { /* Handle "default color" */ return PyString_FromString("Default"); } for (i = 0; i < number_colors; i++) { if (cidx == colorlist[i].color.pixel) { RGBTuple = PyTuple_New(3); PyTuple_SetItem(RGBTuple, 0, PyInt_FromLong((long)(colorlist[i].color.red / 256))); PyTuple_SetItem(RGBTuple, 1, PyInt_FromLong((long)(colorlist[i].color.green / 256))); PyTuple_SetItem(RGBTuple, 2, PyInt_FromLong((long)(colorlist[i].color.blue / 256))); return RGBTuple; } } PyErr_SetString(PyExc_TypeError, "invalid or unknown color index"); return NULL; } /*--------------------------------------------------------------*/ /* Convert color 3-tuple (RGB) or name to a color index */ /*--------------------------------------------------------------*/ int PyRGBToIndex(PyObject *cobj) { PyObject *tobj; int ccolor, r, g, b; if (PyTuple_Check(cobj) && PyTuple_Size(cobj) == 3) { /* RGB 3-tuple */ tobj = PyTuple_GetItem(cobj, 0); if (PyFloat_Check(tobj)) { r = (int)(65535 * (float)PyFloat_AsDouble(tobj)); g = (int)(65535 * (float)PyFloat_AsDouble(PyTuple_GetItem(cobj, 1))); b = (int)(65535 * (float)PyFloat_AsDouble(PyTuple_GetItem(cobj, 2))); } else if (PyInt_Check(tobj)) { r = (int)(256 * PyInt_AsLong(tobj)); g = (int)(256 * PyInt_AsLong(PyTuple_GetItem(cobj, 1))); b = (int)(256 * PyInt_AsLong(PyTuple_GetItem(cobj, 2))); } else { PyErr_SetString(PyExc_TypeError, "tuple components must be integer or float"); return -1; } ccolor = rgb_alloccolor(r, g, b); } else if (PyString_Check(cobj)) { /* color name */ ccolor = xc_alloccolor(PyString_AsString(cobj)); } else if (PyInt_Check(cobj)) { /* index (for backward compatibility) */ ccolor = (int)PyInt_AsLong(cobj); } else { PyErr_SetString(PyExc_TypeError, "argument must be a string or 3-tuple"); return -1; } addnewcolorentry(ccolor); return ccolor; } /*--------------------------------------------------------------*/ /* Convert a Python list to a stringpart* */ /*--------------------------------------------------------------*/ stringpart *PySetStringParts(PyObject *dval) { PyObject *lstr, *litem, *ditem, *sitem, *titem; int i, j, llen; stringpart *strptr, *newpart; char *string; /* If we pass a string, create a list of size 1 to hold the string. */ /* Otherwise, the argument must be a list. */ if (PyList_Check(dval)) { lstr = dval; } else { if (PyString_Check(dval)) { lstr = PyList_New(1); PyList_SetItem(lstr, 0, dval); } else { PyErr_SetString(PyExc_TypeError, "argument must be a string or a list"); return NULL; } } strptr = NULL; llen = PyList_Size(lstr); for (i = 0; i < llen; i++) { newpart = makesegment(&strptr, NULL); newpart->nextpart = NULL; litem = PyList_GetItem(lstr, i); if (PyDict_Check(litem)) { if ((ditem = PyDict_GetItemString(litem, "Parameter")) != NULL) { newpart->type = PARAM_START; newpart->data.string = strdup(PyString_AsString(ditem)); } else if ((ditem = PyDict_GetItemString(litem, "Font")) != NULL) { newpart->type = FONT_NAME; string = PyString_AsString(ditem); for (j = 0; j < fontcount; j++) if (!strcmp(fonts[j].psname, string)) break; if (j == fontcount) loadfontfile(string); newpart->data.font = j; } else if ((ditem = PyDict_GetItemString(litem, "Kern")) != NULL) { newpart->type = KERN; newpart->data.kern[0] = (int)PyInt_AsLong(PyTuple_GetItem(ditem, 0)); newpart->data.kern[1] = (int)PyInt_AsLong(PyTuple_GetItem(ditem, 1)); } else if ((ditem = PyDict_GetItemString(litem, "Color")) != NULL) { newpart->type = FONT_COLOR; newpart->data.color = PyRGBToIndex(ditem); } else if ((ditem = PyDict_GetItemString(litem, "Font Scale")) != NULL) { newpart->type = FONT_SCALE; newpart->data.scale = (float)PyFloat_AsDouble(ditem); } else if ((ditem = PyDict_GetItemString(litem, "Text")) != NULL) { newpart->type = TEXT_STRING; newpart->data.string = strdup(PyString_AsString(ditem)); } } else if (PyString_Check(litem)) { string = PyString_AsString(litem); if (!strcmp(string, "End Parameter")) { newpart->type = PARAM_END; newpart->data.string = (u_char *)NULL; } else if (!strcmp(string, "Tab Stop")) { newpart->type = TABSTOP; } else if (!strcmp(string, "Tab Forward")) { newpart->type = TABFORWARD; } else if (!strcmp(string, "Tab Backward")) { newpart->type = TABBACKWARD; } else if (!strcmp(string, "Return")) { newpart->type = RETURN; } else if (!strcmp(string, "Subscript")) { newpart->type = SUBSCRIPT; } else if (!strcmp(string, "Superscript")) { newpart->type = SUPERSCRIPT; } else if (!strcmp(string, "Normalscript")) { newpart->type = NORMALSCRIPT; } else if (!strcmp(string, "Underline")) { newpart->type = UNDERLINE; } else if (!strcmp(string, "Overline")) { newpart->type = OVERLINE; } else if (!strcmp(string, "No Line")) { newpart->type = NOLINE; } else if (!strcmp(string, "Half Space")) { newpart->type = HALFSPACE; } else if (!strcmp(string, "Quarter Space")) { newpart->type = QTRSPACE; } else { newpart->type = TEXT_STRING; newpart->data.string = strdup(string); } } } return strptr; } /*--------------------------------------------------------------*/ /* Convert a stringpart* to a Python list */ /*--------------------------------------------------------------*/ PyObject *PyGetStringParts(stringpart *thisstring) { PyObject *lstr, *sdict, *stup; int i, llen; stringpart *strptr; llen = stringparts(thisstring); lstr = PyList_New(llen); for (strptr = thisstring, i = 0; strptr != NULL; strptr = strptr->nextpart, i++) { switch(strptr->type) { case TEXT_STRING: sdict = PyDict_New(); PyDict_SetItem(sdict, PyString_FromString("Text"), PyString_FromString(strptr->data.string)); PyList_SetItem(lstr, i, sdict); break; case PARAM_START: sdict = PyDict_New(); PyDict_SetItem(sdict, PyString_FromString("Parameter"), PyString_FromString(strptr->data.string)); PyList_SetItem(lstr, i, sdict); break; case PARAM_END: PyList_SetItem(lstr, i, PyString_FromString("End Parameter")); break; case FONT_NAME: sdict = PyDict_New(); PyDict_SetItem(sdict, PyString_FromString("Font"), PyString_FromString(fonts[strptr->data.font].psname)); PyList_SetItem(lstr, i, sdict); break; case FONT_SCALE: sdict = PyDict_New(); PyDict_SetItem(sdict, PyString_FromString("Font Scale"), PyFloat_FromDouble((double)strptr->data.scale)); PyList_SetItem(lstr, i, sdict); break; case KERN: sdict = PyDict_New(); stup = PyTuple_New(2); PyTuple_SetItem(stup, 0, PyInt_FromLong((long)strptr->data.kern[0])); PyTuple_SetItem(stup, 1, PyInt_FromLong((long)strptr->data.kern[1])); PyDict_SetItem(sdict, PyString_FromString("Kern"), stup); PyList_SetItem(lstr, i, sdict); break; case FONT_COLOR: stup = PyIndexToRGB(strptr->data.color); if (stup != NULL) { sdict = PyDict_New(); PyDict_SetItem(sdict, PyString_FromString("Color"), stup); PyList_SetItem(lstr, i, sdict); } break; case TABSTOP: PyList_SetItem(lstr, i, PyString_FromString("Tab Stop")); break; case TABFORWARD: PyList_SetItem(lstr, i, PyString_FromString("Tab Forward")); break; case TABBACKWARD: PyList_SetItem(lstr, i, PyString_FromString("Tab Backward")); break; case RETURN: PyList_SetItem(lstr, i, PyString_FromString("Return")); break; case SUBSCRIPT: PyList_SetItem(lstr, i, PyString_FromString("Subscript")); break; case SUPERSCRIPT: PyList_SetItem(lstr, i, PyString_FromString("Superscript")); break; case NORMALSCRIPT: PyList_SetItem(lstr, i, PyString_FromString("Normalscript")); break; case UNDERLINE: PyList_SetItem(lstr, i, PyString_FromString("Underline")); break; case OVERLINE: PyList_SetItem(lstr, i, PyString_FromString("Overline")); break; case NOLINE: PyList_SetItem(lstr, i, PyString_FromString("No Line")); break; case HALFSPACE: PyList_SetItem(lstr, i, PyString_FromString("Half Space")); break; case QTRSPACE: PyList_SetItem(lstr, i, PyString_FromString("Quarter Space")); break; } } return lstr; } /*--------------------------------------------------------------*/ /* Check if the handle (integer) is an existing element */ /*--------------------------------------------------------------*/ genericptr *CheckHandle(PyObject *ehandle) { genericptr *gelem; int i, j; long int eaddr; objectptr thisobj; Library *thislib; eaddr = PyInt_AsLong(ehandle); for (gelem = topobject->plist; gelem < topobject->plist + topobject->parts; gelem++) if ((long int)(*gelem) == eaddr) goto exists; /* Okay, it isn't in topobject. Try all other pages. */ for (i = 0; i < xobjs.pages; i++) { if (xobjs.pagelist[i]->pageinst == NULL) continue; thisobj = xobjs.pagelist[i]->pageinst->thisobject; for (gelem = thisobj->plist; gelem < thisobj->plist + thisobj->parts; gelem++) if ((long int)(*gelem) == eaddr) goto exists; } /* Still not found? Maybe in a library */ for (i = 0; i < xobjs.numlibs; i++) { thislib = xobjs.userlibs + i; for (j = 0; j < thislib->number; j++) { thisobj = thislib->library[j]; for (gelem = thisobj->plist; gelem < thisobj->plist + thisobj->parts; gelem++) if ((long int)(*gelem) == eaddr) goto exists; } } /* Either in the delete list (where we don't want to go) or */ /* is an invalid number. */ return NULL; exists: return gelem; } /*--------------------------------------------------------------*/ /* Check if the handle (integer) is an existing page */ /*--------------------------------------------------------------*/ objectptr CheckPageHandle(PyObject *ehandle) { int pageno; long int eaddr; eaddr = PyInt_AsLong(ehandle); pageno = is_page((objectptr)eaddr); if (pageno < 0) return NULL; return (objectptr)eaddr; } /*--------------------------------------------------------------*/ /* Form a 2-tuple from a pair of integers. */ /*--------------------------------------------------------------*/ static PyObject *make_pair(XPoint *thispoint) { PyObject *dtup; dtup = PyTuple_New(2); PyTuple_SetItem(dtup, 0, PyInt_FromLong((long)(thispoint->x))); PyTuple_SetItem(dtup, 1, PyInt_FromLong((long)(thispoint->y))); return dtup; } /*--------------------------------------------------------------*/ /* Get the properties of a page (returned as a dictionary) */ /*--------------------------------------------------------------*/ static PyObject *xc_getpage(PyObject *self, PyObject *args) { Pagedata *thispage; PyObject *rdict, *dlist; int pageno = areawin->page + 1, i; if (!PyArg_ParseTuple(args, "|d:getpage", &pageno)) return NULL; if (pageno <= 0 || pageno > xobjs.pages) return NULL; else pageno--; thispage = xobjs.pagelist[pageno]; rdict = PyDict_New(); PyDict_SetItem(rdict, PyString_FromString("filename"), PyString_FromString(thispage->filename)); PyDict_SetItem(rdict, PyString_FromString("page label"), PyString_FromString(thispage->pageinst->thisobject->name)); PyDict_SetItem(rdict, PyString_FromString("output scale"), PyFloat_FromDouble((double)thispage->outscale)); /* To be done: change these from internal units to "natural" units */ PyDict_SetItem(rdict, PyString_FromString("grid space"), PyFloat_FromDouble((double)thispage->gridspace)); PyDict_SetItem(rdict, PyString_FromString("snap space"), PyFloat_FromDouble((double)thispage->snapspace)); PyDict_SetItem(rdict, PyString_FromString("orientation"), PyInt_FromLong((long)thispage->orient)); PyDict_SetItem(rdict, PyString_FromString("output mode"), PyInt_FromLong((long)thispage->pmode)); PyDict_SetItem(rdict, PyString_FromString("coordinate style"), PyInt_FromLong((long)thispage->coordstyle)); PyDict_SetItem(rdict, PyString_FromString("page size"), make_pair(&(thispage->pagesize))); PyDict_SetItem(rdict, PyString_FromString("drawing scale"), make_pair(&(thispage->drawingscale))); return rdict; } /*--------------------------------------------------------------*/ /* Get the properties of a library (returned as a dictionary) */ /*--------------------------------------------------------------*/ static PyObject *xc_getlibrary(PyObject *self, PyObject *args) { PyObject *rdict, *dlist; const char *lname = NULL; objectptr *curlib = NULL, thisobj; char *errptr; int i, lpage; int curobjs; if (!PyArg_ParseTuple(args, "s:getlibrary", &lname)) return NULL; lpage = strtol(lname, &errptr, 10); if (*lname != '\0' && *errptr == '\0' && lpage <= xobjs.numlibs && lpage > 0) { /* numerical */ curlib = xobjs.userlibs[lpage - 1].library; } else { for (lpage = 0; lpage < xobjs.numlibs; lpage++) { if (!strcmp(lname, xobjs.libtop[lpage + LIBRARY]->thisobject->name)) { curlib = xobjs.userlibs[lpage - 1].library; break; } else if (!strncmp(xobjs.libtop[lpage + LIBRARY]->thisobject->name, "Library: ", 9)) { if (!strcmp(lname, xobjs.libtop[lpage + LIBRARY]->thisobject->name + 9)) { curlib = xobjs.userlibs[lpage - 1].library; break; } } } } if (curlib == NULL) { PyErr_SetString(PyExc_TypeError, "getlibrary() 2nd argument must be a library page or name"); return NULL; } curobjs = xobjs.userlibs[lpage - 1].number; /* Argument to getlibrary() can be a library name or library page # */ rdict = PyDict_New(); PyDict_SetItem(rdict, PyString_FromString("name"), PyString_FromString(xobjs.libtop[lpage + LIBRARY]->thisobject->name)); if (curobjs > 0) { dlist = PyList_New(curobjs); for (i = 0; i < curobjs; i++) { thisobj = *(curlib + i); PyList_SetItem(dlist, i, PyString_FromString(thisobj->name)); } PyDict_SetItem(rdict, PyString_FromString("objects"), dlist); } return rdict; } /*--------------------------------------------------------------*/ /* Get the properties of an object (returned as a dictionary) */ /*--------------------------------------------------------------*/ static PyObject *xc_getobject(PyObject *self, PyObject *args) { objectptr thisobj = NULL, *libobj; oparamptr ops; PyObject *rdict, *dlist, *tpos; const char *oname; int i, j, k, nparam; if (!PyArg_ParseTuple(args, "s:getobject", &oname)) return NULL; for (k = 0; k < xobjs.numlibs; k++) { for (j = 0; j < xobjs.userlibs[k].number; j++) { libobj = xobjs.userlibs[k].library + j; if (!strcmp(oname, (*libobj)->name)) { thisobj = *libobj; break; } } if (thisobj != NULL) break; } if (thisobj == NULL) { /* try the page objects */ for (k = 0; k < xobjs.pages; k++) { if (xobjs.pagelist[k]->pageinst != NULL) if (!strcmp(oname, xobjs.pagelist[k]->pageinst->thisobject->name)) break; } if (k == xobjs.pages) return NULL; /* not found */ } /* return all the object's properties as a dictionary */ rdict = PyDict_New(); PyDict_SetItem(rdict, PyString_FromString("name"), PyString_FromString(thisobj->name)); PyDict_SetItem(rdict, PyString_FromString("width"), PyInt_FromLong((long)(thisobj->bbox.width))); PyDict_SetItem(rdict, PyString_FromString("height"), PyInt_FromLong((long)(thisobj->bbox.height))); PyDict_SetItem(rdict, PyString_FromString("viewscale"), PyFloat_FromDouble((double)(thisobj->viewscale))); tpos = PyTuple_New(2); PyTuple_SetItem(tpos, 0, PyInt_FromLong((long)thisobj->bbox.lowerleft.x)); PyTuple_SetItem(tpos, 1, PyInt_FromLong((long)thisobj->bbox.lowerleft.y)); PyDict_SetItem(rdict, PyString_FromString("boundingbox"), tpos); tpos = PyTuple_New(2); PyTuple_SetItem(tpos, 0, PyInt_FromLong((long)thisobj->pcorner.x)); PyTuple_SetItem(tpos, 1, PyInt_FromLong((long)thisobj->pcorner.y)); PyDict_SetItem(rdict, PyString_FromString("viewcorner"), tpos); dlist = PyList_New(thisobj->parts); for (i = 0; i < thisobj->parts; i++) PyList_SetItem(dlist, i, PyInt_FromLong((long)(*(thisobj->plist + i)))); PyDict_SetItem(rdict, PyString_FromString("parts"), dlist); nparam = get_num_params(thisobj); if (nparam > 0) { dlist = PyList_New(nparam); i = 0; for (ops = thisobj->params; ops != NULL; ops = ops->next) { i++; if (ops->type == XC_INT) PyList_SetItem(dlist, i, PyInt_FromLong((long)(ops->parameter.ivalue))); else if (ops->type == XC_FLOAT) PyList_SetItem(dlist, i, PyFloat_FromDouble((double)(ops->parameter.fvalue))); else if (ops->type == XC_STRING) PyList_SetItem(dlist, i, PyGetStringParts(ops->parameter.string)); } PyDict_SetItem(rdict, PyString_FromString("parameters"), dlist); } return rdict; } /*--------------------------------------------------------------*/ /* Reset the current page */ /*--------------------------------------------------------------*/ static PyObject *xc_reset() { resetbutton(NULL, (pointertype)0, NULL); return PyInt_FromLong(0L); } /*--------------------------------------------------------------*/ /* Get a netlist */ /*--------------------------------------------------------------*/ extern PyObject *pyglobals(objectptr); extern PyObject *pytoplevel(objectptr); static PyObject *xc_netlist() { PyObject *rdict = NULL; if (updatenets(areawin->topinstance, FALSE) <= 0) { PyErr_SetString(PyExc_TypeError, "Error: Check circuit for infinite recursion."); return NULL; } rdict = PyDict_New(); PyDict_SetItem(rdict, PyString_FromString("globals"), pyglobals(topobject)); PyDict_SetItem(rdict, PyString_FromString("circuit"), pytoplevel(topobject)); return rdict; } /*--------------------------------------------------------------*/ /* Load the specified file */ /*--------------------------------------------------------------*/ static PyObject *xc_load(PyObject *self, PyObject *args) { char *filename; int pageno = 0, savepage; if (!PyArg_ParseTuple(args, "s|i:load", &filename, &pageno)) return PyInt_FromLong((long)areawin->page); if (--pageno < 0) pageno = areawin->page; savepage = areawin->page; strcpy(_STR2, filename); if (savepage != pageno) newpage(pageno); startloadfile(-1); if (savepage != pageno) newpage(savepage); return PyString_FromString(filename); } /*--------------------------------------------------------------*/ /* Go to the specified page */ /*--------------------------------------------------------------*/ static PyObject *xc_page(PyObject *self, PyObject *args) { int pageno; if (!PyArg_ParseTuple(args, "i:page", &pageno)) return PyInt_FromLong((long)areawin->page); newpage(pageno - 1); return PyInt_FromLong((long)pageno); } /*--------------------------------------------------------------*/ /* Zoom */ /*--------------------------------------------------------------*/ static PyObject *xc_zoom(PyObject *self, PyObject *args) { float factor, save; if (!PyArg_ParseTuple(args, "f:zoom", &factor)) return NULL; if (factor <= 0) { PyErr_SetString(PyExc_TypeError, "Argument must be positive."); return NULL; } save = areawin->zoomfactor; if (factor < 1.0) { areawin->zoomfactor = 1.0 / factor; zoomout(0, 0); /* Needs to be fixed---give x, y for drag fn */ } else { areawin->zoomfactor = factor; zoomin(0, 0); /* Needs to be fixed---see above */ } areawin->zoomfactor = save; return PyFloat_FromDouble((double)topobject->viewscale); } /*--------------------------------------------------------------*/ /* Pan */ /*--------------------------------------------------------------*/ static PyObject *xc_pan(PyObject *self, PyObject *args) { PyObject *cornerpos, *xobj, *yobj = NULL, *pval; int x, y; XPoint upoint, wpoint; if (!PyArg_ParseTuple(args, "O|O:pan", &xobj, &yobj)) return NULL; if (yobj == NULL) { if (PyTuple_Check(xobj) && PyTuple_Size(xobj) == 2) { if ((pval = PyTuple_GetItem(xobj, 0)) != NULL) upoint.x = PyInt_AsLong(pval); if ((pval = PyTuple_GetItem(xobj, 1)) != NULL) upoint.y = PyInt_AsLong(pval); } else return NULL; } else { upoint.x = PyInt_AsLong(xobj); upoint.y = PyInt_AsLong(yobj); } user_to_window(upoint, &wpoint); panbutton((u_int)5, wpoint.x, wpoint.y, 0.33); /* fixed fraction */ cornerpos = PyTuple_New(2); PyTuple_SetItem(cornerpos, 0, PyInt_FromLong((long)areawin->pcorner.x)); PyTuple_SetItem(cornerpos, 1, PyInt_FromLong((long)areawin->pcorner.y)); return cornerpos; } /*--------------------------------------------------------------*/ /* Get the window size */ /*--------------------------------------------------------------*/ static PyObject *xc_getwindow() { PyObject *windowsize; windowsize = PyTuple_New(2); PyTuple_SetItem(windowsize, 0, PyInt_FromLong((long)areawin->width)); PyTuple_SetItem(windowsize, 1, PyInt_FromLong((long)areawin->height)); return windowsize; } /*--------------------------------------------------------------*/ /* Get the cursor position */ /*--------------------------------------------------------------*/ static PyObject *xc_getcursor() { PyObject *cursorpos; XPoint newpos; newpos = UGetCursorPos(); u2u_snap(&newpos); cursorpos = PyTuple_New(2); PyTuple_SetItem(cursorpos, 0, PyInt_FromLong((long)newpos.x)); PyTuple_SetItem(cursorpos, 1, PyInt_FromLong((long)newpos.y)); return cursorpos; } /*--------------------------------------------------------------*/ /* Get the properties of an element (returned as a dictionary) */ /*--------------------------------------------------------------*/ static PyObject *xc_getattr(PyObject *self, PyObject *args) { genericptr *gelem; PyObject *ehandle, *rdict, *dlist, *lstr, *sdict, *stup; int i, llen; char *tstr; stringpart *strptr; if (!PyArg_ParseTuple(args, "O:getattr", &ehandle)) return NULL; /* Check to make sure that handle exists! */ if ((gelem = CheckHandle(ehandle)) == NULL) { PyErr_SetString(PyExc_TypeError, "Argument must be a valid handle to an element."); return NULL; } /* return the element's properties as a dictionary */ rdict = PyDict_New(); tstr = type_to_string((*gelem)->type); if (tstr == NULL) { PyErr_SetString(PyExc_TypeError, "Element type is unknown."); return NULL; } PyDict_SetItem(rdict, PyString_FromString("type"), PyString_FromString(tstr)); free(tstr); lstr = PyIndexToRGB((*gelem)->color); if (lstr != NULL) PyDict_SetItem(rdict, PyString_FromString("color"), lstr); switch(ELEMENTTYPE(*gelem)) { case LABEL: PyDict_SetItem(rdict, PyString_FromString("position"), make_pair(&(TOLABEL(gelem)->position))); PyDict_SetItem(rdict, PyString_FromString("rotation"), PyFloat_FromDouble((double)TOLABEL(gelem)->rotation)); PyDict_SetItem(rdict, PyString_FromString("scale"), PyFloat_FromDouble((double)TOLABEL(gelem)->scale)); PyDict_SetItem(rdict, PyString_FromString("anchor"), PyInt_FromLong((long)TOLABEL(gelem)->anchor)); PyDict_SetItem(rdict, PyString_FromString("pin"), PyInt_FromLong((long)TOLABEL(gelem)->pin)); lstr = PyGetStringParts(TOLABEL(gelem)->string); PyDict_SetItem(rdict, PyString_FromString("string"), lstr); break; case POLYGON: PyDict_SetItem(rdict, PyString_FromString("style"), PyInt_FromLong((long)TOPOLY(gelem)->style)); PyDict_SetItem(rdict, PyString_FromString("linewidth"), PyFloat_FromDouble((double)TOPOLY(gelem)->width)); dlist = PyList_New(TOPOLY(gelem)->number); for (i = 0; i < TOPOLY(gelem)->number; i++) { PyList_SetItem(dlist, i, make_pair(&(TOPOLY(gelem)->points[i]))); } PyDict_SetItem(rdict, PyString_FromString("points"), dlist); break; case ARC: PyDict_SetItem(rdict, PyString_FromString("style"), PyInt_FromLong((long)TOARC(gelem)->style)); PyDict_SetItem(rdict, PyString_FromString("linewidth"), PyFloat_FromDouble((double)TOARC(gelem)->width)); PyDict_SetItem(rdict, PyString_FromString("radius"), PyInt_FromLong((long)TOARC(gelem)->radius)); PyDict_SetItem(rdict, PyString_FromString("minor axis"), PyInt_FromLong((long)TOARC(gelem)->yaxis)); PyDict_SetItem(rdict, PyString_FromString("start angle"), PyFloat_FromDouble((double)TOARC(gelem)->angle1)); PyDict_SetItem(rdict, PyString_FromString("end angle"), PyFloat_FromDouble((double)TOARC(gelem)->angle2)); PyDict_SetItem(rdict, PyString_FromString("position"), make_pair(&(TOARC(gelem)->position))); break; case SPLINE: PyDict_SetItem(rdict, PyString_FromString("style"), PyInt_FromLong((long)TOSPLINE(gelem)->style)); PyDict_SetItem(rdict, PyString_FromString("linewidth"), PyFloat_FromDouble((double)TOSPLINE(gelem)->width)); dlist = PyList_New(4); for (i = 0; i < 4; i++) { PyList_SetItem(dlist, i, make_pair(&(TOSPLINE(gelem)->ctrl[i]))); } PyDict_SetItem(rdict, PyString_FromString("control points"), dlist); break; case PATH: PyDict_SetItem(rdict, PyString_FromString("style"), PyInt_FromLong((long)TOPATH(gelem)->style)); PyDict_SetItem(rdict, PyString_FromString("linewidth"), PyFloat_FromDouble((double)TOPATH(gelem)->width)); dlist = PyList_New(TOPATH(gelem)->parts); for (i = 0; i < TOPATH(gelem)->parts; i++) { PyList_SetItem(dlist, i, PyInt_FromLong((long)(*(TOPATH(gelem)->plist + i)))); } PyDict_SetItem(rdict, PyString_FromString("parts"), dlist); break; case OBJINST: PyDict_SetItem(rdict, PyString_FromString("position"), make_pair(&(TOOBJINST(gelem)->position))); PyDict_SetItem(rdict, PyString_FromString("rotation"), PyFloat_FromDouble((double)TOOBJINST(gelem)->rotation)); PyDict_SetItem(rdict, PyString_FromString("scale"), PyFloat_FromDouble((double)TOOBJINST(gelem)->scale)); PyDict_SetItem(rdict, PyString_FromString("name"), PyString_FromString(TOOBJINST(gelem)->thisobject->name)); break; } return rdict; } /*--------------------------------------------------------------*/ /* Set properties of an element (supplied as a dictionary) */ /*--------------------------------------------------------------*/ static PyObject *xc_setattr(PyObject *self, PyObject *args) { genericptr *gelem; PyObject *ehandle, *attrdict, *dval, *pval, *qval; int i; if (!PyArg_ParseTuple(args, "OO:setattr", &ehandle, &attrdict)) return NULL; /* Check to make sure that handle exists! */ if ((gelem = CheckHandle(ehandle)) == NULL) return NULL; /* Is the argument a dictionary? */ if (!PyDict_Check(attrdict)) { PyErr_SetString(PyExc_TypeError, "setatrr() 2nd argument must be a dictionary"); return NULL; } /* First, make sure no attempt is made to change the object type. */ if ((dval = PyDict_GetItemString(attrdict, "type")) != NULL) { int dtype = string_to_type(PyString_AsString(dval)); if (dtype < 0) return NULL; if (dtype != ELEMENTTYPE(*gelem)) { PyErr_SetString(PyExc_TypeError, "Attempt to change the type of an object."); return NULL; } } /* Next, look for dictionary strings containing values which apply */ /* to a number of different elements (position, color, etc.) */ if ((dval = PyDict_GetItemString(attrdict, "color")) != NULL) { (*gelem)->color = (short)PyRGBToIndex(dval); } if ((dval = PyDict_GetItemString(attrdict, "position")) != NULL) { if (PyTuple_Check(dval) && PyTuple_Size(dval) == 2) { if ((pval = PyTuple_GetItem(dval, 0)) != NULL) { short xpos = (short)PyInt_AsLong(pval); switch(ELEMENTTYPE(*gelem)) { case ARC: TOARC(gelem)->position.x = xpos; calcarc(TOARC(gelem)); break; case LABEL: TOLABEL(gelem)->position.x = xpos; break; case OBJINST: TOOBJINST(gelem)->position.x = xpos; break; default: PyErr_SetString(PyExc_TypeError, "attempt to set position on Spline, Polygon, or Path"); } } if ((pval = PyTuple_GetItem(dval, 1)) != NULL) { short ypos = (short)PyInt_AsLong(pval); switch(ELEMENTTYPE(*gelem)) { case ARC: TOARC(gelem)->position.y = ypos; calcarc(TOARC(gelem)); break; case LABEL: TOLABEL(gelem)->position.y = ypos; break; case OBJINST: TOOBJINST(gelem)->position.y = ypos; break; default: PyErr_SetString(PyExc_TypeError, "attempt to set position on Spline, Polygon, or Path"); } } } else { PyErr_SetString(PyExc_TypeError, "position must be a tuple containing two integer values"); } } if ((dval = PyDict_GetItemString(attrdict, "style")) != NULL) { short dstyle = (short)PyInt_AsLong(dval); switch(ELEMENTTYPE(*gelem)) { case POLYGON: TOPOLY(gelem)->style = dstyle; break; case PATH: TOPATH(gelem)->style = dstyle; break; case ARC: TOARC(gelem)->style = dstyle; break; case SPLINE: TOSPLINE(gelem)->style = dstyle; break; default: PyErr_SetString(PyExc_TypeError, "attempt to set style on an Object Instance or Label"); } } if ((dval = PyDict_GetItemString(attrdict, "linewidth")) != NULL) { float dwidth = (float)PyFloat_AsDouble(dval); switch(ELEMENTTYPE(*gelem)) { case POLYGON: TOPOLY(gelem)->width = dwidth; break; case PATH: TOPATH(gelem)->width = dwidth; break; case ARC: TOARC(gelem)->width = dwidth; break; case SPLINE: TOSPLINE(gelem)->width = dwidth; break; default: PyErr_SetString(PyExc_TypeError, "attempt to set linewidth on an Object Instance or Label"); } } if ((dval = PyDict_GetItemString(attrdict, "scale")) != NULL) { float dscale = (float)PyFloat_AsDouble(dval); switch(ELEMENTTYPE(*gelem)) { case LABEL: TOLABEL(gelem)->scale = dscale; break; case OBJINST: TOOBJINST(gelem)->scale = dscale; break; default: PyErr_SetString(PyExc_TypeError, "attempt to set scale on something not a Label or Object Instance"); } } if ((dval = PyDict_GetItemString(attrdict, "rotation")) != NULL) { float drot = (float)PyFloat_AsDouble(dval); switch(ELEMENTTYPE(*gelem)) { case LABEL: TOLABEL(gelem)->rotation = drot; break; case OBJINST: TOOBJINST(gelem)->rotation = drot; break; default: PyErr_SetString(PyExc_TypeError, "attempt to set rotation on something not a Label or Object Instance"); } } /* Dictionary entries specific to certain xcircuit types */ switch(ELEMENTTYPE(*gelem)) { case LABEL: if ((dval = PyDict_GetItemString(attrdict, "anchor")) != NULL) { TOLABEL(gelem)->anchor = PyInt_AsLong(dval); } if ((dval = PyDict_GetItemString(attrdict, "string")) != NULL) { freelabel(TOLABEL(gelem)->string); TOLABEL(gelem)->string = PySetStringParts(dval); } if ((dval = PyDict_GetItemString(attrdict, "pin")) != NULL) { TOLABEL(gelem)->pin = PyInt_AsLong(dval); } break; case ARC: if ((dval = PyDict_GetItemString(attrdict, "start angle")) != NULL) { TOARC(gelem)->angle1 = (float)PyFloat_AsDouble(dval); } if ((dval = PyDict_GetItemString(attrdict, "end angle")) != NULL) { TOARC(gelem)->angle2 = (float)PyFloat_AsDouble(dval); } if ((dval = PyDict_GetItemString(attrdict, "radius")) != NULL) { TOARC(gelem)->radius = PyInt_AsLong(dval); } if ((dval = PyDict_GetItemString(attrdict, "minor axis")) != NULL) { TOARC(gelem)->yaxis = PyInt_AsLong(dval); } break; case SPLINE: if ((dval = PyDict_GetItemString(attrdict, "control points")) != NULL) { if (PyList_Check(dval) && PyList_Size(dval) == 4) { for (i = 0; i < 4; i++) { pval = PyList_GetItem(dval, i); if (PyTuple_Check(pval) && PyTuple_Size(pval) == 2) { qval = PyTuple_GetItem(pval, 0); TOSPLINE(gelem)->ctrl[i].x = (short)PyInt_AsLong(qval); qval = PyTuple_GetItem(pval, 1); TOSPLINE(gelem)->ctrl[i].y = (short)PyInt_AsLong(qval); } else { PyErr_SetString(PyExc_TypeError, "must have a tuple of 2 values per point"); break; } } } else { PyErr_SetString(PyExc_TypeError, "must have 4 control points in a list"); break; } } break; case POLYGON: if ((dval = PyDict_GetItemString(attrdict, "points")) != NULL) { if (PyList_Check(dval)) { int number = PyList_Size(dval); if (TOPOLY(gelem)->number != number) { TOPOLY(gelem)->points = (pointlist)realloc( TOPOLY(gelem)->points, number * sizeof(XPoint)); TOPOLY(gelem)->number = number; } for (i = 0; i < number; i++) { pval = PyList_GetItem(dval, i); if (PyTuple_Check(pval) && PyTuple_Size(pval) == 2) { qval = PyTuple_GetItem(pval, 0); TOPOLY(gelem)->points[i].x = (short)PyInt_AsLong(qval); qval = PyTuple_GetItem(pval, 1); TOPOLY(gelem)->points[i].y = (short)PyInt_AsLong(qval); } else { PyErr_SetString(PyExc_TypeError, "must have a tuple of 2 values per point"); break; } } } else { PyErr_SetString(PyExc_TypeError, "points must be in a list of tuples"); break; } } break; } calcbbox(areawin->topinstance); return PyInt_FromLong((long)(*gelem)); } /*--------------------------------------------------------------*/ /* Set various options through the "set" command. */ /* "set