- template with an example of a modal operator drawing with opengl (draw a line on the screen)

- access to event.mouse_region_x/y
- basic type checking to callback functions (use PyCapsule names)
This commit is contained in:
Campbell Barton 2010-02-28 09:36:02 +00:00
parent 67af290bd1
commit 5369bd9c21
4 changed files with 100 additions and 12 deletions

@ -0,0 +1,69 @@
import BGL
def draw_callback_px(self, context):
print("mouse points", len(self.mouse_path))
# 50% alpha, 2 pixel width line
BGL.glEnable(BGL.GL_BLEND)
BGL.glColor4f(0.0, 0.0, 0.0, 0.5)
BGL.glLineWidth(2)
BGL.glBegin(BGL.GL_LINE_STRIP)
for x, y in self.mouse_path:
BGL.glVertex2i(x, y)
BGL.glEnd()
# restore opengl defaults
BGL.glLineWidth(1)
BGL.glDisable(BGL.GL_BLEND)
BGL.glColor4f(0.0, 0.0, 0.0, 1.0)
class ModalDrawOperator(bpy.types.Operator):
'''Draw a line with the mouse'''
bl_idname = "object.modal_operator"
bl_label = "Simple Modal Operator"
def modal(self, context, event):
context.area.tag_redraw()
if event.type == 'MOUSEMOVE':
self.mouse_path.append((event.mouse_region_x, event.mouse_region_y))
elif event.type == 'LEFTMOUSE':
context.region.callback_remove(self._handle)
return {'FINISHED'}
elif event.type in ('RIGHTMOUSE', 'ESC'):
context.region.callback_remove(self._handle)
return {'CANCELLED'}
return {'RUNNING_MODAL'}
def invoke(self, context, event):
if context.area.type == 'VIEW_3D':
context.manager.add_modal_handler(self)
# 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.mouse_path = []
return {'RUNNING_MODAL'}
else:
self.report({'WARNING'}, "View3D not found, cannot run operator")
return {'CANCELLED'}
def register():
bpy.types.register(ModalDrawOperator)
def unregister():
bpy.types.unregister(ModalDrawOperator)
if __name__ == "__main__":
register()

@ -170,8 +170,7 @@ static void unit_dual_convert(double value, bUnitCollection *usys,
{
bUnitDef *unit= unit_best_fit(value, usys, NULL, 1);
if(value < 0.0) *value_a= -floor(-value/unit->scalar) * unit->scalar;
else *value_a= floor( value/unit->scalar) * unit->scalar;
*value_a= (value < 0.0 ? ceil:floor)(value/unit->scalar) * unit->scalar;
*value_b= value - (*value_a);
*unit_a= unit;

@ -1088,6 +1088,16 @@ static void rna_def_event(BlenderRNA *brna)
RNA_def_property_int_sdna(prop, NULL, "y");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Mouse Y Position", "The window relative horizontal location of the mouse");
prop= RNA_def_property(srna, "mouse_region_x", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "mval[0]");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Mouse X Position", "The region relative vertical location of the mouse");
prop= RNA_def_property(srna, "mouse_region_y", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "mval[1]");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Mouse Y Position", "The region relative horizontal location of the mouse");
prop= RNA_def_property(srna, "mouse_prev_x", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "prevx");

@ -32,12 +32,9 @@
#include "BKE_context.h"
#include "ED_space_api.h"
EnumPropertyItem region_draw_mode_items[] = {
{REGION_DRAW_POST_VIEW, "POST_VIEW", 0, "Pose View", ""},
{REGION_DRAW_POST_PIXEL, "POST_PIXEL", 0, "Post Pixel", ""},
{REGION_DRAW_PRE_VIEW, "PRE_VIEW", 0, "Pre View", ""},
{0, NULL, 0, NULL, NULL}};
/* use this to stop other capsules from being mis-used */
#define RNA_CAPSULE_ID "RNA_HANDLE"
#define RNA_CAPSULE_ID_INVALID "RNA_HANDLE_REMOVED"
void cb_region_draw(const bContext *C, ARegion *ar, void *customdata)
{
@ -74,6 +71,12 @@ PyObject *pyrna_callback_add(BPy_StructRNA *self, PyObject *args)
if(RNA_struct_is_a(self->ptr.type, &RNA_Region)) {
EnumPropertyItem region_draw_mode_items[] = {
{REGION_DRAW_POST_VIEW, "POST_VIEW", 0, "Pose View", ""},
{REGION_DRAW_POST_PIXEL, "POST_PIXEL", 0, "Post Pixel", ""},
{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;
@ -81,24 +84,28 @@ PyObject *pyrna_callback_add(BPy_StructRNA *self, PyObject *args)
Py_INCREF(args);
}
else {
PyErr_SetString(PyExc_TypeError, "callbcak_add(): type does not suppport cllbacks");
PyErr_SetString(PyExc_TypeError, "callback_add(): type does not suppport callbacks");
return NULL;
}
return PyCapsule_New((void *)handle, NULL, NULL);
return PyCapsule_New((void *)handle, RNA_CAPSULE_ID, NULL);
}
PyObject *pyrna_callback_remove(BPy_StructRNA *self, PyObject *args)
{
PyObject *py_handle;
PyObject *py_args;
void *handle;
void *customdata;
if (!PyArg_ParseTuple(args, "O!:callback_remove", &PyCapsule_Type, &py_handle))
return NULL;
handle= PyCapsule_GetPointer(py_handle, NULL);
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(self->ptr.type, &RNA_Region)) {
customdata= ED_region_draw_cb_customdata(handle);
@ -107,5 +114,8 @@ PyObject *pyrna_callback_remove(BPy_StructRNA *self, PyObject *args)
ED_region_draw_cb_exit(((ARegion *)self->ptr.data)->type, handle);
}
/* dont allow reuse */
PyCapsule_SetName(py_handle, RNA_CAPSULE_ID_INVALID);
Py_RETURN_NONE;
}