diff options
author | Campbell Barton <ideasman42@gmail.com> | 2012-12-20 17:29:58 +0400 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2012-12-20 17:29:58 +0400 |
commit | 0e3d637ad040f55412856d10197f66f166591e49 (patch) | |
tree | 1ff87859407f73a72b67834d41085eacb1c33740 | |
parent | 80bcc20835cfd328984c3fbc60774d6e6bed6482 (diff) |
Change region drawing callbacks to work much closer to how blender manages them internally.
- yes, this does break scripts, but the api is marked experimental.
ED_region_draw_cb_activate() adds a callback to a region type whereas the api made it look like the callback was being added to the region instance.
Use a class method on bpy.types.Space to manage region drawing, eg.
was:
self._handle = context.region.callback_add(draw_callback_px, args, 'POST_PIXEL')
is now:
self._handle = bpy.types.SpaceView3D.draw_handler_add(draw_callback_px, args, 'WINDOW', 'POST_PIXEL')
-rw-r--r-- | release/scripts/templates/operator_modal_draw.py | 8 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/bpath.c | 2 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/pbvh.c | 2 | ||||
-rw-r--r-- | source/blender/python/intern/bpy.c | 4 | ||||
-rw-r--r-- | source/blender/python/intern/bpy_rna.c | 42 | ||||
-rw-r--r-- | source/blender/python/intern/bpy_rna.h | 1 | ||||
-rw-r--r-- | source/blender/python/intern/bpy_rna_callback.c | 179 | ||||
-rw-r--r-- | source/blender/python/intern/bpy_rna_callback.h | 5 |
8 files changed, 230 insertions, 13 deletions
diff --git a/release/scripts/templates/operator_modal_draw.py b/release/scripts/templates/operator_modal_draw.py index f1c4e113b0a..d11ddf0b467 100644 --- a/release/scripts/templates/operator_modal_draw.py +++ b/release/scripts/templates/operator_modal_draw.py @@ -42,20 +42,22 @@ class ModalDrawOperator(bpy.types.Operator): self.mouse_path.append((event.mouse_region_x, event.mouse_region_y)) elif event.type == 'LEFTMOUSE': - context.region.callback_remove(self._handle) + bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW') return {'FINISHED'} elif event.type in {'RIGHTMOUSE', 'ESC'}: - context.region.callback_remove(self._handle) + bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW') return {'CANCELLED'} return {'RUNNING_MODAL'} def invoke(self, context, event): if context.area.type == 'VIEW_3D': + # the arguments we pass the the callback + args = (self, context) # Add the region OpenGL drawing callback # draw in view space with 'POST_VIEW' and 'PRE_VIEW' - self._handle = context.region.callback_add(draw_callback_px, (self, context), 'POST_PIXEL') + self._handle = bpy.types.SpaceView3D.draw_handler_add(draw_callback_px, args, 'WINDOW', 'POST_PIXEL') self.mouse_path = [] diff --git a/source/blender/blenkernel/intern/bpath.c b/source/blender/blenkernel/intern/bpath.c index 24b13b062f3..f8ee955ab50 100644 --- a/source/blender/blenkernel/intern/bpath.c +++ b/source/blender/blenkernel/intern/bpath.c @@ -25,7 +25,7 @@ * ***** END GPL LICENSE BLOCK ***** */ -/** \file blender/blenlib/intern/bpath.c +/** \file blender/blenkernel/intern/bpath.c * \ingroup bli */ diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c index 3a4e8afca76..209461bad2f 100644 --- a/source/blender/blenkernel/intern/pbvh.c +++ b/source/blender/blenkernel/intern/pbvh.c @@ -18,7 +18,7 @@ * ***** END GPL LICENSE BLOCK ***** */ -/** \file blender/blenlib/intern/pbvh.c +/** \file blender/blenkernel/intern/pbvh.c * \ingroup bli */ diff --git a/source/blender/python/intern/bpy.c b/source/blender/python/intern/bpy.c index 876e2b2568f..082807c62db 100644 --- a/source/blender/python/intern/bpy.c +++ b/source/blender/python/intern/bpy.c @@ -234,6 +234,7 @@ static PyObject *bpy_import_test(const char *modname) return mod; } + /****************************************************************************** * Description: Creates the bpy module and adds it to sys.modules for importing ******************************************************************************/ @@ -293,6 +294,9 @@ void BPy_init_modules(void) PyModule_AddObject(mod, "context", (PyObject *)bpy_context_module); + /* register bpy/rna classmethod callbacks */ + BPY_rna_register_cb(); + /* utility func's that have nowhere else to go */ PyModule_AddObject(mod, meth_bpy_script_paths.ml_name, (PyObject *)PyCFunction_New(&meth_bpy_script_paths, NULL)); PyModule_AddObject(mod, meth_bpy_blend_paths.ml_name, (PyObject *)PyCFunction_New(&meth_bpy_blend_paths, NULL)); diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c index cca37ee1dc3..2de477c46c3 100644 --- a/source/blender/python/intern/bpy_rna.c +++ b/source/blender/python/intern/bpy_rna.c @@ -4624,8 +4624,14 @@ static struct PyMethodDef pyrna_struct_methods[] = { {"__dir__", (PyCFunction)pyrna_struct_dir, METH_NOARGS, NULL}, /* experimental */ + /* unused for now */ +#if 0 {"callback_add", (PyCFunction)pyrna_callback_add, METH_VARARGS, NULL}, {"callback_remove", (PyCFunction)pyrna_callback_remove, METH_VARARGS, NULL}, + + {"callback_add", (PyCFunction)pyrna_callback_classmethod_add, METH_VARARGS | METH_CLASS, NULL}, + {"callback_remove", (PyCFunction)pyrna_callback_classmethod_remove, METH_VARARGS | METH_CLASS, NULL}, +#endif {NULL, NULL, 0, NULL} }; @@ -7627,3 +7633,39 @@ static PyObject *pyrna_unregister_class(PyObject *UNUSED(self), PyObject *py_cla Py_RETURN_NONE; } + +/* currently this is fairly limited, we would need to make some way to split up + * pyrna_callback_classmethod_... if we want more then one callback per type */ +typedef struct BPyRNA_CallBack { + PyMethodDef py_method; + StructRNA *bpy_srna; +} PyRNA_CallBack; + +static struct BPyRNA_CallBack pyrna_cb_methods[] = { + {{"draw_handler_add", (PyCFunction)pyrna_callback_classmethod_add, METH_VARARGS | METH_STATIC, ""}, &RNA_Space}, + {{"draw_handler_remove", (PyCFunction)pyrna_callback_classmethod_remove, METH_VARARGS | METH_STATIC, ""}, &RNA_Space}, + {{NULL, NULL, 0, NULL}, NULL} +}; + +void BPY_rna_register_cb(void) +{ + int i; + + for (i = 0; pyrna_cb_methods[i].bpy_srna; i++) { + PyObject *cls; + PyObject *func; + PyObject *classmethod; + PyObject *args = PyTuple_New(1); + + cls = pyrna_srna_Subtype(pyrna_cb_methods[i].bpy_srna); + func = PyCFunction_New(&pyrna_cb_methods[i].py_method, NULL); + PyTuple_SET_ITEM(args, 0, func); + classmethod = PyObject_CallObject((PyObject *)&PyClassMethod_Type, args); + + PyObject_SetAttrString(cls, pyrna_cb_methods[i].py_method.ml_name, classmethod); + + Py_DECREF(classmethod); + Py_DECREF(args); /* clears 'func' too */ + Py_DECREF(cls); + } +} diff --git a/source/blender/python/intern/bpy_rna.h b/source/blender/python/intern/bpy_rna.h index 880ef4c2185..edd2ada0539 100644 --- a/source/blender/python/intern/bpy_rna.h +++ b/source/blender/python/intern/bpy_rna.h @@ -171,6 +171,7 @@ PyObject *BPY_rna_module(void); void BPY_update_rna_module(void); /*PyObject *BPY_rna_doc(void);*/ PyObject *BPY_rna_types(void); +void BPY_rna_register_cb(void); PyObject *pyrna_struct_CreatePyObject(PointerRNA *ptr); PyObject *pyrna_prop_CreatePyObject(PointerRNA *ptr, PropertyRNA *prop); diff --git a/source/blender/python/intern/bpy_rna_callback.c b/source/blender/python/intern/bpy_rna_callback.c index f7114115a91..adb4ae6a2c6 100644 --- a/source/blender/python/intern/bpy_rna_callback.c +++ b/source/blender/python/intern/bpy_rna_callback.c @@ -38,17 +38,28 @@ #include "BLI_utildefines.h" +#include "DNA_space_types.h" #include "DNA_screen_types.h" #include "RNA_access.h" +#include "RNA_enum_types.h" #include "BKE_context.h" +#include "BKE_screen.h" + #include "ED_space_api.h" /* use this to stop other capsules from being mis-used */ #define RNA_CAPSULE_ID "RNA_HANDLE" #define RNA_CAPSULE_ID_INVALID "RNA_HANDLE_REMOVED" +static EnumPropertyItem region_draw_mode_items[] = { + {REGION_DRAW_POST_PIXEL, "POST_PIXEL", 0, "Post Pixel", ""}, + {REGION_DRAW_POST_VIEW, "POST_VIEW", 0, "Post View", ""}, + {REGION_DRAW_PRE_VIEW, "PRE_VIEW", 0, "Pre View", ""}, + {0, NULL, 0, NULL, NULL} +}; + static void cb_region_draw(const bContext *C, ARegion *UNUSED(ar), void *customdata) { PyObject *cb_func, *cb_args, *result; @@ -56,8 +67,8 @@ static void cb_region_draw(const bContext *C, ARegion *UNUSED(ar), void *customd bpy_context_set((bContext *)C, &gilstate); - cb_func = PyTuple_GET_ITEM((PyObject *)customdata, 0); - cb_args = PyTuple_GET_ITEM((PyObject *)customdata, 1); + cb_func = PyTuple_GET_ITEM((PyObject *)customdata, 1); + cb_args = PyTuple_GET_ITEM((PyObject *)customdata, 2); result = PyObject_CallObject(cb_func, cb_args); if (result) { @@ -71,6 +82,7 @@ static void cb_region_draw(const bContext *C, ARegion *UNUSED(ar), void *customd bpy_context_clear((bContext *)C, &gilstate); } +#if 0 PyObject *pyrna_callback_add(BPy_StructRNA *self, PyObject *args) { void *handle; @@ -89,12 +101,6 @@ PyObject *pyrna_callback_add(BPy_StructRNA *self, PyObject *args) if (RNA_struct_is_a(self->ptr.type, &RNA_Region)) { if (cb_event_str) { - static EnumPropertyItem region_draw_mode_items[] = { - {REGION_DRAW_POST_PIXEL, "POST_PIXEL", 0, "Post Pixel", ""}, - {REGION_DRAW_POST_VIEW, "POST_VIEW", 0, "Post View", ""}, - {REGION_DRAW_PRE_VIEW, "PRE_VIEW", 0, "Pre View", ""}, - {0, NULL, 0, NULL, NULL}}; - if (pyrna_enum_value_from_id(region_draw_mode_items, cb_event_str, &cb_event, "bpy_struct.callback_add()") < 0) { return NULL; } @@ -136,6 +142,163 @@ PyObject *pyrna_callback_remove(BPy_StructRNA *self, PyObject *args) ED_region_draw_cb_exit(((ARegion *)self->ptr.data)->type, handle); } + else { + PyErr_SetString(PyExc_TypeError, "callback_remove(): type does not support callbacks"); + return NULL; + } + + /* don't allow reuse */ + PyCapsule_SetName(py_handle, RNA_CAPSULE_ID_INVALID); + + Py_RETURN_NONE; +} +#endif + +/* reverse of rna_Space_refine() */ +static eSpace_Type rna_Space_refine_reverse(StructRNA *srna) +{ + if (srna == &RNA_SpaceView3D) return SPACE_VIEW3D; + if (srna == &RNA_SpaceGraphEditor) return SPACE_IPO; + if (srna == &RNA_SpaceOutliner) return SPACE_OUTLINER; + if (srna == &RNA_SpaceProperties) return SPACE_BUTS; + if (srna == &RNA_SpaceFileBrowser) return SPACE_FILE; + if (srna == &RNA_SpaceImageEditor) return SPACE_IMAGE; + if (srna == &RNA_SpaceInfo) return SPACE_INFO; + if (srna == &RNA_SpaceSequenceEditor) return SPACE_SEQ; + if (srna == &RNA_SpaceTextEditor) return SPACE_TEXT; + if (srna == &RNA_SpaceDopeSheetEditor) return SPACE_ACTION; + if (srna == &RNA_SpaceNLA) return SPACE_NLA; + if (srna == &RNA_SpaceTimeline) return SPACE_TIME; + if (srna == &RNA_SpaceNodeEditor) return SPACE_NODE; + if (srna == &RNA_SpaceLogicEditor) return SPACE_LOGIC; + if (srna == &RNA_SpaceConsole) return SPACE_CONSOLE; + if (srna == &RNA_SpaceUserPreferences) return SPACE_USERPREF; + if (srna == &RNA_SpaceClipEditor) return SPACE_CLIP; + return -1; +} + +PyObject *pyrna_callback_classmethod_add(PyObject *UNUSED(self), PyObject *args) +{ + void *handle; + PyObject *cls; + PyObject *cb_func, *cb_args; + char *cb_regiontype_str; + char *cb_event_str; + int cb_event; + int cb_regiontype; + StructRNA *srna; + + if (PyTuple_GET_SIZE(args) < 2) { + PyErr_SetString(PyExc_ValueError, "handler_add(handle): expected at least 2 args"); + return NULL; + } + + cls = PyTuple_GET_ITEM(args, 0); + if (!(srna = pyrna_struct_as_srna(cls, FALSE, "handler_add"))) { + return NULL; + } + cb_func = PyTuple_GET_ITEM(args, 1); + if (!PyCallable_Check(cb_func)) { + PyErr_SetString(PyExc_TypeError, "first argument isn't callable"); + return NULL; + } + + /* class spesific callbacks */ + if (RNA_struct_is_a(srna, &RNA_Space)) { + if (!PyArg_ParseTuple(args, "OOO!ss:Space.draw_handler_add", + &cls, &cb_func, /* already assigned, no matter */ + &PyTuple_Type, &cb_args, &cb_regiontype_str, &cb_event_str)) + { + return NULL; + } + + if (pyrna_enum_value_from_id(region_draw_mode_items, cb_event_str, &cb_event, "bpy_struct.callback_add()") < 0) { + return NULL; + } + else if (pyrna_enum_value_from_id(region_type_items, cb_regiontype_str, &cb_regiontype, "bpy_struct.callback_add()") < 0) { + return NULL; + } + else { + const eSpace_Type spaceid = rna_Space_refine_reverse(srna); + if (spaceid == -1) { + PyErr_Format(PyExc_TypeError, "unknown space type '%.200s'", RNA_struct_identifier(srna)); + return NULL; + } + else { + SpaceType *st = BKE_spacetype_from_id(spaceid); + ARegionType *art = BKE_regiontype_from_id(st, cb_regiontype); + + handle = ED_region_draw_cb_activate(art, cb_region_draw, (void *)args, cb_event); + Py_INCREF(args); + } + } + } + else { + PyErr_SetString(PyExc_TypeError, "callback_add(): type does not support callbacks"); + return NULL; + } + + return PyCapsule_New((void *)handle, RNA_CAPSULE_ID, NULL); +} + +PyObject *pyrna_callback_classmethod_remove(PyObject *UNUSED(self), PyObject *args) +{ + PyObject *cls; + PyObject *py_handle; + void *handle; + void *customdata; + StructRNA *srna; + char *cb_regiontype_str; + int cb_regiontype; + + if (PyTuple_GET_SIZE(args) < 2) { + PyErr_SetString(PyExc_ValueError, "callback_remove(handle): expected at least 2 args"); + return NULL; + } + + cls = PyTuple_GET_ITEM(args, 0); + if (!(srna = pyrna_struct_as_srna(cls, FALSE, "callback_remove"))) { + return NULL; + } + py_handle = PyTuple_GET_ITEM(args, 1); + handle = PyCapsule_GetPointer(py_handle, RNA_CAPSULE_ID); + if (handle == NULL) { + PyErr_SetString(PyExc_ValueError, "callback_remove(handle): NULL handle given, invalid or already removed"); + return NULL; + } + + if (RNA_struct_is_a(srna, &RNA_Space)) { + if (!PyArg_ParseTuple(args, "OO!s:Space.draw_handler_remove", + &cls, &PyCapsule_Type, &py_handle, /* already assigned, no matter */ + &cb_regiontype_str)) + { + return NULL; + } + + customdata = ED_region_draw_cb_customdata(handle); + Py_DECREF((PyObject *)customdata); + + if (pyrna_enum_value_from_id(region_type_items, cb_regiontype_str, &cb_regiontype, "bpy_struct.callback_remove()") < 0) { + return NULL; + } + else { + const eSpace_Type spaceid = rna_Space_refine_reverse(srna); + if (spaceid == -1) { + PyErr_Format(PyExc_TypeError, "unknown space type '%.200s'", RNA_struct_identifier(srna)); + return NULL; + } + else { + SpaceType *st = BKE_spacetype_from_id(spaceid); + ARegionType *art = BKE_regiontype_from_id(st, cb_regiontype); + + ED_region_draw_cb_exit(art, handle); + } + } + } + else { + PyErr_SetString(PyExc_TypeError, "callback_remove(): type does not support callbacks"); + return NULL; + } /* don't allow reuse */ PyCapsule_SetName(py_handle, RNA_CAPSULE_ID_INVALID); diff --git a/source/blender/python/intern/bpy_rna_callback.h b/source/blender/python/intern/bpy_rna_callback.h index 7824d2b082d..4b801f35654 100644 --- a/source/blender/python/intern/bpy_rna_callback.h +++ b/source/blender/python/intern/bpy_rna_callback.h @@ -28,5 +28,10 @@ struct BPy_StructRNA; struct PyObject; +#if 0 PyObject *pyrna_callback_add(BPy_StructRNA *self, PyObject *args); PyObject *pyrna_callback_remove(BPy_StructRNA *self, PyObject *args); +#endif + +PyObject *pyrna_callback_classmethod_add(PyObject *cls, PyObject *args); +PyObject *pyrna_callback_classmethod_remove(PyObject *cls, PyObject *args); |