/* pydiacanvasitem.c * Copyright (C) 2002 Arjan Molenaar * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #define NO_IMPORT_PYGOBJECT 1 #define NO_IMPORT_PYGTK 1 #include #include #include #include #include //#define ENABLE_DEBUG 1 //#define ENABLE_DEBUG_GROUP 1 //#define ENABLE_DEBUG_EDIT 1 /* For the DiaCanvasItem callbacks, the prefix is 'on_', for * DiaCanvasGroupable the prefix is 'on_groupable_'. */ #define METHOD_PREFIX "on_" #define DATA_IS_PYOBJECT ((int*) 1) #define DATA_IS_NOT_PYOBJECT ((int*) 2) extern PyTypeObject PyDiaHandle_Type; extern PyTypeObject PyDiaCanvasItem_Type; /* * DiaCanvasItem */ void pydia_canvas_item_class_init (DiaCanvasItemClass *klass); static void pydia_canvas_item_update (DiaCanvasItem *item, gdouble affine[6]); static gboolean pydia_canvas_item_get_shape_iter (DiaCanvasItem *item, DiaCanvasIter *iter); static gboolean pydia_canvas_item_shape_next (DiaCanvasItem *item, DiaCanvasIter *iter); static DiaShape* pydia_canvas_item_shape_value (DiaCanvasItem *item, DiaCanvasIter *iter); static gdouble pydia_canvas_item_point (DiaCanvasItem *item, gdouble x, gdouble y); static void pydia_canvas_item_handle_motion (DiaCanvasItem *item, DiaHandle *handle, gdouble *wx, gdouble *wy, DiaEventMask mask); static gdouble pydia_canvas_item_glue (DiaCanvasItem *item, DiaHandle *handle, gdouble *wx, gdouble *wy); static gboolean pydia_canvas_item_event (DiaCanvasItem *item, gpointer event); static void pydia_canvas_item_move (DiaCanvasItem *item, gdouble dx, gdouble dy, gboolean interactive); static gboolean pydia_canvas_item_connect (DiaCanvasItem *item, DiaHandle *handle); static gboolean pydia_canvas_item_disconnect (DiaCanvasItem *item, DiaHandle *handle); /* * DiaCanvasItem */ void pydia_canvas_item_class_init (DiaCanvasItemClass *klass) { /* Callbacks */ klass->update = pydia_canvas_item_update; klass->point = pydia_canvas_item_point; klass->handle_motion = pydia_canvas_item_handle_motion; klass->glue = pydia_canvas_item_glue; klass->get_shape_iter = pydia_canvas_item_get_shape_iter; klass->shape_next = pydia_canvas_item_shape_next; klass->shape_value = pydia_canvas_item_shape_value; /* Signals. */ klass->event = pydia_canvas_item_event; klass->move = pydia_canvas_item_move; klass->connect = pydia_canvas_item_connect; klass->disconnect = pydia_canvas_item_disconnect; } static void pydia_canvas_item_update (DiaCanvasItem *item, gdouble affine[6]) { PyObject *self; PyObject *py_affine, *py_ret; GValue v = { 0, }; #ifdef ENABLE_DEBUG g_message (G_STRLOC); #endif pyg_block_threads(); g_value_init (&v, DIA_TYPE_AFFINE); g_value_set_static_boxed (&v, affine); //py_affine = pyg_boxed_new (DIA_TYPE_AFFINE, affine, FALSE, FALSE); py_affine = pyg_value_as_pyobject (&v, TRUE); g_value_unset (&v); g_assert (py_affine != NULL); self = pygobject_new ((GObject*) item); py_ret = PyObject_CallMethod (self, METHOD_PREFIX "update", "(O)", py_affine); Py_DECREF (self); Py_DECREF (py_affine); if (!py_ret) { PyErr_Print(); PyErr_Clear(); } else Py_DECREF (py_ret); pyg_unblock_threads(); } static void destroy_iter (gpointer data) { DiaCanvasIter *iter = data; Py_XDECREF ((PyObject*) iter->data[0]); Py_XDECREF ((PyObject*) iter->data[1]); } /* * Shape handling is a little different: * - in get_shape_iter() a PyIter object is requested from shape_iter() * - in shape_next() the next item is fetched from the iterator. * - in shape_value() the DiaShape object is extracted from the PyObject. * The PyIter object is stored in iter.data[0]. The item that is to be fetched * by shape_value() is in data[1]. */ static gboolean pydia_canvas_item_get_shape_iter (DiaCanvasItem *item, DiaCanvasIter *iter) { PyObject *self; PyObject *py_iter; #ifdef ENABLE_DEBUG2 g_message (G_STRLOC); #endif pyg_block_threads(); self = pygobject_new ((GObject*) item); /* Implement generators. * 1. call on_shape_iter(). This will return an Python iterator. * 2. Call PyIter_Next() and store the return value in iter->data[1]. * 3. set the destroy notifier (unrefs data[0] and data[1]). */ py_iter = PyObject_CallMethod (self, METHOD_PREFIX "shape_iter", ""); Py_DECREF (self); pyg_unblock_threads(); if (!py_iter || !PyIter_Check(py_iter)) { g_warning("No iterator returned by self.shape_iter()"); return FALSE; } iter->destroy_func = destroy_iter; iter->data[0] = py_iter; iter->data[1] = NULL; /* Make sure the iterator is pointing to the first shape: */ return pydia_canvas_item_shape_next(item, iter); } static gboolean pydia_canvas_item_shape_next (DiaCanvasItem *item, DiaCanvasIter *iter) { #ifdef ENABLE_DEBUG2 g_message (G_STRLOC); #endif /* remove reference to previously iterated shape */ Py_XDECREF ((PyObject*) iter->data[1]); /* let data[1] point to the next shape */ iter->data[1] = PyIter_Next (iter->data[0]); /* if PyIter_Next() returned NULL there are no more items to fetch */ return iter->data[1] != NULL; } static DiaShape* pydia_canvas_item_shape_value (DiaCanvasItem *item, DiaCanvasIter *iter) { PyObject *py_shape; DiaShape *shape = NULL; #ifdef ENABLE_DEBUG g_message (G_STRLOC": data=%p/%p", iter->data[0], iter->data[1]); #endif py_shape = iter->data[1]; if (py_shape && (pyg_boxed_check (py_shape, DIA_TYPE_SHAPE_PATH) || pyg_boxed_check (py_shape, DIA_TYPE_SHAPE_BEZIER) || pyg_boxed_check (py_shape, DIA_TYPE_SHAPE_ELLIPSE) || pyg_boxed_check (py_shape, DIA_TYPE_SHAPE_TEXT) || pyg_boxed_check (py_shape, DIA_TYPE_SHAPE_IMAGE))) shape = pyg_boxed_get (py_shape, DiaShape); else PyErr_SetString (PyExc_TypeError, "iter_shape() should only return DiaShape's."); return shape; } static gdouble pydia_canvas_item_point (DiaCanvasItem *item, gdouble x, gdouble y) { PyObject *self; PyObject *py_ret; gdouble retval = G_MAXDOUBLE; #ifdef ENABLE_DEBUG g_message (G_STRLOC); #endif pyg_block_threads(); self = pygobject_new ((GObject*) item); py_ret = PyObject_CallMethod (self, METHOD_PREFIX "point", "(dd)", x, y); Py_DECREF (self); if (!py_ret) { PyErr_Clear (); PyErr_SetString (PyExc_TypeError, "method " METHOD_PREFIX "point not found."); } else { PyObject *py_float = PyNumber_Float(py_ret); if (py_float) retval = PyFloat_AsDouble (py_float); else { PyErr_Clear (); PyErr_SetString (PyExc_TypeError, "return value should be a float."); } Py_DECREF (py_float); } Py_XDECREF (py_ret); pyg_unblock_threads(); #ifdef ENABLE_DEBUG g_message (G_STRLOC": returning %f", retval); #endif return retval; } static void pydia_canvas_item_move (DiaCanvasItem *item, gdouble dx, gdouble dy, gboolean interactive) { PyObject *self; PyObject *py_ret; #ifdef ENABLE_DEBUG g_message (G_STRLOC); #endif pyg_block_threads(); self = pygobject_new ((GObject*) item); py_ret = PyObject_CallMethod (self, METHOD_PREFIX "move", "(ddi)", dx, dy, interactive); Py_DECREF (self); if (!py_ret) { PyErr_Print(); PyErr_Clear(); } else Py_DECREF (py_ret); pyg_unblock_threads(); } static void pydia_canvas_item_handle_motion (DiaCanvasItem *item, DiaHandle *handle, gdouble *wx, gdouble *wy, DiaEventMask mask) { PyObject *self; PyObject *py_handle; PyObject *py_ret, *sitem; gdouble val[2]; int i; #ifdef ENABLE_DEBUG g_message (G_STRLOC); #endif pyg_block_threads(); self = pygobject_new ((GObject*) item); py_handle = pygobject_new ((GObject*) handle); py_ret = PyObject_CallMethod (self, METHOD_PREFIX "handle_motion", "(Oddi)", py_handle, *wx, *wy, mask); Py_DECREF (self); Py_DECREF (py_handle); if (!py_ret) { PyErr_Print(); PyErr_Clear(); pyg_unblock_threads(); return; } if (PySequence_Length(py_ret) != 2) { PyErr_SetString(PyExc_TypeError, "return value must be a 2 tuple of floats."); Py_DECREF (py_ret); pyg_unblock_threads(); return; } for (i = 0; i < 2; i++) { sitem = PySequence_GetItem(py_ret, i); Py_DECREF(sitem); sitem = PyNumber_Float(sitem); if (sitem) val[i] = PyFloat_AsDouble(sitem); else { PyErr_Clear(); PyErr_SetString(PyExc_TypeError, "sequence item not a float"); Py_DECREF (py_ret); pyg_unblock_threads(); return; } Py_DECREF(sitem); } *wx = val[0]; *wy = val[1]; Py_DECREF (py_ret); pyg_unblock_threads(); } static gdouble pydia_canvas_item_glue (DiaCanvasItem *item, DiaHandle *handle, gdouble *wx, gdouble *wy) { PyObject *self; PyObject *py_handle, *py_ret, *sitem; GValue v_wxy = { 0, }; DiaPoint *wxy; gdouble retval = G_MAXDOUBLE; #ifdef ENABLE_DEBUG g_message (G_STRLOC); #endif pyg_block_threads(); self = pygobject_new ((GObject*) item); py_handle = pygobject_new ((GObject*)handle); py_ret = PyObject_CallMethod (self, METHOD_PREFIX "glue", "(Odd)", py_handle, *wx, *wy); Py_DECREF (self); Py_DECREF (py_handle); if (!py_ret || py_ret == Py_None) { Py_XDECREF (py_ret); pyg_unblock_threads(); return G_MAXDOUBLE; } if (PySequence_Length(py_ret) != 2) { PyErr_SetString(PyExc_TypeError, "return value must be a tuple of a float and a point."); Py_DECREF(py_ret); pyg_unblock_threads(); return G_MAXDOUBLE; } /* Get distance */ sitem = PySequence_GetItem(py_ret, 0); Py_DECREF(sitem); sitem = PyNumber_Float(sitem); if (sitem) retval = PyFloat_AsDouble(sitem); else { PyErr_Clear(); PyErr_SetString(PyExc_TypeError, "first item of sequence item not a float"); //Py_DECREF(sitem); Py_DECREF(py_ret); pyg_unblock_threads(); return G_MAXDOUBLE; } Py_DECREF(sitem); /* Get glue point */ g_value_init (&v_wxy, DIA_TYPE_POINT); sitem = PySequence_GetItem(py_ret, 1); if (pyg_value_from_pyobject(&v_wxy, sitem) != 0) { PyErr_SetString(PyExc_TypeError, "second item of sequence is not a tuple of 2 floats"); Py_XDECREF(sitem); Py_DECREF(py_ret); pyg_unblock_threads(); return G_MAXDOUBLE; } wxy = g_value_get_boxed (&v_wxy); *wx = wxy->x; *wy = wxy->y; g_value_unset (&v_wxy); Py_DECREF(sitem); Py_DECREF(py_ret); pyg_unblock_threads(); return retval; } static gboolean pydia_canvas_item_event (DiaCanvasItem *item, gpointer event) { PyObject *self; PyObject *py_event; PyObject *py_ret; gboolean ret = FALSE; #ifdef ENABLE_DEBUG g_message (G_STRLOC); #endif pyg_block_threads(); self = pygobject_new ((GObject*) item); py_event = pyg_boxed_new (DIA_TYPE_EVENT, event, FALSE, FALSE); py_ret = PyObject_CallMethod (self, METHOD_PREFIX "event", "(O)", py_event); Py_DECREF (self); Py_DECREF (py_event); if (py_ret) { if (PyObject_IsTrue (py_ret)) ret = TRUE; Py_DECREF (py_ret); } else { PyErr_Print (); PyErr_Clear (); } pyg_unblock_threads(); return ret; } static gboolean pydia_canvas_item_connect (DiaCanvasItem *item, DiaHandle *handle) { PyObject *self; PyObject *py_handle; PyObject *py_ret; gboolean ret = FALSE; self = pygobject_new ((GObject*) item); #ifdef ENABLE_DEBUG g_message (G_STRLOC); #endif pyg_block_threads(); py_handle = pygobject_new ((GObject*)handle); py_ret = PyObject_CallMethod (self, METHOD_PREFIX "connect_handle", "(O)", py_handle); Py_DECREF (self); Py_DECREF (py_handle); if (py_ret) { if (PyObject_IsTrue (py_ret)) ret = TRUE; Py_DECREF (py_ret); } else { PyErr_Print (); PyErr_Clear (); } pyg_unblock_threads(); return ret; } static gboolean pydia_canvas_item_disconnect (DiaCanvasItem *item, DiaHandle *handle) { PyObject *self; PyObject *py_handle; PyObject *py_ret; gboolean ret = FALSE; #ifdef ENABLE_DEBUG g_message (G_STRLOC); #endif pyg_block_threads(); self = pygobject_new ((GObject*) item); py_handle = pygobject_new ((GObject*)handle); py_ret = PyObject_CallMethod (self, METHOD_PREFIX "disconnect_handle", "(O)", py_handle); Py_DECREF (self); Py_DECREF (py_handle); if (py_ret) { if (PyObject_IsTrue (py_ret)) ret = TRUE; Py_DECREF (py_ret); } else { PyErr_Print (); PyErr_Clear (); } pyg_unblock_threads(); return ret; } /* * Methods called by the python code to call their superclass. * * In order to get access to those methods, the user should have called * diacanvas.register_callbacks() on the class. */ #define GET_NON_PYTHON_PARENT_CLASS(klass, callback) \ klass = DIA_CANVAS_ITEM_GET_CLASS (self->obj); \ while (klass && klass->callback == pydia_canvas_item_ ## callback) \ klass = g_type_class_peek_parent (klass); PyObject * _wrap_dia_canvas_item_on_update(PyGObject *self, PyObject *args, PyObject *kwargs) { static char *kwlist[] = { "affine", NULL }; PyObject *py_affine; GValue v = { 0, }; DiaCanvasItemClass *klass; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O:DiaCanvasItem.on_update", kwlist, &py_affine)) return NULL; g_value_init (&v, DIA_TYPE_AFFINE); if (pyg_value_from_pyobject (&v, py_affine) != 0) return NULL; /* Find the first class that doesn't have the python callback. */ GET_NON_PYTHON_PARENT_CLASS(klass, update); if (klass->update) klass->update (DIA_CANVAS_ITEM(self->obj), g_value_get_boxed (&v)); g_value_unset (&v); Py_INCREF(Py_None); return Py_None; } /* Return a Python iterator for all shapes in the canvas item. * This function is used to wrap the shapes found in the C classes to * Python. */ PyObject * _wrap_dia_canvas_item_on_shape_iter (PyGObject *self) { DiaCanvasItem *item = DIA_CANVAS_ITEM(self->obj); DiaCanvasItemClass *klass; DiaCanvasIter iter; DiaShape *shape; PyObject *list, *obj, *listiter; list = PyList_New (0); /* Find the first class that doesn't have the python callback. */ GET_NON_PYTHON_PARENT_CLASS(klass, get_shape_iter); dia_canvas_iter_init (&iter); if (klass && klass->get_shape_iter && klass->shape_value && klass->get_shape_iter (item, &iter)) do { shape = klass->shape_value (item, &iter); if (shape) { /* do not copy the shape, nor free it when the * box is freed: */ obj = pyg_boxed_new (dia_shape_get_type(shape), shape, FALSE, FALSE); PyList_Append (list, obj); Py_DECREF (obj); } } while (klass->shape_next && klass->shape_next (item, &iter)); dia_canvas_iter_destroy (&iter); listiter = PyObject_GetIter (list); Py_DECREF(list); return listiter; } PyObject * _wrap_dia_canvas_item_on_point(PyGObject *self, PyObject *args, PyObject *kwargs) { static char *kwlist[] = { "x", "y", NULL }; double x, y, ret = G_MAXDOUBLE; DiaCanvasItemClass *klass; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "dd:DiaCanvasItem.on_point", kwlist, &x, &y)) return NULL; /* Find the first class that doesn't have the python callback. */ GET_NON_PYTHON_PARENT_CLASS(klass, point); if (klass->point) ret = klass->point (DIA_CANVAS_ITEM(self->obj), x, y); return PyFloat_FromDouble(ret); } PyObject * _wrap_dia_canvas_item_on_move(PyGObject *self, PyObject *args, PyObject *kwargs) { static char *kwlist[] = { "x", "y", "interactive", NULL }; double x, y; int interactive; DiaCanvasItemClass *klass; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ddi:DiaCanvasItem.on_move", kwlist, &x, &y, &interactive)) return NULL; /* Find the first class that doesn't have the python callback. */ GET_NON_PYTHON_PARENT_CLASS(klass, move); if (klass->move) klass->move (DIA_CANVAS_ITEM(self->obj), x, y, (gboolean) interactive); Py_INCREF(Py_None); return Py_None; } PyObject * _wrap_dia_canvas_item_on_handle_motion(PyGObject *self, PyObject *args, PyObject *kwargs) { static char *kwlist[] = { "handle", "x", "y", "mask", NULL }; PyGObject *handle; double x, y; DiaEventMask mask; DiaCanvasItemClass *klass; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "Oddi:DiaCanvasItem.on_handle_motion", kwlist, &handle, &x, &y, &mask)) return NULL; if (!pygobject_check(handle, &PyDiaHandle_Type)) { PyErr_SetString(PyExc_TypeError, "handle should be a DiaHandle"); return NULL; } /* Find the first class that doesn't have the python callback. */ GET_NON_PYTHON_PARENT_CLASS(klass, handle_motion); if (klass->handle_motion) klass->handle_motion (DIA_CANVAS_ITEM(self->obj), DIA_HANDLE (handle->obj), &x, &y, mask); /* We should somehow forward x and y. */ return Py_BuildValue ("(dd)", x, y); } PyObject * _wrap_dia_canvas_item_on_glue(PyGObject *self, PyObject *args, PyObject *kwargs) { static char *kwlist[] = { "handle", "x", "y", NULL }; PyGObject *handle; double x = 0.0, y = 0.0, ret = G_MAXDOUBLE; DiaCanvasItemClass *klass; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "Odd:DiaCanvasItem.on_glue", kwlist, &handle, &x, &y)) return NULL; /* Find the first class that doesn't have the python callback. */ GET_NON_PYTHON_PARENT_CLASS(klass, glue); if (klass->glue) ret = klass->glue (DIA_CANVAS_ITEM(self->obj), DIA_HANDLE (handle->obj), &x, &y); return Py_BuildValue ("(d(dd))", ret, x, y); } PyObject * _wrap_dia_canvas_item_on_event(PyGObject *self, PyObject *args, PyObject *kwargs) { //static char *kwlist[] = { "event", NULL }; PyObject *py_event, *py_ret; int ret = FALSE; //gpointer event = NULL; //DiaCanvasItemClass *klass; #if 0 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O:DiaCanvasItem.on_event", kwlist, &py_event)) return NULL; if (pyg_boxed_check(py_event, DIA_TYPE_EVENT)) event = pyg_boxed_get(py_event, DiaEvent); else { PyErr_SetString(PyExc_TypeError, "event should be a DiaEvent"); return NULL; } /* Find the first class that doesn't have the python callback. */ GET_NON_PYTHON_PARENT_CLASS(klass, event); if (klass->event) ret = klass->event (DIA_CANVAS_ITEM(self->obj), (gpointer) event); #endif py_ret = ret ? Py_True : Py_False; Py_INCREF(py_ret); return py_ret; } PyObject * _wrap_dia_canvas_item_on_connect_handle(PyGObject *self, PyObject *args, PyObject *kwargs) { static char *kwlist[] = { "handle", NULL }; PyGObject *handle; PyObject *py_ret; int ret = FALSE; DiaCanvasItemClass *klass; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!:DiaCanvasItem.on_connect_handle", kwlist, &PyDiaHandle_Type, &handle)) return NULL; /* Find the first class that doesn't have the python callback. */ GET_NON_PYTHON_PARENT_CLASS(klass, connect); if (klass->connect) ret = klass->connect (DIA_CANVAS_ITEM(self->obj), DIA_HANDLE(handle->obj)); py_ret = ret ? Py_True : Py_False; Py_INCREF(py_ret); return py_ret; } PyObject * _wrap_dia_canvas_item_on_disconnect_handle(PyGObject *self, PyObject *args, PyObject *kwargs) { static char *kwlist[] = { "handle", NULL }; PyGObject *handle; PyObject *py_ret; int ret = FALSE; DiaCanvasItemClass *klass; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!:DiaCanvasItem.on_disconnect_handle", kwlist, &PyDiaHandle_Type, &handle)) return NULL; /* Find the first class that doesn't have the python callback. */ GET_NON_PYTHON_PARENT_CLASS(klass, disconnect); if (klass->disconnect) ret = klass->disconnect (DIA_CANVAS_ITEM(self->obj), DIA_HANDLE(handle->obj)); py_ret = ret ? Py_True : Py_False; Py_INCREF(py_ret); return py_ret; } /* * DiaCanvasGroupable * * The only canvas item that is groupable by default is DiaCanvasGroup. * * For now only C->Python groupability will be coded. */ #undef METHOD_PREFIX #define METHOD_PREFIX "on_groupable_" static void pydia_canvas_groupable_add (DiaCanvasGroupable *group, DiaCanvasItem *item); static void pydia_canvas_groupable_remove (DiaCanvasGroupable *group, DiaCanvasItem *item); static gboolean pydia_canvas_groupable_get_iter (DiaCanvasGroupable *group, DiaCanvasIter *iter); static gboolean pydia_canvas_groupable_next (DiaCanvasGroupable *group, DiaCanvasIter *iter); static DiaCanvasItem* pydia_canvas_groupable_value (DiaCanvasGroupable *group, DiaCanvasIter *iter); void pydia_canvas_groupable_init (DiaCanvasGroupableIface *iface) { iface->add = pydia_canvas_groupable_add; iface->remove = pydia_canvas_groupable_remove; iface->get_iter = pydia_canvas_groupable_get_iter; iface->next = pydia_canvas_groupable_next; iface->value = pydia_canvas_groupable_value; } static void pydia_canvas_groupable_add (DiaCanvasGroupable *group, DiaCanvasItem *item) { PyObject *self; self = pygobject_new ((GObject*) group); #ifdef ENABLE_DEBUG_GROUP g_message (G_STRLOC": self = %p, obj = %p", self, group); #endif if (PyObject_HasAttrString (self, METHOD_PREFIX "add")) { PyObject *py_ret, *py_item; pyg_block_threads(); py_item = pygobject_new ((GObject*) item); py_ret = PyObject_CallMethod (self, METHOD_PREFIX "add", "O", py_item); Py_DECREF(py_item); if (py_ret) { Py_DECREF (py_ret); } else { PyErr_Print (); PyErr_Clear (); } pyg_unblock_threads(); } else { g_signal_stop_emission_by_name (group, "add"); } Py_DECREF (self); } static void pydia_canvas_groupable_remove (DiaCanvasGroupable *group, DiaCanvasItem *item) { PyObject *self; self = pygobject_new ((GObject*) group); #ifdef ENABLE_DEBUG_GROUP g_message (G_STRLOC": self = %p, obj = %p", self, group); #endif if (PyObject_HasAttrString (self, METHOD_PREFIX "remove")) { PyObject *py_item, *py_ret; pyg_block_threads(); py_item = pygobject_new ((GObject*) item); py_ret = PyObject_CallMethod (self, METHOD_PREFIX "remove", "O", py_item); Py_DECREF (py_item); if (py_ret) { Py_DECREF (py_ret); } else { PyErr_Print (); PyErr_Clear (); } pyg_unblock_threads(); } else { g_signal_stop_emission_by_name (group, "add"); } Py_DECREF (self); } static gboolean pydia_canvas_groupable_get_iter (DiaCanvasGroupable *group, DiaCanvasIter *iter) { PyObject *self; gboolean ret = FALSE; self = pygobject_new ((GObject*) group); #ifdef ENABLE_DEBUG_GROUP g_message (G_STRLOC": self = %p, obj = %p", self, group); #endif if (PyObject_HasAttrString (self, METHOD_PREFIX "iter")) { PyObject *py_iter; pyg_block_threads(); py_iter = PyObject_CallMethod (self, METHOD_PREFIX "iter", NULL); pyg_unblock_threads(); if (py_iter && PyIter_Check(py_iter)) { iter->destroy_func = destroy_iter; iter->data[0] = py_iter; iter->data[1] = NULL; /* Make sure the iterator is pointing to the first shape: */ ret = pydia_canvas_groupable_next (group, iter); } else { g_warning("No iterator returned by self.groupable_iter()"); } } Py_DECREF (self); return ret; } static gboolean pydia_canvas_groupable_next (DiaCanvasGroupable *group, DiaCanvasIter *iter) { #ifdef ENABLE_DEBUG_GROUP g_message (G_STRLOC": self = %p, obj = %p", self, group); #endif /* remove reference to previously iterated shape */ Py_XDECREF ((PyObject*) iter->data[1]); /* let data[1] point to the next shape */ iter->data[1] = PyIter_Next (iter->data[0]); /* if PyIter_Next() returned NULL there are no more items to fetch */ return iter->data[1] != NULL; } static DiaCanvasItem* pydia_canvas_groupable_value (DiaCanvasGroupable *group, DiaCanvasIter *iter) { PyObject *py_item; #ifdef ENABLE_DEBUG_GROUP g_message (G_STRLOC": self = %p, obj = %p", self, group); #endif py_item = iter->data[1]; if (!PyObject_TypeCheck(py_item, &PyDiaCanvasItem_Type)) { PyErr_SetString(PyExc_TypeError,"argument must be a DiaCanvasItem instance"); return NULL; } return (DiaCanvasItem*) ((PyGObject*) py_item)->obj; } /* * DiaCanvasEditable * * Only C->Python is needed. */ #undef METHOD_PREFIX #define METHOD_PREFIX "on_editable_" static gboolean pydia_canvas_editable_is_editable (DiaCanvasEditable *editable); static DiaShapeText* pydia_canvas_editable_get_editable_shape (DiaCanvasEditable *editable, gdouble x, gdouble y); static void pydia_canvas_editable_start_editing (DiaCanvasEditable *editable, DiaShapeText *text_shape); static void pydia_canvas_editable_editing_done (DiaCanvasEditable *editable, DiaShapeText *text_shape, const gchar *new_text); static void pydia_canvas_editable_text_changed (DiaCanvasEditable *editable, DiaShapeText *text_shape, const gchar *new_text); void pydia_canvas_editable_init (DiaCanvasEditableIface *iface) { iface->is_editable = pydia_canvas_editable_is_editable; iface->get_editable_shape = pydia_canvas_editable_get_editable_shape; iface->start_editing = pydia_canvas_editable_start_editing; iface->editing_done = pydia_canvas_editable_editing_done; iface->text_changed = pydia_canvas_editable_text_changed; } static gboolean pydia_canvas_editable_is_editable (DiaCanvasEditable *editable) { PyObject *self; PyObject *py_ret; gboolean ret = TRUE; #ifdef ENABLE_DEBUG_EDIT g_message (G_STRLOC); #endif self = pygobject_new ((GObject*) editable); if (PyObject_HasAttrString (self, METHOD_PREFIX "is_editable")) { pyg_block_threads(); py_ret = PyObject_CallMethod (self, METHOD_PREFIX "is_editable", ""); pyg_unblock_threads(); if (py_ret) { if (!PyObject_IsTrue (py_ret)) ret = FALSE; Py_DECREF (py_ret); } else { PyErr_Print (); PyErr_Clear (); } } Py_DECREF (self); return ret; } static DiaShapeText* pydia_canvas_editable_get_editable_shape (DiaCanvasEditable *editable, gdouble x, gdouble y) { PyObject *self; DiaShapeText *text_shape = NULL; self = pygobject_new ((GObject*) editable); #ifdef ENABLE_DEBUG_EDIT g_message (G_STRLOC": self = %p, obj = %p", self, text_shape); #endif if (PyObject_HasAttrString (self, METHOD_PREFIX "get_editable_shape")) { PyObject *py_ret; pyg_block_threads (); py_ret = PyObject_CallMethod (self, METHOD_PREFIX "get_editable_shape", "(dd)", x, y); pyg_unblock_threads (); if (!py_ret) { PyErr_Print (); PyErr_Clear (); } else { if (!pyg_boxed_check (py_ret, DIA_TYPE_SHAPE_TEXT)) PyErr_SetString (PyExc_TypeError, METHOD_PREFIX "get_editable_shape() should only return DiaShapeText's."); else text_shape = pyg_boxed_get (py_ret, DiaShapeText); Py_DECREF (py_ret); } } Py_DECREF (self); return text_shape; } static void pydia_canvas_editable_start_editing (DiaCanvasEditable *editable, DiaShapeText *text_shape) { PyObject *self; self = pygobject_new ((GObject*) editable); #ifdef ENABLE_DEBUG_EDIT g_message (G_STRLOC": self = %p, obj = %p", self, text_shape); #endif if (PyObject_HasAttrString (self, METHOD_PREFIX "start_editing")) { PyObject *py_ret, *py_text_shape; pyg_block_threads (); py_text_shape = pyg_boxed_new (dia_shape_get_type ((DiaShape*) text_shape), text_shape, FALSE, FALSE); py_ret = PyObject_CallMethod (self, METHOD_PREFIX "start_editing", "O", py_text_shape); Py_DECREF (py_text_shape); pyg_unblock_threads (); if (!py_ret) { PyErr_Print (); PyErr_Clear (); } else { Py_DECREF (py_ret); } } Py_DECREF (self); } static void pydia_canvas_editable_editing_done (DiaCanvasEditable *editable, DiaShapeText *text_shape, const gchar *new_text) { PyObject *self; self = pygobject_new ((GObject*) editable); #ifdef ENABLE_DEBUG_EDIT g_message (G_STRLOC": self = %p, obj = %p", self, text_shape); #endif if (PyObject_HasAttrString (self, METHOD_PREFIX "editing_done")) { PyObject *py_ret, *py_text_shape; pyg_block_threads (); py_text_shape = pyg_boxed_new (dia_shape_get_type ((DiaShape*) text_shape), text_shape, FALSE, FALSE); py_ret = PyObject_CallMethod (self, METHOD_PREFIX "editing_done", "Os", py_text_shape, new_text); Py_DECREF (py_text_shape); pyg_unblock_threads (); if (!py_ret) { PyErr_Print (); PyErr_Clear (); } else { Py_DECREF (py_ret); } } Py_DECREF (self); } static void pydia_canvas_editable_text_changed (DiaCanvasEditable *editable, DiaShapeText *text_shape, const gchar *new_text) { PyObject *self; self = pygobject_new ((GObject*) editable); #ifdef ENABLE_DEBUG_EDIT g_message (G_STRLOC": self = %p, obj = %p", self, text_shape); #endif if (PyObject_HasAttrString (self, METHOD_PREFIX "text_changed")) { PyObject *py_ret, *py_text_shape; pyg_block_threads (); py_text_shape = pyg_boxed_new (dia_shape_get_type ((DiaShape*) text_shape), text_shape, FALSE, FALSE); py_ret = PyObject_CallMethod (self, METHOD_PREFIX "text_changed", "Os", py_text_shape, new_text); Py_DECREF (py_text_shape); pyg_unblock_threads (); if (!py_ret) { PyErr_Print (); PyErr_Clear (); } else { Py_DECREF (py_ret); } } Py_DECREF (self); }