From 0cc59b9bb7d46a5a8a7e4c9cf88bfe794a0c675b Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Sun, 21 Feb 2010 14:05:02 +0000 Subject: [PATCH] generic modal operator to make adjusting almost any rna property with the mouse possible with a few lines. Example which is similar to interactive lamp adjusting in 2.4x ... wm.context_modal_mouse(path_iter="selected_editable_objects", path_item="data.spot_size") Added lamp Wkey menu back. --- release/scripts/op/wm.py | 86 ++++++++++++++++++++++ release/scripts/ui/space_view3d.py | 37 ++++++++++ source/blender/editors/object/object_ops.c | 2 + 3 files changed, 125 insertions(+) diff --git a/release/scripts/op/wm.py b/release/scripts/op/wm.py index 6d2c105ea29..33e691f7674 100644 --- a/release/scripts/op/wm.py +++ b/release/scripts/op/wm.py @@ -297,6 +297,91 @@ doc_new = StringProperty(name="Edit Description", description="", maxlen=1024, default="") + +class WM_OT_context_modal_mouse(bpy.types.Operator): + '''Adjust arbitrary values with mouse input''' + bl_idname = "wm.context_modal_mouse" + bl_label = "Context Modal Mouse" + + path_iter = StringProperty(description="The path relative to the context, must point to an iterable.") + path_item = StringProperty(description="The path from each iterable to the value (int or float)") + input_scale = FloatProperty(default=0.01, description="Scale the mouse movement by this value before applying the delta") + invert = BoolProperty(default=False, description="Invert the mouse input") + initial_x = IntProperty(options={'HIDDEN'}) + + _values = {} + + def _values_store(self, context): + path_iter = self.properties.path_iter + path_item = self.properties.path_item + + self._values.clear() + values = self._values + + for item in getattr(context, path_iter): + try: + value_orig = eval("item." + path_item) + except: + continue + + # check this can be set, maybe this is library data. + try: + exec("item.%s = %s" % (path_item, value_orig)) + except: + continue + + values[item] = value_orig + + + def _values_delta(self, delta): + delta *= self.properties.input_scale + if self.properties.invert: + delta = -delta + + path_item = self.properties.path_item + for item, value_orig in self._values.items(): + exec("item.%s = %s" % (path_item, value_orig + delta)) + + def _values_restore(self): + path_item = self.properties.path_item + for item, value_orig in self._values.items(): + exec("item.%s = %s" % (path_item, value_orig)) + + self._values.clear() + + def _values_clear(self): + self._values.clear() + + def modal(self, context, event): + event_type = event.type + + if event_type == 'MOUSEMOVE': + delta = event.mouse_x - self.properties.initial_x + self._values_delta(delta) + + elif 'LEFTMOUSE' == event_type: + self._values_clear() + return {'FINISHED'} + + elif event_type in ('RIGHTMOUSE', 'ESCAPE'): + self._values_restore() + return {'FINISHED'} + + return {'RUNNING_MODAL'} + + def invoke(self, context, event): + self._values_store(context) + + if not self._values: + self.report({'WARNING'}, "Nothing to operate on: %s[ ].%s" % (self.properties.path_iter, self.properties.path_item)) + return {'CANCELLED'} + else: + self.properties.initial_x = event.mouse_x + + context.manager.add_modal_handler(self) + return {'RUNNING_MODAL'} + + class WM_OT_doc_view(bpy.types.Operator): '''Load online reference docs''' bl_idname = "wm.doc_view" @@ -433,6 +518,7 @@ classes = [ WM_OT_context_toggle_enum, WM_OT_context_cycle_enum, WM_OT_context_cycle_int, + WM_OT_context_modal_mouse, WM_OT_doc_view, WM_OT_doc_edit, diff --git a/release/scripts/ui/space_view3d.py b/release/scripts/ui/space_view3d.py index 1fc2447bcfc..3a1bca75baa 100644 --- a/release/scripts/ui/space_view3d.py +++ b/release/scripts/ui/space_view3d.py @@ -700,6 +700,42 @@ class VIEW3D_MT_object_clear(bpy.types.Menu): layout.operator("object.origin_clear", text="Origin") +class VIEW3D_MT_object_specials(bpy.types.Menu): + bl_label = "Specials" + + def poll(self, context): + # add more special types + obj = context.object + return bool(obj and obj.type == 'LAMP') + + def draw(self, context): + layout = self.layout + + obj = context.object + if obj and obj.type == 'LAMP': + layout.operator_context = 'INVOKE_REGION_WIN' + + props = layout.operator("wm.context_modal_mouse", text="Spot Size") + props.path_iter = "selected_editable_objects" + props.path_item = "data.spot_size" + props.input_scale = 0.01 + + props = layout.operator("wm.context_modal_mouse", text="Distance") + props.path_iter = "selected_editable_objects" + props.path_item = "data.distance" + props.input_scale = 0.1 + + props = layout.operator("wm.context_modal_mouse", text="Clip Start") + props.path_iter = "selected_editable_objects" + props.path_item = "data.shadow_buffer_clip_start" + props.input_scale = 0.05 + + props = layout.operator("wm.context_modal_mouse", text="Clip End") + props.path_iter = "selected_editable_objects" + props.path_item = "data.shadow_buffer_clip_end" + props.input_scale = 0.05 + + class VIEW3D_MT_object_apply(bpy.types.Menu): bl_label = "Apply" @@ -2141,6 +2177,7 @@ classes = [ VIEW3D_MT_uv_map, # Edit Menus VIEW3D_MT_object, # Object Menu + VIEW3D_MT_object_specials, VIEW3D_MT_object_apply, VIEW3D_MT_object_clear, VIEW3D_MT_object_parent, diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c index c87442c29ed..d7ffa1d983b 100644 --- a/source/blender/editors/object/object_ops.c +++ b/source/blender/editors/object/object_ops.c @@ -336,6 +336,8 @@ void ED_keymap_object(wmKeyConfig *keyconf) WM_keymap_verify_item(keymap, "GROUP_OT_objects_add_active", GKEY, KM_PRESS, KM_SHIFT|KM_CTRL, 0); WM_keymap_verify_item(keymap, "GROUP_OT_objects_remove_active", GKEY, KM_PRESS, KM_SHIFT|KM_ALT, 0); + WM_keymap_add_menu(keymap, "VIEW3D_MT_object_specials", WKEY, KM_PRESS, 0, 0); + for(i=0; i<=5; i++) { kmi = WM_keymap_add_item(keymap, "OBJECT_OT_subdivision_set", ZEROKEY+i, KM_PRESS, KM_CTRL, 0); RNA_int_set(kmi->ptr, "level", i);