I'm writing a script that contains both an operator and a panel. Both the operator and the panel are created in the script's register()
method. In my panel's draw()
method, I'd like to be able to get a reference to the operator object so I can access its properties. Is there a way to look up the operator object using its ID?
--- Edit
To elaborate on the above - I'm trying to create an object picker field. The idea is that I have a string field called 'target'. I want my NormalToolPropsPanel
panel to display a string field representing the target
field of my operator. Then when the user clicks on the eyedropper icon, they can pick an object in the scene and its name will be filled into the field.
class ModalDrawOperator(bpy.types.Operator):
"""Adjust normals"""
bl_idname = "kitfox.normal_tool"
bl_label = "Normal Tool Kitfox"
prop_brush_type : bpy.props.EnumProperty(
items=(
('FIXED', "Fixed", "Normals are in a fixed direction"),
('ATTRACT', "Attract", "Normals point toward target object"),
('REPEL', "Repel", "Normals point away from target object")
),
default='FIXED'
)
prop_strength : bpy.props.FloatProperty(
name="Strength", description="Amount to adjust mesh normal", default = 1, min=0, max = 1
)
prop_normal = bpy.props.FloatVectorProperty(name="Normal", description="Direction of normal in Fixed mode", default = (0, 1, 0))
prop_target = bpy.props.StringProperty(name="Target", description="Object Attract and Repel mode reference", default="")
def mouse_down(self, context, event):
#Do the work here
pass
def modal(self, context, event):
context.area.tag_redraw()
if event.type in {'MIDDLEMOUSE', 'WHEELUPMOUSE', 'WHEELDOWNMOUSE'}:
# allow navigation
return {'PASS_THROUGH'}
elif event.type == 'MOUSEMOVE':
pass
elif event.type == 'LEFTMOUSE':
self.mouse_down(context, event)
pass
elif event.type in {'RIGHTMOUSE', 'ESC'}:
bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW')
print("norm tool cancelled")
return {'CANCELLED'}
return {'PASS_THROUGH'}
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._context = context
self._handle = bpy.types.SpaceView3D.draw_handler_add(draw_callback, args, 'WINDOW', 'POST_VIEW')
self.mouse_path = []
context.window_manager.modal_handler_add(self)
return {'RUNNING_MODAL'}
else:
self.report({'WARNING'}, "View3D not found, cannot run operator")
return {'CANCELLED'}
#------------------------
class NTTargetPickerOperator(bpy.types.Operator):
"""Pick object with the mouse"""
bl_idname = "kitfox.nt_pick_target_object"
bl_label = "Normal Tool Pick Target Object Kitfox"
def mouse_down(self, context, event):
mouse_pos = (event.mouse_region_x, event.mouse_region_y)
ctx = bpy.context
region = context.region
rv3d = context.region_data
view_vector = view3d_utils.region_2d_to_vector_3d(region, rv3d, mouse_pos)
ray_origin = view3d_utils.region_2d_to_origin_3d(region, rv3d, mouse_pos)
viewlayer = bpy.context.view_layer
result, location, normal, index, object, matrix = context.scene.ray_cast(viewlayer.depsgraph, ray_origin, view_vector)
if result:
print("--picked " + object.name)
#This doesn't work - I want to set the property 'target' on my operator
bpy.ops.kitfox.normal_tool["prop_target.set"] = object.name
def modal(self, context, event):
if event.type == 'LEFTMOUSE':
self.mouse_down(context, event)
bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW')
return {'FINISHED'}
elif event.type in {'RIGHTMOUSE', 'ESC'}:
bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW')
print("pick target object cancelled")
return {'CANCELLED'}
else:
return {'PASS_THROUGH'}
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._context = context
self._handle = bpy.types.SpaceView3D.draw_handler_add(draw_callback, args, 'WINDOW', 'POST_VIEW')
context.window_manager.modal_handler_add(self)
return {'RUNNING_MODAL'}
else:
self.report({'WARNING'}, "View3D not found, cannot run operator")
return {'CANCELLED'}
#------------------------
class NormalToolPropsPanel(bpy.types.Panel):
"""Properties Panel for the Normal Tool on tool shelf"""
bl_label = "Normal Tool Properties Panel"
bl_idname = "3D_VIEW_PT_normal_tool_props"
bl_space_type = 'VIEW_3D'
bl_region_type = 'UI'
def draw(self, context):
layout = self.layout
obj = context.object
props = layout.operator(ModalDrawOperator.bl_idname)
row = layout.row()
#Not working - I want to refer to the property in my operator
row.prop(bpy.ops.kitfox.normal_tool, "prop_target", expand=True)
pickOp = layout.operator(NTTargetPickerOperator.bl_idname, icon="EYEDROPPER")
#------------------------
def register():
bpy.utils.register_class(NTTargetPickerOperator)
bpy.utils.register_class(ModalDrawOperator)
bpy.utils.register_class(NormalToolPropsPanel)
def unregister():
bpy.utils.unregister_class(NTTargetPickerOperator)
bpy.utils.unregister_class(ModalDrawOperator)
bpy.utils.unregister_class(NormalToolPropsPanel)
if __name__ == "__main__":
register()
context.active_operator
$\endgroup$props = self.layout.operator("foo.bar")
is a reference to its properties, which can be set in draw method withprops.prop = 33
, trying to uselayout.prop(props, "prop")
however will not work. (Given your since deleted answer) Please elaborate on what is the expectation here. $\endgroup$bpy.types.ID
as a subclass. An operatorbpy.types.Operator
is not an ID object. AFAICT this could be replaced by having a "kitfox tools" property group with the target object as a pointer property tobpy.types.Object
which can be set via eyedropper see blender.stackexchange.com/a/159155/15543 $\endgroup$