Prompted by my previous question, I was trying to create an addon to move background images with the mouse.
However, I can't figure out a good way to determine what image to move.
I thought I might somehow add a button to each background image panel in 3D view > Properties region, but is there a way to get which image's button was pressed?
Here is a modal operator (based on the template) that picks an image based on a bunch of hacks that fail in too many situations:
import bpy, math
from bpy.props import IntProperty, FloatProperty
class MoveBackgroundImage(bpy.types.Operator):
"""Move background images with the mouse"""
bl_idname = "view3d.background_image_move"
bl_label = "Move backgound image"
first_mouse_x = IntProperty()
first_mouse_y = IntProperty()
first_x = FloatProperty()
first_y = FloatProperty()
def modal(self, context, event):
if event.type == 'MOUSEMOVE':
delta_x = self.first_mouse_x - event.mouse_x
delta_y = self.first_mouse_y - event.mouse_y
if event.shift:
backimage.offset_x = self.first_x - delta_x * 0.01
backimage.offset_y = self.first_y - delta_y * 0.01
else:
backimage.offset_x = self.first_x - delta_x * 0.05
backimage.offset_y = self.first_y - delta_y * 0.05
# backimage.size = self.first_y - delta_y * 0.05
elif event.type == 'LEFTMOUSE':
return {'FINISHED'}
elif event.type in {'RIGHTMOUSE', 'ESC'}:
backimage.offset_x = self.first_x
backimage.offset_y = self.first_y
return {'CANCELLED'}
return {'RUNNING_MODAL'}
def invoke(self, context, event):
go_hack = 0
def get_view_orientation(view_matrix):
r = lambda x: round(x, 2)
view_rot = view_matrix.to_euler()
orientation_dict = {(0.0, 0.0, 0.0) : 'TOP',
(r(math.pi), 0.0, 0.0) : 'BOTTOM',
(r(-math.pi/2), 0.0, 0.0) : 'FRONT',
(r(math.pi/2), 0.0, r(-math.pi)) : 'BACK',
(r(-math.pi/2), r(math.pi/2), 0.0) : 'LEFT',
(r(-math.pi/2), r(-math.pi/2), 0.0) : 'RIGHT'}
return orientation_dict.get(tuple(map(r, view_rot)), 'UNDEFINED')
for area in bpy.context.screen.areas:
if area.type == 'VIEW_3D':
for space in area.spaces:
if space.type == 'VIEW_3D':
vmatrix = space.region_3d.view_matrix
view_orientation = get_view_orientation(vmatrix)
view_persp = space.region_3d.view_perspective
global backimage
for bgimage in space.background_images:
fail_hack = 1
bgi_axis = bgimage.view_axis
expanded = bgimage.show_expanded
if view_persp == 'ORTHO':
go_hack = 1
if view_persp == 'CAMERA':
go_hack = 1
if go_hack == 1:
if expanded: #HACK
if view_orientation != 'UNDEFINED':
if view_orientation == bgi_axis:
fail_hack = 0
backimage = bgimage
self.first_mouse_x = event.mouse_x
self.first_mouse_y = event.mouse_y
self.first_x = backimage.offset_x
self.first_y = backimage.offset_y
context.window_manager.modal_handler_add(self)
return {'RUNNING_MODAL'}
else:
fail_hack = 1
fail_message = "No active image, could not finish"
else:
if view_persp == 'CAMERA':
if bgi_axis == 'CAMERA':
fail_hack = 0
backimage = bgimage
self.first_mouse_x = event.mouse_x
self.first_mouse_y = event.mouse_y
self.first_x = backimage.offset_x
self.first_y = backimage.offset_y
context.window_manager.modal_handler_add(self)
return {'RUNNING_MODAL'}
else:
fail_hack = 1
fail_message = "No images visible in camera view"
if bgi_axis == 'ALL':
fail_hack = 0
backimage = bgimage
self.first_mouse_x = event.mouse_x
self.first_mouse_y = event.mouse_y
self.first_x = backimage.offset_x
self.first_y = backimage.offset_y
context.window_manager.modal_handler_add(self)
return {'RUNNING_MODAL'}
else:
fail_hack = 1
fail_message = "No images visible in camera view"
else:
fail_hack = 1
fail_message = "View not aligned to an axis, no images visible"
else:
fail_hack = 1
fail_message = "No active image, could not finish"
else:
fail_hack = 1
fail_message = "View not in ortho or camera perspective"
if fail_hack == 1:
self.report({'WARNING'}, fail_message)
return {'CANCELLED'}
def register():
bpy.utils.register_class(MoveBackgroundImage)
def unregister():
bpy.utils.unregister_class(MoveBackgroundImage)
if __name__ == "__main__":
register()
# test call
bpy.ops.view3d.background_image_move('INVOKE_DEFAULT')