diff --git a/WINGs/python/.cvsignore b/WINGs/python/.cvsignore new file mode 100644 index 00000000..b326ce5d --- /dev/null +++ b/WINGs/python/.cvsignore @@ -0,0 +1,3 @@ +WINGs.c +wings.so +build diff --git a/WINGs/python/Makefile b/WINGs/python/Makefile new file mode 100644 index 00000000..cf8c258f --- /dev/null +++ b/WINGs/python/Makefile @@ -0,0 +1,17 @@ + +all: WINGs.c + python setup.py build + ln -s `find build/ -name wings.so` . + +install: WINGs.c + python setup.py install + +clean: + rm -rf build dist WINGs.c *.o *~ *.so MANIFEST wings.py *.pyc *.pyo core + +dist: + python setup.py sdist + +WINGs.c: WINGs.i + swig -python -noproxy `get-wings-flags --cflags` -I.. -o WINGs.c WINGs.i + diff --git a/WINGs/python/README b/WINGs/python/README new file mode 100644 index 00000000..375cfacd --- /dev/null +++ b/WINGs/python/README @@ -0,0 +1,21 @@ + +This is a python wrapper for the WINGs library. With it you can write python +based programs which will have WINGs based graphic interfaces. + +This module in not built by default. To build it you need python2.1 or later +and swig-1.3.14 or later. + +To build it, first compile and install WINGs. after that run 'make' in this +directory. 'make install' will install the python module into the python tree. + +run test.py or even WINGs.py for an example. + +the code is not yet finished and probably won't do everything you expect it +to do. + +Note: currently the module expects WINGs installed to build. it won't take +the WINGs libraries and header files from the source tree. You need to +install WINGs first. Even if an old version of WINGs is already installed, +you still need to nstall the newly built WINGs, else the python module will +be built against the old version + diff --git a/WINGs/python/WINGs.i b/WINGs/python/WINGs.i new file mode 100644 index 00000000..255f68af --- /dev/null +++ b/WINGs/python/WINGs.i @@ -0,0 +1,677 @@ +%module wings +%{ +#include "WINGs/WINGsP.h" +%} + +%include typemaps.i + +// This tells SWIG to treat char ** as a special case +%typemap(python, in) char ** { + /* Check if is a list */ + if (PyList_Check($input)) { + int size = PyList_Size($input); + int i = 0; + $1 = (char **) wmalloc((size+1)*sizeof(char *)); + for (i = 0; i < size; i++) { + PyObject *o = PyList_GetItem($input, i); + if (PyString_Check(o)) + $1[i] = PyString_AsString(PyList_GetItem($input, i)); + else { + PyErr_SetString(PyExc_TypeError, "list must contain strings"); + wfree($1); + return NULL; + } + } + $1[i] = 0; + } else { + PyErr_SetString(PyExc_TypeError, "not a list"); + return NULL; + } +} +// This cleans up the char ** array we mallocd before the function call +%typemap(python, freearg) char ** { + wfree($1); +} +// This allows a C function to return a char ** as a Python list +%typemap(python, out) char ** { + int len,i; + len = 0; + while ($1[len]) len++; + $result = PyList_New(len); + for (i = 0; i < len; i++) { + PyList_SetItem($result, i, PyString_FromString($1[i])); + } +} + +// Now for some callbacks +%typemap(python, in) PyObject *pyacArgs { + if (PyTuple_Check($input)) { + if (PyTuple_Size($input) != 3) { + PyErr_SetString(PyExc_ValueError, + "wrong number of parameters in tuple. should be 3."); + return NULL; + } else { + PyObject *func = PyTuple_GetItem($input, 1); + if (func!=Py_None && !PyCallable_Check(func)) { + PyErr_SetString(PyExc_TypeError, + "'action' needs to be a callable object!"); + return NULL; + } + } + } else { + PyErr_SetString(PyExc_TypeError, "2nd argument not a tuple!"); + return NULL; + } + $1 = $input; +} + +%typemap(python, in) PyObject *pycArgs { + if (PyTuple_Check($input)) { + if (PyTuple_Size($input) != 2) { + PyErr_SetString(PyExc_ValueError, + "wrong number of parameters in tuple. should be 2."); + return NULL; + } else { + PyObject *func = PyTuple_GetItem($input, 0); + if (func!=Py_None && !PyCallable_Check(func)) { + PyErr_SetString(PyExc_TypeError, + "'action' needs to be a callable object!"); + return NULL; + } + } + } else { + PyErr_SetString(PyExc_TypeError, "2nd argument not a tuple!"); + return NULL; + } + $1 = $input; +} + +// Type mapping for grabbing a FILE * from Python +%typemap(python, in) FILE * { + if (!PyFile_Check($input)) { + PyErr_SetString(PyExc_TypeError, "Need a file!"); + return NULL; + } + $1 = PyFile_AsFile($input); +} + +/* These are for freeing the return of functions that need to be freed + * before returning control to python. */ +%typemap(python, ret) char* WMGetTextFieldText { wfree($1); }; + + +%include exception.i + +%exception pyWMScreenMainLoop { + $function + if (PyErr_Occurred()) + return NULL; +} + +%exception pyWMRunModalLoop { + $function + if (PyErr_Occurred()) + return NULL; +} + +%{ + static int mainLoopDone = 0; +%} + + +%inline %{ + WMScreen *pyWMOpenScreen(const char *display, int simpleapp) + { + Display *dpy = XOpenDisplay(display); + + if (!dpy) { + wwarning("WINGs: could not open display %s", XDisplayName(display)); + return NULL; + } + + if (simpleapp) { + return WMCreateSimpleApplicationScreen(dpy); + } else { + return WMCreateScreen(dpy, DefaultScreen(dpy)); + } + } + + void pyWMScreenMainLoop(WMScreen *scr) + { + XEvent event; + + while (!PyErr_Occurred() && !mainLoopDone) { + WMNextEvent(((W_Screen*)scr)->display, &event); + WMHandleEvent(&event); + } + } + + void pyWMBreakScreenMainLoop(WMScreen *scr) + { + mainLoopDone = 1; + } + + void pyWMRunModalLoop(WMScreen *scr, WMView *view) + { + int oldModalLoop = scr->modalLoop; + WMView *oldModalView = scr->modalView; + + scr->modalView = view; + + scr->modalLoop = 1; + while (!PyErr_Occurred() && scr->modalLoop) { + XEvent event; + + WMNextEvent(scr->display, &event); + WMHandleEvent(&event); + } + + scr->modalView = oldModalView; + scr->modalLoop = oldModalLoop; + } +%} + + +//%rename WMScreenMainLoop _WMScreenMainLoop; +//%rename WMRunModalLoop _WMRunModalLoop; + + +%{ + /* These functions match the prototypes of the normal C callback + * functions. However, we use the clientdata pointer for holding a + * reference to a Python tuple containing (object, funct, clientData). + */ + static void PythonWMActionCallback(WMWidget *widget, void *cdata) + { + PyObject *pyobj, *func, *pydata, *arglist, *tuple, *result; + + tuple = (PyObject*) cdata; + pyobj = PyTuple_GetItem(tuple, 0); + func = PyTuple_GetItem(tuple, 1); + if (func && func!=Py_None) { + pydata = PyTuple_GetItem(tuple, 2); + arglist = Py_BuildValue("(OO)", pyobj, pydata); + result = PyEval_CallObject(func, arglist); + Py_DECREF(arglist); + Py_XDECREF(result); + } + } + + static void PythonWMCallback(void *data) + { + PyObject *func, *pydata, *arglist, *tuple, *result; + + tuple = (PyObject*) data; + func = PyTuple_GetItem(tuple, 0); + if (func && func!=Py_None) { + pydata = PyTuple_GetItem(tuple, 1); + arglist = Py_BuildValue("(O)", pydata); + result = PyEval_CallObject(func, arglist); + Py_DECREF(arglist); + Py_XDECREF(result); + } + } + + static void + pyTextFieldDidBeginEditing(WMTextFieldDelegate *self, WMNotification *notif) + { + PyObject *pyobj, *delegate, *func, *pydata, *arglist, *tuple, *result; + int action; + + tuple = (PyObject*) self->data; + pyobj = PyTuple_GetItem(tuple, 0); + delegate = PyTuple_GetItem(tuple, 1); + if (delegate != Py_None) { + // should we call PyObject_HasAttrString()?? rather not and let + // python raise an exception because the object doesn't has the + // attribute + func = PyObject_GetAttrString(delegate, "didBeginEditing"); + if (func!=NULL && func!=Py_None) { + pydata = PyObject_GetAttrString(delegate, "data"); + if (!pydata) { + Py_INCREF(Py_None); + pydata = Py_None; + } + action = (int)WMGetNotificationClientData(notif); + arglist = Py_BuildValue("(OOi)", pyobj, pydata, action); + result = PyEval_CallObject(func, arglist); + Py_DECREF(pydata); + Py_DECREF(arglist); + Py_XDECREF(result); + } + Py_XDECREF(func); + } + } + + static void + pyTextFieldDidChange(WMTextFieldDelegate *self, WMNotification *notif) + { + PyObject *pyobj, *delegate, *func, *pydata, *arglist, *tuple, *result; + int action; + + tuple = (PyObject*) self->data; + pyobj = PyTuple_GetItem(tuple, 0); + delegate = PyTuple_GetItem(tuple, 1); + if (delegate != Py_None) { + func = PyObject_GetAttrString(delegate, "didChange"); + if (func!=NULL && func!=Py_None) { + pydata = PyObject_GetAttrString(delegate, "data"); + if (!pydata) { + Py_INCREF(Py_None); + pydata = Py_None; + } + action = (int)WMGetNotificationClientData(notif); + arglist = Py_BuildValue("(OOi)", pyobj, pydata, action); + result = PyEval_CallObject(func, arglist); + Py_DECREF(pydata); + Py_DECREF(arglist); + Py_XDECREF(result); + } + Py_XDECREF(func); + } + } + + static void + pyTextFieldDidEndEditing(WMTextFieldDelegate *self, WMNotification *notif) + { + PyObject *pyobj, *delegate, *func, *pydata, *arglist, *tuple, *result; + int action; + + tuple = (PyObject*) self->data; + pyobj = PyTuple_GetItem(tuple, 0); + delegate = PyTuple_GetItem(tuple, 1); + if (delegate != Py_None) { + func = PyObject_GetAttrString(delegate, "didEndEditing"); + if (func!=NULL && func!=Py_None) { + pydata = PyObject_GetAttrString(delegate, "data"); + if (!pydata) { + Py_INCREF(Py_None); + pydata = Py_None; + } + action = (int)WMGetNotificationClientData(notif); + arglist = Py_BuildValue("(OOi)", pyobj, pydata, action); + result = PyEval_CallObject(func, arglist); + Py_DECREF(pydata); + Py_DECREF(arglist); + Py_XDECREF(result); + } + Py_XDECREF(func); + } + } + + static Bool + pyTextFieldShouldBeginEditing(WMTextFieldDelegate *self, WMTextField *tPtr) + { + PyObject *pyobj, *delegate, *func, *pydata, *arglist, *tuple, *result; + Bool retval = False; + + tuple = (PyObject*) self->data; + pyobj = PyTuple_GetItem(tuple, 0); + delegate = PyTuple_GetItem(tuple, 1); + if (delegate != Py_None) { + func = PyObject_GetAttrString(delegate, "shouldBeginEditing"); + if (func!=NULL && func!=Py_None) { + pydata = PyObject_GetAttrString(delegate, "data"); + if (!pydata) { + Py_INCREF(Py_None); + pydata = Py_None; + } + arglist = Py_BuildValue("(OO)", pyobj, pydata); + result = PyEval_CallObject(func, arglist); + if (result!=Py_None && PyInt_AsLong(result)!=0) { + retval = True; + } + Py_DECREF(pydata); + Py_DECREF(arglist); + Py_XDECREF(result); + } + Py_XDECREF(func); + } + + return retval; + } + + static Bool + pyTextFieldShouldEndEditing(WMTextFieldDelegate *self, WMTextField *tPtr) + { + PyObject *pyobj, *delegate, *func, *pydata, *arglist, *tuple, *result; + Bool retval = False; + + tuple = (PyObject*) self->data; + pyobj = PyTuple_GetItem(tuple, 0); + delegate = PyTuple_GetItem(tuple, 1); + if (delegate != Py_None) { + func = PyObject_GetAttrString(delegate, "shouldEndEditing"); + if (func!=NULL && func!=Py_None) { + pydata = PyObject_GetAttrString(delegate, "data"); + if (!pydata) { + Py_INCREF(Py_None); + pydata = Py_None; + } + arglist = Py_BuildValue("(OO)", pyobj, pydata); + result = PyEval_CallObject(func, arglist); + if (result!=Py_None && PyInt_AsLong(result)!=0) { + retval = True; + } + Py_DECREF(pydata); + Py_DECREF(arglist); + Py_XDECREF(result); + } + Py_XDECREF(func); + } + + return retval; + } +%} + +%inline %{ + void pyWMSetWindowCloseAction(WMWindow *win, PyObject *pyacArgs) { + WMSetWindowCloseAction(win, PythonWMActionCallback, (void*)pyacArgs); + Py_INCREF(pyacArgs); + } + + void pyWMSetButtonAction(WMButton *bPtr, PyObject *pyacArgs) { + WMSetButtonAction(bPtr, PythonWMActionCallback, (void*)pyacArgs); + Py_INCREF(pyacArgs); + } + + void pyWMSetScrollerAction(WMScroller *sPtr, PyObject *pyacArgs) { + WMSetScrollerAction(sPtr, PythonWMActionCallback, (void*)pyacArgs); + Py_INCREF(pyacArgs); + } + + void pyWMSetListAction(WMList *lPtr, PyObject *pyacArgs) { + WMSetListAction(lPtr, PythonWMActionCallback, (void*)pyacArgs); + Py_INCREF(pyacArgs); + } + + void pyWMSetListDoubleAction(WMList *lPtr, PyObject *pyacArgs) { + WMSetListDoubleAction(lPtr, PythonWMActionCallback, (void*)pyacArgs); + Py_INCREF(pyacArgs); + } + + void pyWMSetBrowserAction(WMBrowser *bPtr, PyObject *pyacArgs) { + WMSetBrowserAction(bPtr, PythonWMActionCallback, (void*)pyacArgs); + Py_INCREF(pyacArgs); + } + + void pyWMSetBrowserDoubleAction(WMBrowser *bPtr, PyObject *pyacArgs) { + WMSetBrowserDoubleAction(bPtr, PythonWMActionCallback, (void*)pyacArgs); + Py_INCREF(pyacArgs); + } + + void pyWMSetMenuItemAction(WMMenuItem *miPtr, PyObject *pyacArgs) { + WMSetMenuItemAction(miPtr, PythonWMActionCallback, (void*)pyacArgs); + Py_INCREF(pyacArgs); + } + + void pyWMSetPopUpButtonAction(WMPopUpButton *pPtr, PyObject *pyacArgs) { + WMSetPopUpButtonAction(pPtr, PythonWMActionCallback, (void*)pyacArgs); + Py_INCREF(pyacArgs); + } + + void pyWMSetSliderAction(WMSlider *sPtr, PyObject *pyacArgs) { + WMSetSliderAction(sPtr, PythonWMActionCallback, (void*)pyacArgs); + Py_INCREF(pyacArgs); + } + + void pyWMSetRulerMoveAction(WMRuler *rPtr, PyObject *pyacArgs) { + WMSetRulerMoveAction(rPtr, PythonWMActionCallback, (void*)pyacArgs); + Py_INCREF(pyacArgs); + } + + void pyWMSetRulerReleaseAction(WMRuler *rPtr, PyObject *pyacArgs) { + WMSetRulerReleaseAction(rPtr, PythonWMActionCallback, (void*)pyacArgs); + Py_INCREF(pyacArgs); + } + + void pyWMSetColorPanelAction(WMColorPanel *panel, PyObject *pyacArgs) { + WMSetColorPanelAction(panel, (WMAction2*)PythonWMActionCallback, (void*)pyacArgs); + Py_INCREF(pyacArgs); + } + + void* pyWMAddTimerHandler(int miliseconds, PyObject *pycArgs) { + Py_INCREF(pycArgs); + return (void*)WMAddTimerHandler(miliseconds, PythonWMCallback, + (void*)pycArgs); + } + + void* pyWMAddPersistentTimerHandler(int miliseconds, PyObject *pycArgs) { + Py_INCREF(pycArgs); + return (void*)WMAddPersistentTimerHandler(miliseconds, PythonWMCallback, + (void*)pycArgs); + } + + /* this doesn't work. we pass (func, data) as cdata at creation time, but + * only data at destruction, so it won't find it unless we change + * WMDeleteTimerWithClientData() to extract data from the tuple, and this + * requires access to the internals of WINGs + void pyWMDeleteTimerWithClientData(PyObject *pycData) { + WMDeleteTimerWithClientData((void*)pycData); + }*/ + + void pyWMDeleteTimerHandler(void *handlerID) { + WMDeleteTimerHandler((WMHandlerID)handlerID); + } + + void* pyWMAddIdleHandler(PyObject *pycArgs) { + Py_INCREF(pycArgs); + return (void*)WMAddIdleHandler(PythonWMCallback, (void*)pycArgs); + } + + void pyWMDeleteIdleHandler(void *handlerID) { + WMDeleteIdleHandler((WMHandlerID)handlerID); + } + +%} + + +%exception pyWMSetTextFieldDelegate { + $function + if (PyErr_Occurred()) { + return NULL; + } +} + +%inline %{ + void pyWMSetTextFieldDelegate(WMTextField *tPtr, PyObject *txtArgs) { + WMTextFieldDelegate *td; + + if (!txtArgs || !PyTuple_Check(txtArgs) || PyTuple_Size(txtArgs)!=2) { + PyErr_SetString(PyExc_TypeError, "invalid setting of WMTextField " + "delegate. Should be '(self, delegate)'"); + return; + } + // how do I check if txtArgs[1] is an instance of WMTextFieldDelegate? + td = WMGetTextFieldDelegate(tPtr); + if (!td) { + td = (WMTextFieldDelegate*)wmalloc(sizeof(WMTextFieldDelegate)); + td->didBeginEditing = pyTextFieldDidBeginEditing; + td->didChange = pyTextFieldDidChange; + td->didEndEditing = pyTextFieldDidEndEditing; + td->shouldBeginEditing = pyTextFieldShouldBeginEditing; + td->shouldEndEditing = pyTextFieldShouldEndEditing; + } else { + Py_XDECREF((PyObject*)td->data); + } + Py_INCREF(txtArgs); + td->data = txtArgs; + WMSetTextFieldDelegate(tPtr, td); + } +%} + + +%inline %{ + PyObject* pyWMGetTextFieldDelegate(WMTextField *tPtr) { + WMTextFieldDelegate *td; + PyObject *result, *tuple; + + td = WMGetTextFieldDelegate(tPtr); + if (!td) { + Py_INCREF(Py_None); + return Py_None; + } + + tuple = (PyObject*)td->data; + if (!tuple || !PyTuple_Check(tuple) || PyTuple_Size(tuple)!=2) { + PyErr_SetString(PyExc_TypeError, "invalid TextField delegate"); + return NULL; + } + + result = PyTuple_GetItem(tuple, 1); + if (!result) + result = Py_None; + + Py_INCREF(result); + + return result; + } +%} + + +%apply int *INPUT { int *argc }; + +#define Bool int + +%include "WINGs/WUtil.h" + +%include "WINGs/WINGs.h" + +%{ +void +WHandleEvents() +{ + /* Check any expired timers */ + W_CheckTimerHandlers(); + + /* Do idle and timer stuff while there are no input events */ + /* Do not wait for input here. just peek to se if input is available */ + while (!W_HandleInputEvents(False, -1) && W_CheckIdleHandlers()) { + /* dispatch timer events */ + W_CheckTimerHandlers(); + } + + W_HandleInputEvents(True, -1); + + /* Check any expired timers */ + W_CheckTimerHandlers(); +} +%} + +/* rewrite functions originally defined as macros */ +%inline %{ +#undef WMDuplicateArray +WMArray* WMDuplicateArray(WMArray* array) { + return WMCreateArrayWithArray(array); +} + +#undef WMPushInArray +void WMPushInArray(WMArray *array, void *item) { + WMAddToArray(array, item); +} + +#undef WMSetInArray +void* WMSetInArray(WMArray *array, int index, void *item) { + return WMReplaceInArray(array, index, item); +} + +#undef WMRemoveFromArray +int WMRemoveFromArray(WMArray *array, void *item) { + return WMRemoveFromArrayMatching(array, NULL, item); +} + +#undef WMGetFirstInArray +int WMGetFirstInArray(WMArray *array, void *item) { + return WMFindInArray(array, NULL, item); +} + +#undef WMCreateBag +WMBag* WMCreateBag(int size) { + return WMCreateTreeBag(); +} + +#undef WMCreateBagWithDestructor +WMBag* WMCreateBagWithDestructor(int size, WMFreeDataProc *destructor) { + return WMCreateTreeBagWithDestructor(destructor); +} + +#undef WMSetInBag +void* WMSetInBag(WMBag *bag, int index, void *item) { + return WMReplaceInBag(bag, index, item); +} + +#undef WMAddItemToTree +WMTreeNode* WMAddItemToTree(WMTreeNode *parent, void *item) { + return WMInsertItemInTree(parent, -1, item); +} + +#undef WMAddNodeToTree +WMTreeNode* WMAddNodeToTree(WMTreeNode *parent, WMTreeNode *aNode) { + return WMInsertNodeInTree(parent, -1, aNode); +} + +#undef WMGetFirstInTree +/* Returns first tree node that has data == cdata */ +WMTreeNode* WMGetFirstInTree(WMTreeNode *aTree, void *cdata) { + return WMFindInTree(aTree, NULL, cdata); +} + +#undef WMFlushConnection +int WMFlushConnection(WMConnection *cPtr) { + return WMSendConnectionData(cPtr, NULL); +} + +#undef WMGetConnectionQueuedData +WMArray* WMGetConnectionQueuedData(WMConnection *cPtr) { + return WMGetConnectionUnsentData(cPtr); +} + +#undef WMWidgetClass +W_Class WMWidgetClass(WMWidget *widget) { + return (((W_WidgetType*)(widget))->widgetClass); +} + +#undef WMWidgetView +WMView* WMWidgetView(WMWidget *widget) { + return (((W_WidgetType*)(widget))->view); +} + +#undef WMCreateCommandButton +WMButton* WMCreateCommandButton(WMWidget *parent) { + return WMCreateCustomButton(parent, WBBSpringLoadedMask|WBBPushInMask + |WBBPushLightMask|WBBPushChangeMask); +} + +#undef WMCreateRadioButton +WMButton* WMCreateRadioButton(WMWidget *parent) { + return WMCreateButton(parent, WBTRadio); +} + +#undef WMCreateSwitchButton +WMButton* WMCreateSwitchButton(WMWidget *parent) { + return WMCreateButton(parent, WBTSwitch); +} + +#undef WMAddListItem +WMListItem* WMAddListItem(WMList *lPtr, char *text) +{ + return WMInsertListItem(lPtr, -1, text); +} + +#undef WMCreateText +WMText* WMCreateText(WMWidget *parent) { + return WMCreateTextForDocumentType(parent, NULL, NULL); +} + +#undef WMRefreshText +void WMRefreshText(WMText *tPtr) { + return WMThawText(tPtr); +} + +#undef WMClearText +void WMClearText(WMText *tPtr) { + return WMAppendTextStream(tPtr, NULL); +} +%} + + diff --git a/WINGs/python/WINGs.py b/WINGs/python/WINGs.py new file mode 100644 index 00000000..b131e58c --- /dev/null +++ b/WINGs/python/WINGs.py @@ -0,0 +1,644 @@ +#!/usr/bin/env python + +import sys +import wings +import exceptions +from types import * + +# check about None as action for buttonAction/windowCloseAction ... + +################################################################################ +# Exceptions +################################################################################ +class Error(exceptions.Exception): + def __init__(self, msg): + self.msg = msg + def __str__(self): + return self.msg + __repr__ = __str__ + +class WMTimer: + def __init__(self, milliseconds, callback, cdata=None, persistent=0): + if persistent: + self._o = wings.pyWMAddPersistentTimerHandler(milliseconds, (callback, cdata)) + else: + self._o = wings.pyWMAddTimerHandler(milliseconds, (callback, cdata)) + + def __del__(self): + wings.pyWMDeleteTimerHandler(self._o) + #delete = __del__ + +class WMPersistentTimer(WMTimer): + def __init__(self, milliseconds, callback, cdata=None): + WMTimer.__init__(self, milliseconds, callback, cdata, persistent=1) + + +class WMScreen: + __readonly = ('display', 'width', 'height', 'depth') + + def __init__(self, appname, display="", simpleapp=0): + wings.WMInitializeApplication(appname, len(sys.argv), sys.argv) + self._o = wings.pyWMOpenScreen(display, simpleapp) + self.__dict__['display'] = wings.WMScreenDisplay(self._o) + self.__dict__['width'] = wings.WMScreenWidth(self._o) + self.__dict__['height'] = wings.WMScreenHeight(self._o) + self.__dict__['depth'] = wings.WMScreenDepth(self._o) + + def __setattr__(self, name ,value): + if name in self.__readonly: + #raise AttributeError, "'%s' is a read-only WMScreen attribute" % name + raise Error, "'%s' is a read-only WMScreen attribute" % name + self.__dict__[name] = value + + def mainLoop(self): + wings.pyWMScreenMainLoop(self._o) + + def breakMainLoop(self): + wings.pyWMBreakScreenMainLoop(self._o) + + def runModalLoop(self, view): + wings.pyWMRunModalLoop(self._o, view) + + def breakModalLoop(self): + wings.WMBreakModalLoop(self._o) + + def size(self): + return (self.width, self.height) + + +class WMView: + pass + + +class WMWidget(WMView): + def __init__(self): + self._o = None + if self.__class__ == WMWidget: + raise Error, "a WMWidget can't be instantiated directly" + + def __del__(self): + if (self._o != None): + wings.WMDestroyWidget(self._o) + + def resize(self, width, height): + wings.WMResizeWidget(self._o, width, height) + + def move(self, x, y): + wings.WMMoveWidget(self._o, x, y) + + def realize(self): + wings.WMRealizeWidget(self._o) + + def show(self): + wings.WMMapWidget(self._o) + + def hide(self): + wings.WMUnmapWidget(self._o) + + def redisplay(self): + wings.WMRedisplayWidget(self._o) + + def width(self): + return wings.WMWidgetWidth(self._o) + + def height(self): + return wings.WMWidgetHeight(self._o) + + def screen(self): + return wings.WMWidgetScreen(self._o) + + def view(self): + return wings.WMWidgetView(self._o) + + def setFocusTo(self, other): + wings.WMSetFocusToWidget(other._o) + + +class WMWindow(WMWidget): + def __init__(self, screen, name, style=wings.WMTitledWindowMask + |wings.WMClosableWindowMask|wings.WMMiniaturizableWindowMask + |wings.WMResizableWindowMask): + WMWidget.__init__(self) + self._o = wings.WMCreateWindowWithStyle(screen._o, name, style) + + def setMinSize(self, minWidth, minHeight): + wings.WMSetWindowMinSize(self._o, minWidth, minHeight) + + def setMaxSize(self, maxWidth, maxHeight): + wings.WMSetWindowMaxSize(self._o, maxWidth, maxHeight) + + def setInitialPosition(self, x, y): + wings.WMSetWindowInitialPosition(self._o, x, y) + + def setTitle(self, title): + wings.WMSetWindowTitle(self._o, title) + + def setCloseAction(self, action, data=None): + if action!=None and (not callable(action)): + raise Error, "action needs to be a callable object or None" + wings.pyWMSetWindowCloseAction(self._o, (self, action, data)) + + +class WMPanel(WMWindow): + def __init__(self, owner, name, style=wings.WMTitledWindowMask + |wings.WMClosableWindowMask|wings.WMResizableWindowMask): + WMWidget.__init__(self) + self._o = wings.WMCreatePanelWithStyleForWindow(owner._o, name, style) + +class WMFrame(WMWidget): + def __init__(self, parent, title=None): + WMWidget.__init__(self) + self._o = wings.WMCreateFrame(parent._o) + self.setTitle(title) + + def setRelief(self, relief): + wings.WMSetFrameRelief(self._o, relief) + + def setTitle(self, title=None): + title = title or "" + assert type(title)==StringType + wings.WMSetFrameTitle(self._o, title) + + def setTitlePosition(self, position): + wings.WMSetFrameTitlePosition(self._o, position) + +class WMLabel(WMWidget): + def __init__(self, parent, text=None): + WMWidget.__init__(self) + self._o = wings.WMCreateLabel(parent._o) + self.setText(text) + + def setWraps(self, flag): + assert type(flag)==IntType + wings.WMSetLabelWraps(self._o, flag) + + def setRelief(self, relief): + wings.WMSetLabelRelief(self._o, relief) + + def setText(self, text=None): + text = text or "" + assert type(text)==StringType + wings.WMSetLabelText(self._o, text) + + def setTextColor(self, color): + wings.WMSetLabelTextColor(self._o, color) + + def setFont(self, font): + wings.WMSetLabelFont(self._o, font) + + def setTextAlignment(self, alignment): + wings.WMSetLabelTextAlignment(self._o, alignment) + + def setImage(self, image): + wings.WMSetLabelImage(self._o, image) + + def setImagePosition(self, position): + wings.WMSetLabelImagePosition(self._o, position) + + def text(self): + return wings.WMGetLabelText(self._o) + + def font(self): + return wings.WMGetLabelFont(self._o) + + def image(self): + return wings.WMGetLabelImage(self._o) + + +class WMBox(WMWidget): + def __init__(self, parent): + WMWidget.__init__(self) + self._o = wings.WMCreateBox(parent._o) + + def setHorizontal(self, flag): + assert type(flag)==IntType + wings.WMSetBoxHorizontal(self._o, flag) + + def setBorderWidth(self, width): + assert type(width)==IntType + wings.WMSetBoxBorderWidth(self._o, width) + + def addSubview(self, view, expand, fill, minSize, maxSize, space): + wings.WMAddBoxSubview(self._o, view, expand, fill, minSize, maxSixe, space) + + def addSubviewAtEnd(self, view, expand, fill, minSize, maxSize, space): + wings.WMAddBoxSubviewAtEnd(self._o, view, expand, fill, minSize, maxSixe, space) + + def removeSubview(self, view): + wings.WMRemoveBoxSubview(self._o, view) + + +class WMButton(WMWidget): # not for user instantiation + def __init__(self, parent): + WMWidget.__init__(self) + if self.__class__ == WMButton: + raise Error, "a WMButton can't be instantiated directly" + + + def setText(self, text): + assert type(text) == StringType + wings.WMSetButtonText(self._o, text) + + def setAction(self, action, data=None): + if action!=None and (not callable(action)): + raise Error, "action needs to be a callable object or None" + wings.pyWMSetButtonAction(self._o, (self, action, data)) + + def performClick(self): + wings.WMPerformButtonClick(self._o) + + def setEnabled(self, flag): + assert type(flag) == IntType + wings.WMSetButtonEnabled(self._o, flag) + + def isEnabled(self): + return wings.WMGetButtonEnabled(self._o) + + def setImageDimsWhenDisabled(self, flag): + assert type(flag) == IntType + wings.WMSetButtonImageDimsWhenDisabled(self._o, flag) + + def setImage(self, image): + wings.WMSetButtonImage(self_.o, image) + + def setAlternateImage(self, image): + wings.WMSetButtonAltImage(self._o, image) + + def setImagePosition(self, position): + wings.WMSetButtonImagePosition(self._o, position) + + def setImageDefault(self): + wings.WMSetButtonImageDefault(self._o) + + +class WMCommandButton(WMButton): + def __init__(self, parent): + WMButton.__init__(self, parent) + self._o = wings.WMCreateCommandButton(parent._o) + + +class WMSwitchButton(WMButton): + def __init__(self, parent): + WMButton.__init__(self, parent) + self._o = wings.WMCreateSwitchButton(parent._o) + + +class WMRadioButton(WMButton): + def __init__(self, parent, group=None): + WMButton.__init__(self, parent) + self._o = wings.WMCreateRadioButton(parent._o) + if group: + wings.WMGroupButtons(group._o, self._o) + + +class WMListItem: + pass + + +class WMList(WMWidget): + def __init__(self, parent): + WMWidget.__init__(self) + self._o = wings.WMCreateList(parent._o) + + def allowEmptySelection(self, flag): + assert type(flag) == IntType + wings.WMSetListAllowEmptySelection(self._o, flag) + + def allowMultipleSelection(self, flag): + assert type(flag) == IntType + wings.WMSetListAllowMultipleSelection(self._o, flag) + + def addItem(self, item): + assert type(item) == StringType + wings.WMAddListItem(self._o, item) + + def insertItem(self, row, item): + assert type(row) == IntType and type(item) == StringType + wings.WMAddListItem(self._o, item) + + def sortItems(self): + wings.WMSortListItems(self._o) + + def rowWithTitle(self, title): + assert type(title) == StringType + return wings.WMFindRowOfListItemWithTitle(self._o, title) + + def selectedItemRow(self): + return wings.WMGetListSelectedItemRow(self._o) + + def selectedItem(self): + return wings.WMGetListSelectedItem(self._o) + + def removeItem(self, index): + assert type(index)==IntType + wings.WMRemoveListItem(self._o, index) + + def selectItem(self, index): + assert type(index)==IntType + wings.WMSelectListItem(self._o, index) + + def unselectItem(self, index): + assert type(index)==IntType + wings.WMUnselectListItem(self._o, index) + + +class WMTextFieldDelegate: + __callbacks = ('didBeginEditing', 'didChange', 'didEndEditing', + 'shouldBeginEditing', 'shouldEndEditing') + + def __init__(self): + self.__dict__['data'] = None + self.__dict__['didBeginEditing'] = None + self.__dict__['didChange'] = None + self.__dict__['didEndEditing'] = None + self.__dict__['shouldBeginEditing'] = None + self.__dict__['shouldEndEditing'] = None + + def __setattr__(self, name ,value): + if name in self.__callbacks and value!=None and (not callable(value)): + #raise AttributeError, "%s.%s needs to be a callable object or None" % (self.__class__.__name__, name) + raise Error, "%s.%s needs to be a callable object or None" % (self.__class__.__name__, name) + else: + self.__dict__[name] = value + + +class WMTextField(WMWidget): + def __init__(self, parent, text=None): + WMWidget.__init__(self) + self._o = wings.WMCreateTextField(parent._o) + text = text or "" + assert type(text) == StringType + wings.WMSetTextFieldText(self._o, text) + + def setDelegate(self, delegate): + if delegate.__class__ != WMTextFieldDelegate: + raise Error, "textfield delegate must be of type 'WMTextFieldDelegate'" + wings.pyWMSetTextFieldDelegate(self._o, (self, delegate)) + + def delegate(self): + return wings.pyWMGetTextFieldDelegate(self._o) + + def text(self): + return wings.WMGetTextFieldText(self._o) + + def setEditable(self, flag): + assert type(flag) == IntType + wings.WMSetTextFieldEditable(self._o, flag) + + def setBordered(self, flag): + assert type(flag) == IntType + wings.WMSetTextFieldBordered(self._o, flag) + + def setBeveled(self, flag): + assert type(flag) == IntType + wings.WMSetTextFieldBeveled(self._o, flag) + + def setSecure(self, flag): + assert type(flag) == IntType + wings.WMSetTextFieldSecure(self._o, flag) + + def setCursorPosition(self, position): + assert type(position) == IntType + wings.WMSetTextFieldCursorPosition(self._o, position) + + def setNextText(self, next): + wings.WMSetTextFieldNextTextField(self._o, next._o) + + def setPreviousText(self, previous): + wings.WMSetTextFieldPrevTextField(self._o, previous._o) + + def setTextAlignment(self, alignment): + wings.WMSetTextFieldAlignment(self._o, alignment) + + def isEditable(self): + return wings.WMGetTextFieldEditable(self._o) + + def insertText(self, text, position): + assert type(text)==StringType and type(position)==IntType + wings.WMInsertTextFieldText(self._o, text, position) + + def deleteText(self, start, count): + assert type(start)==IntType and type(count)==IntType + wings.WMDeleteTextFieldRange(self._o, wings.wmkrange(start, count)) + + def selectText(self, start, count): + assert type(start)==IntType and type(count)==IntType + wings.WMSelectTextFieldRange(self._o, wings.wmkrange(start, count)) + + def setFont(self, font): + wings.WMSetTextFieldFont(self._o, font) + + def font(self): + return wings.WMGettextFieldFont(self._o) + + +################################################################################ +# wrap the WINGs constants so we don't need wings.constant_name +################################################################################ + +# WMWindow title style +WMTitledWindowMask = wings.WMTitledWindowMask +WMClosableWindowMask = wings.WMClosableWindowMask +WMMiniaturizableWindowMask = wings.WMMiniaturizableWindowMask +WMResizableWindowMask = wings.WMResizableWindowMask + +# WMFrame title positions +WTPNoTitle = wings.WTPNoTitle +WTPAboveTop = wings.WTPAboveTop +WTPAtTop = wings.WTPAtTop +WTPBelowTop = wings.WTPBelowTop +WTPAboveBottom = wings.WTPAboveBottom +WTPAtBottom = wings.WTPAtBottom +WTPBelowBottom = wings.WTPBelowBottom + +# Alingments +WALeft = wings.WALeft +WACenter = wings.WACenter +WARight = wings.WARight +WAJustified = wings.WAJustified # not valid for textfields + +# Image positions +WIPNoImage = wings.WIPNoImage +WIPImageOnly = wings.WIPImageOnly +WIPLeft = wings.WIPLeft +WIPRight = wings.WIPRight +WIPBelow = wings.WIPBelow +WIPAbove = wings.WIPAbove +WIPOverlaps = wings.WIPOverlaps + +# Relief types +WRFlat = wings.WRFlat +WRSimple = wings.WRSimple +WRRaised = wings.WRRaised +WRSunken = wings.WRSunken +WRGroove = wings.WRGroove +WRRidge = wings.WRRidge +WRPushed = wings.WRPushed + + +# TextField events +WMReturnTextMovement = wings.WMReturnTextMovement +WMEscapeTextMovement = wings.WMEscapeTextMovement +WMIllegalTextMovement = wings.WMIllegalTextMovement +WMTabTextMovement = wings.WMTabTextMovement +WMBacktabTextMovement = wings.WMBacktabTextMovement +WMLeftTextMovement = wings.WMLeftTextMovement +WMRightTextMovement = wings.WMRightTextMovement +WMUpTextMovement = wings.WMUpTextMovement +WMDownTextMovement = wings.WMDownTextMovement + + +if __name__ == "__main__": + def quit(obj, data): + #sys.exit() + scr.breakMainLoop() + + def click(btn, list): + print win.width(), win.height() + print list.selectedItemRow() + win2.show() + scr.runModalLoop(win2.view()) + print txt2.text() + + def sayhi(btn, data): + print "hi" + + def breakLoop(btn, data): + #sys.exit() + scr.breakModalLoop() + win2.hide() + + def dc(object, data, action): + print "didChnage:", object, data, action + + def dbe(object, data, action): + print "didBeginEditing:", object, data, action + + def dee(object, data, action): + if action == wings.WMReturnTextMovement: + if object == txt: + object.setFocusTo(txt2) + else: + object.setFocusTo(txt) + print "didEndEditing:", object, data, action, txt.text() + + def tcb(one): + old = list.selectedItemRow() + list.selectItem(list.index) + list.unselectItem(old) + list.index = (list.index+1) % 3 + #print one + + scr = WMScreen("foobar") + win = WMWindow(scr, "aWindow") + win.setCloseAction(quit) + win.setTitle("test window") + win.resize(400, 180) + win.setInitialPosition((scr.width-win.width())/2, (scr.height-win.height())/2) + + btn = WMCommandButton(win) + btn.setText("Click Me") + btn.resize(100, 25) + btn.move(20, 20) + btn.show() + + sw = WMSwitchButton(win) + sw.setText("Some option") + sw.resize(100, 25) + sw.move(20, 50) + sw.show() + + radios = [] + r = None + j = 0 + for i in ["One", "Two", "Four"]: + r = WMRadioButton(win, r) + radios.append(r) + r.show() + r.setText(i) + r.move(20, 70+j*25) + r.resize(100, 25) + j=j+1 + + sw.setAction(sayhi) + + list = WMList(win) + list.resize(100,100) + list.move(130, 20) + list.addItem("one") + list.addItem("two") + list.addItem("three") + list.allowMultipleSelection(1) + list.show() + list.index = 0 + + txtdel = WMTextFieldDelegate() + txtdel.data = 'mydata' + txtdel.didBeginEditing = dbe + txtdel.didEndEditing = dee + txtdel.didChange = dc + + txt = WMTextField(win, "abc") + txt.resize(95, 20) + txt.move(295, 20) + txt.setDelegate(txtdel) + txt.show() + txt2 = WMTextField(win, "01234567890") + txt2.resize(95, 20) + txt2.move(295, 45) + txt2.setDelegate(txtdel) + txt2.show() + + txt.setNextText(txt2) + txt2.setNextText(txt) + + label = WMLabel(win, "Text1:") + label.setTextAlignment(WARight) + label.move(240, 20) + label.resize(55, 20) + label.show() + + label2 = WMLabel(win, "mytext2:") + label2.setTextAlignment(WARight) + label2.move(240, 45) + label2.resize(55, 20) + label2.show() + + btn.setAction(click, list) + + frame = WMFrame(win, "My Frame") + frame.resize(150, 50) + frame.move(240, 70) + #frame.setRelief(WRPushed) + frame.show() + + ebtn = WMCommandButton(win) + ebtn.setText("Exit") + ebtn.resize(100, 25) + ebtn.move(290, 147) + ebtn.setAction(quit) + ebtn.show() + + win.realize() + win.show() + + timer = WMPersistentTimer(1000, tcb, win) + #del(timer) + #timer.delete() + + win2 = WMPanel(win, "anotherWindow", WMTitledWindowMask) + win2.setTitle("transient test window") + win2.resize(150, 50) + win2.setInitialPosition((scr.width-win2.width())/2, (scr.height-win2.height())/2) + + btn7 = WMCommandButton(win2) + btn7.setText("Dismiss") + btn7.resize(100, 25) + btn7.move(27, 10) + btn7.show() + btn7.setAction(breakLoop) + + win2.realize() + + scr.mainLoop() + diff --git a/WINGs/python/setup.py b/WINGs/python/setup.py new file mode 100755 index 00000000..5100ec3b --- /dev/null +++ b/WINGs/python/setup.py @@ -0,0 +1,72 @@ +#!/usr/bin/env python + +"""Setup script for the WINGs module distribution.""" + +import os, sys +from distutils.core import setup +from distutils.extension import Extension + +## Get the include dirs +wings = os.popen("get-wings-flags --cflags", "r") +lines = [x.strip() for x in wings.readlines()] +flags = reduce(lambda x,y: x+y, [x.split() for x in lines if x]) +include_dirs = [x[2:] for x in flags] +wings.close() + +## Get the library dirs +wings = os.popen("get-wings-flags --ldflags", "r") +lines = [x.strip() for x in wings.readlines()] +flags = reduce(lambda x,y: x+y, [x.split() for x in lines if x]) +library_dirs = [x[2:] for x in flags] +wings.close() + +## Get the libraries +wings = os.popen("get-wings-flags --libs", "r") +lines = [x.strip() for x in wings.readlines()] +flags = reduce(lambda x,y: x+y, [x.split() for x in lines if x]) +libraries = [x[2:] for x in flags] +wings.close() + +runtime_library_dirs = [] +extra_objects = [] +extra_compile_args = ['-Wno-strict-prototypes', '-Wno-unused'] + +long_description = \ +"""Python interface to the WINGs library + +Python WINGs is an interface to WINGs, a small widget set with the +N*XTSTEP look and feel. It's API is inspired in OpenStep and it's +implementation borrows some ideas from Tk. It has a reasonable set of +widgets, sufficient for building small applications (like a CDPlayer +or hacking something like rxvt). It also has other functions that are +usefull for applications, like a User Defaults alike configuration +manager and a notification system. + +""" + +setup (# Distribution meta-data + name = "Python-WINGs", + version = "0.81.0", + description = "A python interface to WINGs", + long_description=long_description, + author = "Dan Pascu", + author_email = "dan@windowmaker.org", + license = "GPL", + platforms = "ALL", + url = "http://windowmaker.org/", + + # Description of the modules and packages in the distribution + + py_modules = ["WINGs"], + + ext_modules = [Extension( + name='wings', + sources=['WINGs.c'], + include_dirs=include_dirs, + library_dirs=library_dirs, + runtime_library_dirs=runtime_library_dirs, + libraries=libraries, + extra_objects=extra_objects, + extra_compile_args=extra_compile_args, + )], +) diff --git a/WINGs/python/test.py b/WINGs/python/test.py new file mode 100755 index 00000000..31b45187 --- /dev/null +++ b/WINGs/python/test.py @@ -0,0 +1,159 @@ +#!/usr/bin/env python + +import sys +from WINGs import * + +if __name__ == "__main__": + def quit(obj, data): + #sys.exit() + scr.breakMainLoop() + + def click(btn, list): + print win.width(), win.height() + print list.selectedItemRow() + win2.show() + scr.runModalLoop(win2.view()) + print txt2.text() + + def sayhi(btn, data): + print "hi" + + def breakLoop(btn, data): + #sys.exit() + scr.breakModalLoop() + win2.hide() + + def dc(object, data, action): + print "didChnage:", object, data, action + + def dbe(object, data, action): + print "didBeginEditing:", object, data, action + + def dee(object, data, action): + if action == wings.WMReturnTextMovement: + if object == txt: + object.setFocusTo(txt2) + else: + object.setFocusTo(txt) + print "didEndEditing:", object, data, action, txt.text() + + def tcb(one): + old = list.selectedItemRow() + list.selectItem(list.index) + list.unselectItem(old) + list.index = (list.index+1) % 3 + #print one + + scr = WMScreen("foobar") + win = WMWindow(scr, "aWindow") + win.setCloseAction(quit) + win.setTitle("test window") + win.resize(400, 180) + win.setInitialPosition((scr.width-win.width())/2, (scr.height-win.height())/2) + + btn = WMCommandButton(win) + btn.setText("Click Me") + btn.resize(100, 25) + btn.move(20, 20) + btn.show() + + sw = WMSwitchButton(win) + sw.setText("Some option") + sw.resize(100, 25) + sw.move(20, 50) + sw.show() + + radios = [] + r = None + j = 0 + for i in ["One", "Two", "Four"]: + r = WMRadioButton(win, r) + radios.append(r) + r.show() + r.setText(i) + r.move(20, 70+j*25) + r.resize(100, 25) + j=j+1 + + sw.setAction(sayhi) + + list = WMList(win) + list.resize(100,100) + list.move(130, 20) + list.addItem("one") + list.addItem("two") + list.addItem("three") + list.allowMultipleSelection(1) + list.show() + list.index = 0 + + txtdel = WMTextFieldDelegate() + txtdel.data = 'mydata' + txtdel.didBeginEditing = dbe + txtdel.didEndEditing = dee + txtdel.didChange = dc + + txt = WMTextField(win, "abc") + txt.resize(95, 20) + txt.move(295, 20) + txt.setDelegate(txtdel) + txt.show() + txt2 = WMTextField(win, "01234567890") + txt2.resize(95, 20) + txt2.move(295, 45) + txt2.setDelegate(txtdel) + txt2.show() + + txt.setNextText(txt2) + txt2.setNextText(txt) + + label = WMLabel(win, "Text1:") + label.setTextAlignment(WARight) + label.move(240, 20) + label.resize(55, 20) + label.show() + + label2 = WMLabel(win, "mytext2:") + label2.setTextAlignment(WARight) + label2.move(240, 45) + label2.resize(55, 20) + label2.show() + + btn.setAction(click, list) + + frame = WMFrame(win, "My Frame") + frame.resize(150, 50) + frame.move(240, 70) + #frame.setRelief(WRPushed) + frame.show() + + ebtn = WMCommandButton(win) + ebtn.setText("Exit") + ebtn.resize(100, 25) + ebtn.move(290, 147) + ebtn.setAction(quit) + ebtn.show() + + win.realize() + win.show() + + timer = WMPersistentTimer(1000, tcb, win) + #del(timer) + #timer.delete() + + win2 = WMPanel(win, "anotherWindow", WMTitledWindowMask) + win2.setTitle("transient test window") + win2.resize(150, 50) + win2.setInitialPosition((scr.width-win2.width())/2, (scr.height-win2.height())/2) + + btn7 = WMCommandButton(win2) + btn7.setText("Dismiss") + btn7.resize(100, 25) + btn7.move(27, 10) + btn7.show() + btn7.setAction(breakLoop) + + win2.realize() + + scr.mainLoop() +