Add menu and some cleanup

This commit is contained in:
ChristopheSeux
2024-02-26 11:26:49 +01:00
parent 917531f59a
commit 150bae5920
13 changed files with 778 additions and 571 deletions
+383 -252
View File
@@ -1,9 +1,11 @@
import bpy
from bpy.props import EnumProperty, IntProperty, BoolProperty
from ..constants import PICKERS
from ..core.bl_utils import get_view_3d_override
from bpy.props import EnumProperty, IntProperty, BoolProperty, StringProperty
from bpy.types import Operator, Menu
from ..constants import PICKERS, SHADERS
from ..core.addon_utils import get_picker_collection
from ..core.bl_utils import get_view_3d_override, split_path, eval_attr
from ..core.geometry_utils import bounding_rect
from ..core.picker import get_picker_path, pack_picker, unpack_picker
from ..core.picker import get_picker_path, pack_picker, unpack_picker, load_picker_data
#from .func_bgl import draw_callback_px
#from .func_bgl import select_bone
#from core.picker import *
@@ -16,95 +18,28 @@ import json
import os
vertex_shader = '''
layout (location = 0) in vec2 pos;
flat out vec2 startPos;
out vec2 vertPos;
uniform mat4 viewMatrix;
void main()
{
vec4 outPos = viewMatrix * vec4(pos.x, pos.y, 0.0, 1.0);
gl_Position = outPos;
vertPos = pos.xy / outPos.w;
startPos = vertPos;
}
'''
fragment_shader = '''
flat in vec2 startPos;
in vec2 vertPos;
out vec4 fragColor;
uniform vec4 color;
uniform float dashSize;
uniform float gapSize;
void main()
{
vec2 dir = (vertPos.xy - startPos.xy);
float dist = length(dir);
if (fract(dist / (dashSize + gapSize)) > dashSize/(dashSize + gapSize))
discard;
fragColor = color;
}
'''
def draw_callback(self):
#print('draw callback border')
if not self.draw_border:
return
gpu.state.blend_set('ALPHA')
#print('DRAW BORDER')
self.color_shader.bind()
self.color_shader.uniform_float("color", self.bg_color)
self.bg_batch.draw(self.color_shader)
self.dash_shader.bind()
matrix = gpu.matrix.get_projection_matrix()
self.dash_shader.uniform_float("color", self.border_color)
self.dash_shader.uniform_float("viewMatrix", matrix)
self.dash_shader.uniform_float("dashSize", 5)
self.dash_shader.uniform_float("gapSize", 4)
self.contour_batch.draw(self.dash_shader)
gpu.state.blend_set('NONE')
def is_picker_space(context):
sp = context.space_data
if sp and (sp.type == 'NODE_EDITOR' and sp.tree_type == 'RigPickerTree'):
def is_picker_space(space_data=None):
if not space_data:
space_data = bpy.context.space_data
if space_data and (space_data.type == 'NODE_EDITOR' and space_data.tree_type == 'RigPickerTree'):
return True
return False
class RP_OT_box_select(bpy.types.Operator):
"""Tooltip"""
class RP_OT_box_select(Operator):
"""Box Select bones in the picker view"""
bl_idname = "node.rp_box_select"
bl_label = "Picker Box Select"
mode: EnumProperty(items=[(i, i.title(), '') for i in ('SET', 'EXTEND', 'SUBSTRACT')])
color_shader = gpu.shader.from_builtin('UNIFORM_COLOR')
dash_shader = gpu.types.GPUShader(vertex_shader, fragment_shader)
@classmethod
def poll(cls, context):
if not is_picker_space(context):
if not is_picker_space(context.space_data):
return
ob = context.object
@@ -120,6 +55,31 @@ class RP_OT_box_select(bpy.types.Operator):
return 'SET'
'''
def draw_callback(self):
#print('draw callback border')
if not self.draw_border:
return
gpu.state.blend_set('ALPHA')
#print('DRAW BORDER')
self.color_shader.bind()
self.color_shader.uniform_float("color", self.bg_color)
self.bg_batch.draw(self.color_shader)
self.dash_shader.bind()
matrix = gpu.matrix.get_projection_matrix()
self.dash_shader.uniform_float("color", self.border_color)
self.dash_shader.uniform_float("viewMatrix", matrix)
self.dash_shader.uniform_float("dashSize", 5)
self.dash_shader.uniform_float("gapSize", 4)
self.contour_batch.draw(self.dash_shader)
gpu.state.blend_set('NONE')
def invoke(self, context, event):
#print(f'invoke: type={event.type}, value={event.value}, ctrl={event.ctrl}, shift={event.shift}, alt={event.alt}')
@@ -140,7 +100,9 @@ class RP_OT_box_select(bpy.types.Operator):
self.bg_color = [1, 1, 1, 0.05]
#args = (self, context)
self._handle = bpy.types.SpaceNodeEditor.draw_handler_add(draw_callback, (self,), 'WINDOW', 'POST_PIXEL')
self.color_shader = gpu.shader.from_builtin('UNIFORM_COLOR')
self.dash_shader = SHADERS['dashed_line']
self._handle = bpy.types.SpaceNodeEditor.draw_handler_add(self.draw_callback, (), 'WINDOW', 'POST_PIXEL')
context.window_manager.modal_handler_add(self)
@@ -163,12 +125,12 @@ class RP_OT_box_select(bpy.types.Operator):
self.region.tag_redraw()
if event.value == 'RELEASE':
return self.release_event()
return self.release_event(context)
return {'RUNNING_MODAL'}
def release_event(self):
scn = bpy.context.scene
def release_event(self, context):
scn = context.scene
if scn.rig_picker.use_pick_bone:
self.picker.assign_bone_event()
@@ -181,173 +143,246 @@ class RP_OT_box_select(bpy.types.Operator):
bpy.ops.ed.undo_push(message="Box Select")
return self.exit()
def exit(self):
#print('Border Select Finished')
return self.exit(context)
def exit(self, context):
bpy.types.SpaceNodeEditor.draw_handler_remove(self._handle, 'WINDOW')
self.region.tag_redraw()
context.region.tag_redraw()
return {'FINISHED'}
class RP_OT_picker_transform(bpy.types.Operator):
"""Tooltip"""
class RP_OT_picker_transform(Operator):
"""Transform Bones in the picker view"""
bl_idname = "node.picker_transform"
bl_label = "Move Bone in Picker View"
bl_label = "Transform Bone in Picker View"
mode : EnumProperty(items=[(m, m.title(), '') for m in ('TRANSLATE', 'ROTATE', 'SCALE')])
mode : EnumProperty(items=[(m, m.title(), '') for m in ('ROTATE', 'SCALE')])
@classmethod
def poll(cls, context):
return is_picker_space(context)
return context.selected_pose_bones and is_picker_space(context.space_data)
'''
def execute(self, context):
with context.temp_override(**get_view_3d_override()):
if self.mode == 'TRANSLATE':
bpy.ops.transform.translate("INVOKE_DEFAULT")
elif self.mode == 'ROTATE':
bpy.ops.transform.rotate("INVOKE_DEFAULT")
elif self.mode == 'SCALE':
bpy.ops.transform.resize("INVOKE_DEFAULT")
def draw_callback(self):
gpu.state.blend_set('ALPHA')
gpu.state.line_width_set(2)
return {"FINISHED"}
self.dash_shader.bind()
matrix = gpu.matrix.get_projection_matrix()
self.dash_shader.uniform_float("color", [0, 0, 0, 1])
self.dash_shader.uniform_float("viewMatrix", matrix)
self.dash_shader.uniform_float("dashSize", 5)
self.dash_shader.uniform_float("gapSize", 4)
self.batch = batch_for_shader(self.dash_shader, 'LINE_LOOP', {"pos": [self.view_center, self.mouse]})
self.batch.draw(self.dash_shader)
gpu.state.line_width_set(1)
gpu.state.blend_set('NONE')
'''
def invoke(self, context, event):
self.override = get_view_3d_override()
if self.mode == 'TRANSLATE':
with context.temp_override(**self.override):
if event.alt:
bpy.ops.pose.loc_clear()
else:
bpy.ops.transform.translate("INVOKE_DEFAULT")
return {"FINISHED"}
elif self.mode == 'ROTATE' and event.alt:
with context.temp_override(**self.override):
bpy.ops.pose.rot_clear()
return {"FINISHED"}
elif self.mode == 'SCALE' and event.alt:
with context.temp_override(**self.override):
bpy.ops.pose.scale_clear()
return {"FINISHED"}
self.mouse = event.mouse_region_x, event.mouse_region_y
self.center = context.active_pose_bone.matrix.translation.copy()
self.view_center = Vector((int(context.region.width / 2), int(context.region.height / 2)))
self.mouse_start = Vector((event.mouse_region_x, event.mouse_region_y))
self.mouse = Vector((0, 0))
transform_type = context.scene.tool_settings.transform_pivot_point
self.center = context.active_pose_bone.matrix.to_translation()
if transform_type == 'MEDIAN_POINT':
origins = [b.matrix.to_translation() for b in context.selected_pose_bones]
self.center = sum(origins, Vector()) / len(context.selected_pose_bones)
# self.bone_data = {}
# for bone in context.selected_pose_bones:
# self.bone_data[bone] = bone.matrix.copy()
self.bone_data = {b: b.matrix.copy() for b in context.selected_pose_bones}
space = self.override['area'].spaces.active
view_matrix = space.region_3d.view_matrix
if space.region_3d.view_perspective == 'CAMERA':
view_matrix = context.scene.camera.matrix_world
context.window.cursor_modal_set('MOVE_X')
self.view_vector = Vector((0, 0, 1))
if self.mode == 'ROTATE':
self.view_vector.rotate(view_matrix)
elif self.mode == 'SCALE':
self.view_vector = Vector((0, 0, 0))
self.transform_type = "VIEW"
self.transform_types = ["VIEW", 'GLOBAL', 'LOCAL']
if context.scene.transform_orientation_slots[0].type == 'LOCAL':
self.transform_types = ["VIEW", 'LOCAL', 'GLOBAL']
self.transform_orientation = context.scene.transform_orientation_slots[0].type
#self.dash_shader = SHADERS['dashed_line']
#self._handle = bpy.types.SpaceNodeEditor.draw_handler_add(self.draw_callback, (), 'WINDOW', 'POST_PIXEL')
context.window_manager.modal_handler_add(self)
return {'RUNNING_MODAL'}
def change_transform_type(self):
indices = {0: 1, 1:2, 2:1}
index = self.transform_types.index(self.transform_type)
new_index = indices[index]
self.transform_type = self.transform_types[new_index]
def release_event(self, context):
scn = bpy.context.scene
# Insert keyframe
#bpy.ops.ed.undo_push(message="Transform")
if scn.tool_settings.use_keyframe_insert_auto:
try:
bpy.ops.animtoolbox.insert_keyframe()
except Exception:
self.report({"WARNING"}, 'You need animtoolbox addon for inserting keyframe')
self.exit(context)
def exit(self, context):
#bpy.types.SpaceNodeEditor.draw_handler_remove(self._handle, 'WINDOW')
context.window.cursor_modal_restore()
#context.region.tag_redraw()
def modal(self, context, event):
delta_x = (event.mouse_region_x - self.mouse[0]) / 100
#delta_y = (event.mouse_region_y - self.mouse[1]) / 1000
#for bone, matrix in self.bone_data.items():
# bone.matrix.#translation = matrix.translation + Vector((delta_x, 0, delta_y))
center = context.active_pose_bone.tail
scn = context.scene
cam = scn.camera
self.mouse = Vector((event.mouse_region_x, event.mouse_region_y))
if self.mode == 'ROTATE':
delta = (event.mouse_region_x - self.mouse_start[0]) / 100
elif self.mode == 'SCALE':
delta = 1 + (event.mouse_region_x - self.mouse_start[0]) / 100
#delta = (self.mouse - self.view_center).length / (self.mouse_start - self.view_center).length
transform_type = self.transform_type
#self.batch = batch_for_shader(self.dash_shader, 'LINE_STRIP', {"pos": [self.mouse_start, self.mouse]})
#context.area.tag_redraw()
#rotation_axis = cam.matrix_world.to_3x3().transposed().col[2]
#rotation_matrix = Matrix.Rotation(delta_x, 4, Vector((0, 0, -1)) @ cam.matrix_world)
view_vec = Vector((0, 0, 1))
view_vec.rotate(cam.matrix_world)
rotation_matrix = Matrix.Rotation(delta_x, 4, view_vec)
#rot_mat = Matrix.Rotation(delta_x, 4, "Z")
#rot_mat = scn.camera.matrix_world.inverted() @ rot_mat
#rot_mat = Matrix.LocRotScale(center, Euler((0, 0, delta_x)), (1, 1, 1))
if event.type == "MOUSEMOVE":
for bone, matrix in self.bone_data.items():
#center =
mat = matrix.copy()
mat.translation -= self.center
mat = rotation_matrix @ mat
mat.translation += self.center
bone.matrix = mat
#rotation_matrix.translation = matrix.translation
#mat = matrix.copy().to_3x3()
#mat.rotate(rotation_matrix)
#mat = mat.to_4x4()
#mat.translation = matrix.translation
#bone.matrix = mat
#bone.matrix = matrix.inverted() @ (rotation_matrix @ bone_mat)
#bone.matrix.translation = 0, 0, 0
#bone.matrix = rotation_matrix @ matrix
#bone.matrix = matrix @ (matrix.inverted() @ rotation_matrix)
#bone.matrix.translation = matrix.translation
#print('Rotate', delta_x)
#with context.temp_override(**get_view_3d_override()):
#for bone, matrix in self.bone_data.items():
# bone.rotation_euler.x = delta_x
#bpy.ops.transform.rotate(value=delta_x)
#print(delta_x, delta_y)
if event.type=="LEFTMOUSE" and event.value == 'RELEASE':
#print(event.type, event.value)
if self.mode == 'ROTATE' and event.type == "R" and event.value == 'PRESS':
with context.temp_override(**self.override):
self.exit(context)
bpy.ops.transform.trackball('INVOKE_DEFAULT')
return {'FINISHED'}
if event.type == "RIGHTMOUSE":
if event.type == "LEFTMOUSE" and event.value == 'RELEASE':
self.release_event(context)
return {'FINISHED'}
if event.type in {"RIGHTMOUSE", "ESC"}:
for bone, matrix in self.bone_data.items():
bone.matrix = matrix
self.exit(context)
return {'CANCELLED'}
elif event.type == "X" and event.value == 'PRESS':
self.change_transform_type()
self.view_vector = Vector((1, 0, 0))
#transform_type = self.transform_orientation
elif event.type == "Y" and event.value == 'PRESS':
self.change_transform_type()
self.view_vector = Vector((0, 1, 0))
#transform_type = self.transform_orientation
elif event.type == "Z" and event.value == 'PRESS':
self.change_transform_type()
self.view_vector = Vector((0, 0, 1))
#transform_type = self.transform_orientation
elif event.type == "MOUSEMOVE":
if self.mode == 'ROTATE':
transform_matrix = Matrix.Rotation(delta, 4, self.view_vector)
elif self.mode == 'SCALE':
if self.view_vector.length:
transform_matrix = Matrix.Scale(delta, 4, self.view_vector)
else:
transform_matrix = Matrix.Scale(delta, 4)
for bone, matrix in self.bone_data.items():
center = self.center
if scn.tool_settings.transform_pivot_point == "INDIVIDUAL_ORIGINS":
center = matrix.to_translation()
if self.mode == 'ROTATE':
if transform_type == 'LOCAL':
view_vector = self.view_vector.copy()
view_vector.rotate(matrix)
transform_matrix = Matrix.Rotation(delta, 4, view_vector)
elif self.mode == 'SCALE':
if transform_type == 'LOCAL':
view_vector = self.view_vector.copy()
view_vector.rotate(matrix)
transform_matrix = Matrix.Scale(delta, 4, view_vector)
mat = matrix.copy()
mat.translation -= center
mat = transform_matrix @ mat
mat.translation += center
bone.matrix = mat
return {'RUNNING_MODAL'}
class RP_OT_function_execute(bpy.types.Operator):
bl_idname = "rigpicker.function_execute"
bl_label = 'Function Execute'
class RP_OT_toogle_property(Operator):
"""Invert a bone custom property"""
shape_index = IntProperty()
bl_idname = "rigpicker.toogle_property"
bl_label = 'Toogle Property'
data_path : StringProperty()
@classmethod
def poll(cls, context):
if not is_picker_space(context):
return
return is_picker_space(context.space_data)
def execute(self,context):
event = self.event
ob = context.object
shape = ob.data.rig_picker['shapes'][self.shape_index]
try:
value = ob.path_resolve(self.data_path)
except Exception:
return {'CANCELLED'}
function = shape['function']
if shape.get('variables'):
variables=shape['variables'].to_dict()
else:
variables={}
data = ob
prop_name = self.data_path
#if '.' in self.data_path:
# data, prop = prop_name.rsplit('.', 1)
value = type(value)(not value)
exec(f'{repr(ob)}.{self.data_path} = {value}')
variables['event']=event
globals()[function](variables)
#setattr(data, prop_name, value)
bpy.ops.object.mode_set(mode='OBJECT')
bpy.ops.object.mode_set(mode='POSE')
if context.scene.tool_settings.use_keyframe_insert_auto:
bone_name, _ = split_path(self.data_path)
ob.keyframe_insert(data_path=self.data_path, group=bone_name)
context.area.tag_redraw()
return {'FINISHED'}
def invoke(self,context,event):
self.event = event
return self.execute(context)
class RP_OT_reload_picker(Operator):
"""Reload the picker shapes"""
class RP_OT_reload_picker(bpy.types.Operator):
bl_idname = "rigpicker.reload_picker"
bl_label = 'Reload Picker'
@@ -356,22 +391,37 @@ class RP_OT_reload_picker(bpy.types.Operator):
# if not is_picker_space(context):
# return
def execute(self,context):
PICKERS.clear()
def execute(self, context):
#PICKERS.clear()
if context.object.type == 'ARMATURE':
rig = context.object
else:
collection = get_picker_collection(context.object)
rig = collection.rig_picker.rig
for a in context.screen.areas:
a.tag_redraw()
load_picker_data(rig)
'''
for area in context.screen.areas:
#print(area.type, is_picker_space(area.spaces.active))
if is_picker_space(area.spaces.active):
print('Tag Redraw Region', area.type)
area.regions[0].tag_redraw()
area.tag_redraw()
'''
return {"FINISHED"}
class RP_OT_toogle_bone_layer(bpy.types.Operator):
class RP_OT_toogle_bone_layer(Operator):
"""Toogle bone layer visibility when double clicking on a bone"""
bl_idname = "rigpicker.toogle_bone_layer"
bl_label = 'Toogle Bone Layer'
@classmethod
def poll(cls, context):
if not is_picker_space(context):
if not is_picker_space(context.space_data):
return
ob = context.object
@@ -396,13 +446,14 @@ class RP_OT_toogle_bone_layer(bpy.types.Operator):
return {"FINISHED"}
class RP_OT_context_menu_picker(bpy.types.Operator):
class RP_OT_context_menu_picker(Operator):
"""Display Menu with the custom properties of the hovered bone if any or the active bone"""
bl_idname = "node.context_menu_picker"
bl_label = 'Context Menu Picker'
@classmethod
def poll(cls, context):
return is_picker_space(context)
return is_picker_space(context.space_data)
def execute(self, context):
bpy.ops.wm.call_menu(name='RP_MT_context_menu')
@@ -410,75 +461,91 @@ class RP_OT_context_menu_picker(bpy.types.Operator):
return {"FINISHED"}
class RP_OT_pack_picker(bpy.types.Operator):
class RP_OT_pack_picker(Operator):
"""Pack Unpack the picker on the rig"""
bl_idname = "rigpicker.pack_picker"
bl_label = 'Toogle Bone Layer'
bl_label = 'Pack Picker'
@classmethod
def poll(cls, context):
ob = context.object
return (ob and ob.type == 'ARMATURE' and ob.data.rig_picker.source)
return (ob and ob.type == 'ARMATURE' and ob.data.rig_picker.sources)
def execute(self, context):
print('Pack Picker')
print('Pack Pickers...')
rig = context.object
picker_path = get_picker_path(rig)
if 'picker' in rig.data.rig_picker.keys():
if 'pickers' in rig.data.rig_picker.keys():
unpack_picker(rig)
self.report({"INFO"}, f'The picker is unpacked')
return {"FINISHED"}
if not picker_path.exists():
self.report({"ERROR"}, f'The path of the picker not exist: {picker_path}')
return {"CANCELLED"}
pack_picker(rig)
if not rig.data.rig_picker['pickers']:
self.report({"ERROR"}, f'No picker have been packed')
return {"CANCELLED"}
elif len(rig.data.rig_picker['pickers']) < len(rig.data.rig_picker.sources):
self.report({"WARNING"}, f'No all pickers have been packed')
return {"FINISHED"}
self.report({"INFO"}, f'The picker is packed')
return {"FINISHED"}
class RP_OT_call_operator(bpy.types.Operator):
class RP_OT_call_operator(Operator):
bl_idname = "rigpicker.call_operator"
bl_label = 'Call operator'
operator : bpy.props.StringProperty()
view_3d : bpy.props.BoolProperty()
operator : StringProperty()
arguments : StringProperty()
invoke: BoolProperty()
view_3d : BoolProperty()
@classmethod
def poll(cls, context):
return is_picker_space(context)
return is_picker_space(context.space_data)
def execute(self, context):
if not self.operator.startswith('bpy.ops'):
print("Operator call_operator can only execute operator")
return {"FINISHED"}
print('CAll Operator')
@classmethod
def description(cls, context, properties):
try:
op = eval_attr(bpy.ops, properties.operator).get_rna_type()
return op.description
except AttributeError:
return 'Call operator'
context.area.tag_redraw()
def execute(self, context):
#context.area.tag_redraw()
override = {}
if self.view_3d:
override = get_view_3d_override()
arguments = json.loads(self.arguments or "{}")
with context.temp_override(**override):
try:
exec(self.operator)
ops = eval_attr(bpy.ops, self.operator)
if self.invoke:
ops('INVOKE_DEFAULT', **arguments)
else:
ops(**arguments)
except Exception as e:
self.report({"ERROR"}, e)
print(e)
self.report({"ERROR"}, f'The operator {self.operator} cannot be called')
return {"CANCELLED"}
context.area.tag_redraw()
return {"FINISHED"}
class RP_MT_context_menu(bpy.types.Menu):
class RP_MT_context_menu(Menu):
bl_label = "Context Menu"
#bl_idname = "RP_MT_context_menu"
# Set the menu operators and draw functions
def draw(self, context):
@@ -491,7 +558,10 @@ class RP_MT_context_menu(bpy.types.Menu):
if picker.hover_shape and picker.hover_shape.type == 'bone':
bone = picker.hover_shape.bone
else:
bone = context.active_pose_bone
if bone:
for key in bone.keys():
layout.prop(bone,f'["{key}"]', slider=True)
@@ -499,7 +569,51 @@ class RP_MT_context_menu(bpy.types.Menu):
#layout.operator("rigidbody.objects_add", text="B Add Passive").type = 'PASSIVE'
class RP_OT_add_picker_source(bpy.types.Operator):
class RP_OT_add_picker_collection(Operator):
bl_idname = "rigpicker.add_picker_collection"
bl_label = "Add a Picker Collection"
bl_description = "Add a Picker Collection"
bl_options = {'UNDO', 'REGISTER'}
@classmethod
def poll(cls, context):
ob = context.object
return (ob and ob.type == 'ARMATURE')
def execute(self, context):
scn = context.scene
ob = context.object
name = ob.name
if name.endswith('_rig'):
name = name[:-4]
canvas_name = f'canevas_{name}'
canvas_points = [(-0.5, 0.5, 0), (0.5, 0.5, 0), (0.5, -0.5, 0), (-0.5, -0.5, 0)]
canvas_faces = [(0, 1, 2, 3)]
canvas_mesh = bpy.data.meshes.new(canvas_name)
canvas_mesh.from_pydata(canvas_points, [], canvas_faces)
canvas_mesh.update(calc_edges=True)
canvas_ob = bpy.data.objects.new(canvas_name, canvas_mesh)
canvas_ob.rig_picker.shape_type = 'DISPLAY'
col = bpy.data.collections.new(f'Picker {name}')
col.rig_picker.enabled = True
col.rig_picker.rig = ob
col.rig_picker.canvas = canvas_ob
col.objects.link(canvas_ob)
scn.collection.children.link(col)
self.report({"INFO"}, f"New Picker Collection {col.name} Created")
return {'FINISHED'}
class RP_OT_add_picker_source(Operator):
bl_idname = "rigpicker.add_picker_source"
bl_label = "Add a Picker source"
bl_description = "Add a Picker source"
@@ -512,7 +626,7 @@ class RP_OT_add_picker_source(bpy.types.Operator):
return {'FINISHED'}
class RP_OT_remove_picker_source(bpy.types.Operator):
class RP_OT_remove_picker_source(Operator):
bl_idname = "rigpicker.remove_picker_source"
bl_label = "Delete a Picker source"
bl_description = "Delete a Picker source"
@@ -527,7 +641,7 @@ class RP_OT_remove_picker_source(bpy.types.Operator):
return {'FINISHED'}
class RP_OT_fit_picker(bpy.types.Operator):
class RP_OT_fit_picker(Operator):
bl_idname = "rigpicker.fit_picker"
bl_label = "Fit Picker"
bl_description = "Fit Picker in 2d view"
@@ -537,7 +651,7 @@ class RP_OT_fit_picker(bpy.types.Operator):
@classmethod
def poll(cls, context):
return is_picker_space(context) and PICKERS.get(context.object)
return is_picker_space(context.space_data) and PICKERS.get(context.object)
def execute(self, context):
ob = context.object
@@ -585,43 +699,58 @@ def register_keymaps():
keymaps.append((km, kmi))
kmi = km.keymap_items.new("rigpicker.call_operator", type="NUMPAD_PERIOD", value="PRESS")
kmi.properties.operator = "bpy.ops.view3d.view_selected()"
kmi.properties.operator = "view3d.view_selected"
kmi.properties.view_3d = True
keymaps.append((km, kmi))
kmi = km.keymap_items.new("rigpicker.call_operator", type="A", value="PRESS")
kmi.properties.operator = "bpy.ops.pose.select_all(action='SELECT')"
kmi.properties.operator = "pose.select_all"
kmi.properties.arguments = '{"action": "SELECT"}'
keymaps.append((km, kmi))
kmi = km.keymap_items.new("rigpicker.call_operator", type="A", value="PRESS", alt=True)
kmi.properties.operator = "bpy.ops.pose.select_all(action='DESELECT')"
kmi.properties.operator = "pose.select_all"
kmi.properties.arguments = '{"action": "DESELECT"}'
keymaps.append((km, kmi))
kmi = km.keymap_items.new("rigpicker.toogle_bone_layer", type="LEFTMOUSE", value="DOUBLE_CLICK")
keymaps.append((km, kmi))
kmi = km.keymap_items.new("node.picker_transform", type="G", value="PRESS")
kmi.properties.mode = 'TRANSLATE'
kmi = km.keymap_items.new("rigpicker.call_operator", type="X", value="PRESS")
kmi.properties.operator = "animtoolbox.reset_bone"
keymaps.append((km, kmi))
kmi = km.keymap_items.new("node.picker_transform", type="G", value="PRESS", alt=True)
kmi.properties.mode = 'TRANSLATE'
kmi = km.keymap_items.new("rigpicker.call_operator", type="K", value="PRESS")
kmi.properties.operator = "animtoolbox.insert_keyframe"
keymaps.append((km, kmi))
kmi = km.keymap_items.new("anim.keyframe_delete_v3d", type="K", value="PRESS", alt=True)
keymaps.append((km, kmi))
kmi = km.keymap_items.new("rigpicker.call_operator", type="G", value="PRESS")
kmi.properties.operator = 'transform.translate'
kmi.properties.view_3d = True
kmi.properties.invoke = True
keymaps.append((km, kmi))
kmi = km.keymap_items.new("rigpicker.call_operator", type="G", value="PRESS", alt=True)
kmi.properties.operator = 'pose.loc_clear'
keymaps.append((km, kmi))
kmi = km.keymap_items.new("node.picker_transform", type="R", value="PRESS")
kmi.properties.mode = 'ROTATE'
keymaps.append((km, kmi))
kmi = km.keymap_items.new("node.picker_transform", type="R", value="PRESS", alt=True)
kmi.properties.mode = 'ROTATE'
kmi = km.keymap_items.new("rigpicker.call_operator", type="R", value="PRESS", alt=True)
kmi.properties.operator = 'pose.rot_clear'
keymaps.append((km, kmi))
kmi = km.keymap_items.new("node.picker_transform", type="S", value="PRESS")
kmi.properties.mode = 'SCALE'
keymaps.append((km, kmi))
kmi = km.keymap_items.new("node.picker_transform", type="S", value="PRESS", alt=True)
kmi.properties.mode = 'SCALE'
kmi = km.keymap_items.new("rigpicker.call_operator", type="S", value="PRESS", alt=True)
kmi.properties.operator = 'pose.scale_clear'
keymaps.append((km, kmi))
kmi = km.keymap_items.new("node.context_menu_picker", type="RIGHTMOUSE", value="PRESS")
@@ -641,9 +770,9 @@ def register_keymaps():
keymaps.append((km, kmi))
#km = wm.keyconfigs.addon.keymaps.new(name="View2D")
kmi = km.keymap_items.new("rigpicker.call_operator", type="MIDDLEMOUSE", value="PRESS")
kmi.properties.operator = "bpy.ops.view2d.pan('INVOKE_DEFAULT')"
keymaps.append((km, kmi))
#kmi = km.keymap_items.new("rigpicker.call_operator", type="MIDDLEMOUSE", value="PRESS")
#kmi.properties.operator = "bpy.ops.view2d.pan('INVOKE_DEFAULT')"
#keymaps.append((km, kmi))
def unregister_keymaps():
@@ -653,7 +782,7 @@ def unregister_keymaps():
classes = (
RP_OT_box_select,
RP_OT_function_execute,
RP_OT_toogle_property,
RP_OT_reload_picker,
RP_OT_toogle_bone_layer,
RP_OT_call_operator,
@@ -663,7 +792,8 @@ classes = (
RP_OT_pack_picker,
RP_OT_add_picker_source,
RP_OT_remove_picker_source,
RP_OT_fit_picker
RP_OT_fit_picker,
RP_OT_add_picker_collection
#RP_OT_ui_draw
)
@@ -674,6 +804,7 @@ def register():
register_keymaps()
def unregister():
unregister_keymaps()
for cls in reversed(classes):
+9 -15
View File
@@ -8,7 +8,7 @@ from bpy.props import IntProperty
from mathutils import Matrix
from ..core.shape import get_picker_data
from ..core.addon_utils import is_shape
from ..core.addon_utils import is_shape, get_picker_collection
from ..core.bl_utils import link_mat_to_object, flip_name
@@ -77,7 +77,7 @@ class RP_OT_name_from_bone(Operator):
class RP_OT_mirror_shape(Operator):
bl_label = 'Mirror UI shape'
bl_idname = 'rigpicker.mirror_shape'
#bl_options = {'REGISTER', 'UNDO'}
#bl_options = g
@classmethod
def poll(cls, context):
@@ -86,7 +86,7 @@ class RP_OT_mirror_shape(Operator):
def execute(self,context):
scn = context.scene
ob = context.object
collection = next((c for c in ob.users_collection if c.rig_picker.enabled), None)
collection = get_picker_collection(ob)
objects = context.selected_objects
# Remove mirror object:
@@ -192,39 +192,33 @@ class RP_OT_save_picker(Operator):
scn = context.scene
ob = context.object
print('SAve Picker', self.index)
if self.index == -1:
collection = next((c for c in ob.users_collection if c.rig_picker.enabled), None)
collection = get_picker_collection(ob)
else:
source = context.active_object.data.rig_picker.sources[self.index].source
source = Path(bpy.path.abspath(source, library=ob.data.library)).resolve()
collection = next((c for c in set(scn.collection.children_recursive) if c.rig_picker.enabled
and Path(bpy.path.abspath(c.rig_picker.destination)).resolve() == source), None)
print('source', source)
print('colleciton', collection)
if not collection:
self.report({"ERROR"}, 'No Picker found')
return {'CANCELLED'}
canvas = collection.rig_picker.canvas
rig = collection.rig_picker.rig
#rig = collection.rig_picker.rig
shapes = [o for o in collection.all_objects if o != canvas and o.type in ('MESH', 'CURVE', 'FONT')]
if not rig:
self.report({'ERROR'}, 'Choose a Rig')
return {'CANCELLED'}
if not canvas:
self.report({'ERROR'}, 'Choose a Canvas')
return {'CANCELLED'}
data = get_picker_data(shapes, canvas, rig)
picker_data = get_picker_data(collection)
picker_path = Path(bpy.path.abspath(collection.rig_picker.destination))
picker_path.write_text(json.dumps(data))
print(f'Save Picker to {picker_path}')
picker_path.write_text(json.dumps(picker_data))
bpy.ops.rigpicker.reload_picker()