Great script, lukas_t! I didn't even know about Macros :D
That fancy object ptr thing works for me, no error message in 2.67.
I solved the "remember last object"-problem in another way, maybe that is not going to give errors for you, matali. I simply used static class attributes to store snap settings and the object.
import bpy
from bpy.types import Operator, Macro
from bpy.props import *
class TranslateCursorMacro(Macro):
"""Overall macro for combining move and cursor operators"""
bl_idname = "object.translate_cursor_macro"
bl_label = "Translate Cursor"
bl_options = {'REGISTER', 'UNDO'}
@classmethod
def poll(cls, context):
if not context.active_object:
return False
return True
"""
def _find_prev_object(ptr):
for ob in bpy.data.objects:
if ob.as_pointer() == ptr:
return ob
"""
class Storage:
ob = None
use_snap = False
snap_element = 'CLOSEST'
snap_target = 'INCREMENT'
class RememberObject(Operator):
"""Store active object"""
bl_idname = "object.remember_object"
bl_label = "Remember Object"
def execute(self, context):
# XXX This is not super nice, but we don't have real
# properties shared between macro component operators.
# In an addon this might be stored as a module-level
# python variable.
context.scene["_prev_object"] = context.active_object.as_pointer()
Storage.ob = context.active_object
Storage.use_snap = context.tool_settings.use_snap
Storage.snap_element = context.tool_settings.snap_element
Storage.snap_target = context.tool_settings.snap_target
context.tool_settings.use_snap = True
context.tool_settings.snap_element = 'VERTEX'
context.tool_settings.snap_target = 'ACTIVE'
return {'FINISHED'}
class DeleteNoQuestionsObject(Operator):
"""Delete object without asking"""
bl_idname = "object.delete_no_questions"
bl_label = "Delete Object"
def execute(self, context):
# XXX The usual bpy.ops operator opens a popup
# when invoke. Use this wrapper to avoid that.
bpy.ops.object.delete('EXEC_DEFAULT')
return {'FINISHED'}
class SelectPreviousObject(Operator):
"""Select previous object"""
bl_idname = "object.select_previous_object"
bl_label = "Select Previous Object"
def execute(self, context):
context.tool_settings.use_snap = Storage.use_snap
context.tool_settings.snap_element = Storage.snap_element
context.tool_settings.snap_target = Storage.snap_target
ob = Storage.ob
if ob is None:
self.report({"WARNING"}, "Previous object not found")
return {'CANCELLED'}
"""
ptr = context.scene.get("_prev_object", None)
if ptr is None:
return {'CANCELLED'}
del context.scene["_prev_object"] # cleanup
ob = _find_prev_object(ptr)
if not ob:
self.report({"WARNING"}, "Previous object not found")
return {'CANCELLED'}
"""
for tob in bpy.data.objects:
# Avoid checking every ob, just deselect all an re-reselt previous
#tob.select = (tob == ob)
tob.select = False
ob.select = True
context.scene.objects.active = ob
return {'FINISHED'}
bpy.utils.register_class(TranslateCursorMacro)
bpy.utils.register_class(RememberObject)
bpy.utils.register_class(DeleteNoQuestionsObject)
bpy.utils.register_class(SelectPreviousObject)
TranslateCursorMacro.define("OBJECT_OT_remember_object")
TranslateCursorMacro.define("MESH_OT_primitive_uv_sphere_add")
TranslateCursorMacro.define("TRANSFORM_OT_translate")
TranslateCursorMacro.define("VIEW3D_OT_snap_cursor_to_active")
TranslateCursorMacro.define("OBJECT_OT_delete_no_questions")
TranslateCursorMacro.define("OBJECT_OT_select_previous_object")
Just in case anyone wonders how to pass parameters to the operators in the macro:
import bpy
class m(bpy.types.Macro):
bl_idname = "object.macro_test"
bl_label = "Macro Test"
bpy.utils.register_class(m)
op = m.define("TRANSFORM_OT_translate")
op.properties.constraint_axis = (True, False, False)