Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender-addons.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDemeter Dzadik <Mets>2021-08-18 20:23:01 +0300
committerDemeter Dzadik <demeter@blender.studio>2021-08-18 20:36:02 +0300
commit9a7afcbcae91978db8173e205f0ec73f1d6ad440 (patch)
tree4988c90ccd139ac3f3998bab1ffb0c101e4da6c7
parent9ffc56b3b7fbc1b76ff50d32ab791d27f28b2d2b (diff)
Rigify: Clean up "Rigify Buttons" panel UX
The UX for this panel felt like it could use a facelift. It was extremely ugly to look at, nothing about it was done the correct way and it broke every possible modern Blender UI convention it could. Before/After: {F10135475} {F10159077} After generating a rig: {F10159078} - Removed the "overwrite/new" enum. - If there is a target rig object, we overwrite. If not, we create. I think that's intuitive behaviour without the extra UI element. - If a rig object with the desired name already existed, but wasn't selected as the target rig, the "overwrite" option still overwrote that rig. I don't agree with that because this meant messing with data without indicating that that data is going to be messed with. Unaware users could lose data/work. With these changes, the worst thing that can happen is that your rig ends up with a .001 suffix. - Removed the "rig name" text input field. Before this patch, this would always rename your rig object and your rig script text datablock, which I think is more frustrating than useful. Now you can simply rename them after generation yourself, and the names will be kept in subsequent generations. - Renamed the panel from "Rigify Buttons" to "Rigify Generation" in pose/object mode and "Rigify Samples" in edit mode. - Changed the "Advanced Options" into a sub-panel instead. - Single column layout. - Added an info message to show the name of the successfully generated rig: {F10159079} Feedback welcome. Differential Revision: https://developer.blender.org/D11356
-rw-r--r--rigify/__init__.py16
-rw-r--r--rigify/generate.py59
-rw-r--r--rigify/rig_ui_template.py25
-rw-r--r--rigify/ui.py228
4 files changed, 137 insertions, 191 deletions
diff --git a/rigify/__init__.py b/rigify/__init__.py
index 1bb633f6..1eac52ae 100644
--- a/rigify/__init__.py
+++ b/rigify/__init__.py
@@ -507,20 +507,6 @@ def register():
IDStore.rigify_types = CollectionProperty(type=RigifyName)
IDStore.rigify_active_type = IntProperty(name="Rigify Active Type", description="The selected rig type")
- bpy.types.Armature.rigify_advanced_generation = BoolProperty(name="Advanced Options",
- description="Enables/disables advanced options for Rigify rig generation",
- default=False)
-
- def update_mode(self, context):
- if self.rigify_generate_mode == 'new':
- self.rigify_force_widget_update = False
-
- bpy.types.Armature.rigify_generate_mode = EnumProperty(name="Rigify Generate Rig Mode",
- description="'Generate Rig' mode. In 'overwrite' mode the features of the target rig will be updated as defined by the metarig. In 'new' mode a new rig will be created as defined by the metarig. Current mode",
- update=update_mode,
- items=( ('overwrite', 'overwrite', ''),
- ('new', 'new', '')))
-
bpy.types.Armature.rigify_force_widget_update = BoolProperty(name="Force Widget Update",
description="Forces Rigify to delete and rebuild all the rig widgets. if unset, only missing widgets will be created",
default=False)
@@ -579,8 +565,6 @@ def unregister():
del ArmStore.rigify_colors_index
del ArmStore.rigify_colors_lock
del ArmStore.rigify_theme_to_add
- del ArmStore.rigify_advanced_generation
- del ArmStore.rigify_generate_mode
del ArmStore.rigify_force_widget_update
del ArmStore.rigify_target_rig
del ArmStore.rigify_rig_ui
diff --git a/rigify/generate.py b/rigify/generate.py
index aa9a9a84..bb3f1ac0 100644
--- a/rigify/generate.py
+++ b/rigify/generate.py
@@ -65,53 +65,28 @@ class Generator(base_generate.BaseGenerator):
return rig_module.Rig
-
- def __create_rig_object(self):
- scene = self.scene
- id_store = self.id_store
+
+ def __create_rig_object(self) -> bpy.types.Object:
+ """ Check if the generated rig already exists, so we can
+ regenerate in the same object. If not, create a new
+ object to generate the rig in.
+ """
meta_data = self.metarig.data
- # Check if the generated rig already exists, so we can
- # regenerate in the same object. If not, create a new
- # object to generate the rig in.
- print("Fetch rig.")
-
- self.rig_new_name = name = meta_data.rigify_rig_basename or "rig"
-
- obj = None
-
- if meta_data.rigify_generate_mode == 'overwrite':
- obj = meta_data.rigify_target_rig
+ target_rig = meta_data.rigify_target_rig
+ if target_rig:
+ return target_rig
- if not obj and name in scene.objects:
- obj = scene.objects[name]
+ rig_new_name = meta_data.rigify_rig_basename or "rig"
- if obj:
- self.rig_old_name = obj.name
+ target_rig = bpy.data.objects.new(rig_new_name, bpy.data.armatures.new(rig_new_name))
+ target_rig.display_type = 'WIRE'
+ self.collection.objects.link(target_rig)
- obj.name = name
- obj.data.name = obj.name
-
- rig_collections = filter_layer_collections_by_object(self.usable_collections, obj)
- self.layer_collection = (rig_collections + [self.layer_collection])[0]
- self.collection = self.layer_collection.collection
-
- elif name in bpy.data.objects:
- obj = bpy.data.objects[name]
-
- if not obj:
- obj = bpy.data.objects.new(name, bpy.data.armatures.new(name))
- obj.display_type = 'WIRE'
- self.collection.objects.link(obj)
-
- elif obj.name not in self.collection.objects: # rig exists but was deleted
- self.collection.objects.link(obj)
-
- meta_data.rigify_target_rig = obj
- obj.data.pose_position = 'POSE'
+ meta_data.rigify_target_rig = target_rig
+ target_rig.data.pose_position = 'POSE'
- self.obj = obj
- return obj
+ return target_rig
def __create_widget_group(self):
@@ -383,7 +358,7 @@ class Generator(base_generate.BaseGenerator):
#------------------------------------------
# Create/find the rig object and set it up
- obj = self.__create_rig_object()
+ self.obj = obj = self.__create_rig_object()
# Get rid of anim data in case the rig already existed
print("Clear rig animation data.")
diff --git a/rigify/rig_ui_template.py b/rigify/rig_ui_template.py
index c83dd02b..8780461d 100644
--- a/rigify/rig_ui_template.py
+++ b/rigify/rig_ui_template.py
@@ -1167,27 +1167,10 @@ class ScriptGenerator(base_generate.GeneratorPlugin):
layer_layout += [(l.name, l.row)]
# Generate the UI script
- if metarig.data.rigify_rig_basename:
- rig_ui_name = metarig.data.rigify_rig_basename + '_ui.py'
- else:
- rig_ui_name = 'rig_ui.py'
-
- script = None
-
- if metarig.data.rigify_generate_mode == 'overwrite':
- script = metarig.data.rigify_rig_ui
-
- if not script and rig_ui_name in bpy.data.texts:
- script = bpy.data.texts[rig_ui_name]
-
- if script:
- script.clear()
- script.name = rig_ui_name
-
- if script is None:
- script = bpy.data.texts.new(rig_ui_name)
-
- metarig.data.rigify_rig_ui = script
+ script = metarig.data.rigify_rig_ui
+ if not script:
+ script = bpy.data.texts.new("rig_ui.py")
+ metarig.data.rigify_rig_ui = script
for s in OrderedDict.fromkeys(self.ui_imports):
script.write(s + "\n")
diff --git a/rigify/ui.py b/rigify/ui.py
index 6ba455da..2dda2485 100644
--- a/rigify/ui.py
+++ b/rigify/ui.py
@@ -59,140 +59,139 @@ def build_type_list(context, rigify_types):
a = rigify_types.add()
a.name = r
+class DATA_PT_rigify_generate_base(bpy.types.Panel):
+ @classmethod
+ def poll(cls, context):
+ obj = context.object
+ if not context.object:
+ return False
+ return obj.type == 'ARMATURE' \
+ and obj.data.get("rig_id") is None \
+ and obj.mode in {'POSE', 'OBJECT'}
-class DATA_PT_rigify_buttons(bpy.types.Panel):
- bl_label = "Rigify Buttons"
bl_space_type = 'PROPERTIES'
bl_region_type = 'WINDOW'
bl_context = "data"
- @classmethod
- def poll(cls, context):
- if not context.object:
- return False
- return context.object.type == 'ARMATURE' and context.active_object.data.get("rig_id") is None
+class DATA_PT_rigify_generate(DATA_PT_rigify_generate_base):
+ bl_label = "Rigify Generation"
def draw(self, context):
- C = context
layout = self.layout
+ layout.use_property_split = True
+ layout.use_property_decorate = False
obj = context.object
- id_store = C.window_manager
+ id_store = context.window_manager
+
+ armature_id_store = context.object.data
- if obj.mode in {'POSE', 'OBJECT'}:
- armature_id_store = C.object.data
+ show_warning = False
+ show_update_metarig = False
+ show_not_updatable = False
+ show_upgrade_face = False
- WARNING = "Warning: Some features may change after generation"
- show_warning = False
- show_update_metarig = False
- show_not_updatable = False
- show_upgrade_face = False
+ check_props = ['IK_follow', 'root/parent', 'FK_limb_follow', 'IK_Stretch']
- check_props = ['IK_follow', 'root/parent', 'FK_limb_follow', 'IK_Stretch']
+ for bone in obj.pose.bones:
+ if bone.bone.layers[30] and (list(set(bone.keys()) & set(check_props))):
+ show_warning = True
+ break
- for bone in obj.pose.bones:
- if bone.bone.layers[30] and (list(set(bone.keys()) & set(check_props))):
- show_warning = True
+ for b in obj.pose.bones:
+ if b.rigify_type in outdated_types.keys():
+ old_bone = b.name
+ old_rig = b.rigify_type
+ if outdated_types[b.rigify_type]:
+ show_update_metarig = True
+ else:
+ show_update_metarig = False
+ show_not_updatable = True
break
+ elif b.rigify_type == 'faces.super_face':
+ show_upgrade_face = True
- for b in obj.pose.bones:
- if b.rigify_type in outdated_types.keys():
- old_bone = b.name
- old_rig = b.rigify_type
- if outdated_types[b.rigify_type]:
- show_update_metarig = True
- else:
- show_update_metarig = False
- show_not_updatable = True
- break
- elif b.rigify_type == 'faces.super_face':
- show_upgrade_face = True
-
- if show_warning:
- layout.label(text=WARNING, icon='ERROR')
-
- enable_generate_and_advanced = not (show_not_updatable or show_update_metarig)
-
- if show_not_updatable:
- layout.label(text="WARNING: This metarig contains deprecated rigify rig-types and cannot be upgraded automatically.", icon='ERROR')
- layout.label(text="("+old_rig+" on bone "+old_bone+")")
- elif show_update_metarig:
- layout.label(text="This metarig contains old rig-types that can be automatically upgraded to benefit of rigify's new features.", icon='ERROR')
- layout.label(text="("+old_rig+" on bone "+old_bone+")")
- layout.operator("pose.rigify_upgrade_types", text="Upgrade Metarig")
- elif show_upgrade_face:
- layout.label(text="This metarig uses the old face rig.", icon='INFO')
- layout.operator("pose.rigify_upgrade_face")
+ if show_warning:
+ layout.label(text="Warning: Some features may change after generation", icon='ERROR')
- row = layout.row()
- # Rig type field
+ if show_not_updatable:
+ layout.label(text="WARNING: This metarig contains deprecated rigify rig-types and cannot be upgraded automatically.", icon='ERROR')
+ layout.label(text="("+old_rig+" on bone "+old_bone+")")
+ layout.label(text="If you want to use it anyway try enabling the legacy mode before generating again.")
- col = layout.column(align=True)
- col.active = (not 'rig_id' in C.object.data)
+ layout.operator("pose.rigify_switch_to_legacy", text="Switch to Legacy")
+ elif show_update_metarig:
+ layout.label(text="This metarig contains old rig-types that can be automatically upgraded to benefit of rigify's new features.", icon='ERROR')
+ layout.label(text="("+old_rig+" on bone "+old_bone+")")
+ layout.label(text="To use it as-is you need to enable legacy mode.",)
+ layout.operator("pose.rigify_upgrade_types", text="Upgrade Metarig")
+ elif show_upgrade_face:
+ layout.label(text="This metarig uses the old face rig.", icon='INFO')
+ layout.operator("pose.rigify_upgrade_face")
- col.separator()
- row = col.row()
- row.operator("pose.rigify_generate", text="Generate Rig", icon='POSE_HLT')
+ enable_generation = not (show_not_updatable or show_update_metarig)
- row.enabled = enable_generate_and_advanced
+ col = layout.column()
+ col.enabled = enable_generation
- if armature_id_store.rigify_advanced_generation:
- icon = 'UNLOCKED'
- else:
- icon = 'LOCKED'
+ # Make it clear whether we are generating a new object or overwriting existing one.
+ text = "Generate New Rig"
+ if armature_id_store.rigify_target_rig:
+ text = f'Re-Generate Target Rig'
+ col.row().operator("pose.rigify_generate", text=text, icon='POSE_HLT')
- col = layout.column()
- col.enabled = enable_generate_and_advanced
- row = col.row()
- row.prop(armature_id_store, "rigify_advanced_generation", toggle=True, icon=icon)
+class DATA_PT_rigify_generate_advanced(DATA_PT_rigify_generate_base):
+ bl_label = "Advanced"
+ bl_parent_id = 'DATA_PT_rigify_generate'
- if armature_id_store.rigify_advanced_generation:
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+ layout.use_property_decorate = False
- row = col.row(align=True)
- row.prop(armature_id_store, "rigify_generate_mode", expand=True)
-
- main_row = col.row(align=True).split(factor=0.3)
- col1 = main_row.column()
- col2 = main_row.column()
- col1.label(text="Rig Name")
- row = col1.row()
- row.label(text="Target Rig")
- row.enabled = (armature_id_store.rigify_generate_mode == "overwrite")
- row = col1.row()
- row.label(text="Target UI")
- row.enabled = (armature_id_store.rigify_generate_mode == "overwrite")
-
- row = col2.row(align=True)
- row.prop(armature_id_store, "rigify_rig_basename", text="", icon="SORTALPHA")
-
- row = col2.row(align=True)
- row.prop(armature_id_store, "rigify_target_rig", text="")
- row.enabled = (armature_id_store.rigify_generate_mode == "overwrite")
-
- row = col2.row()
- row.prop(armature_id_store, "rigify_rig_ui", text="", icon='TEXT')
- row.enabled = (armature_id_store.rigify_generate_mode == "overwrite")
-
- row = col.row()
- row.prop(armature_id_store, "rigify_force_widget_update")
- if armature_id_store.rigify_generate_mode == 'new':
- row.enabled = False
-
- elif obj.mode == 'EDIT':
- # Build types list
- build_type_list(context, id_store.rigify_types)
-
- if id_store.rigify_active_type > len(id_store.rigify_types):
- id_store.rigify_active_type = 0
-
- # Rig type list
- if len(feature_set_list.get_installed_list()) > 0:
- row = layout.row()
- row.prop(context.object.data, "active_feature_set")
- row = layout.row()
- row.template_list("UI_UL_list", "rigify_types", id_store, "rigify_types", id_store, 'rigify_active_type')
+ armature_id_store = context.object.data
+
+ col = layout.column()
+ col.row().prop(armature_id_store, 'rigify_target_rig', text="Target Rig")
+ col.row().prop(armature_id_store, 'rigify_rig_ui', text="Rig UI Script")
+ col.row().prop(armature_id_store, 'rigify_force_widget_update')
- props = layout.operator("armature.metarig_sample_add", text="Add sample")
- props.metarig_type = id_store.rigify_types[id_store.rigify_active_type].name
+
+class DATA_PT_rigify_samples(bpy.types.Panel):
+ bl_label = "Rigify Samples"
+ bl_space_type = 'PROPERTIES'
+ bl_region_type = 'WINDOW'
+ bl_context = "data"
+
+ @classmethod
+ def poll(cls, context):
+ obj = context.object
+ if not obj:
+ return False
+ return obj.type == 'ARMATURE' \
+ and obj.data.get("rig_id") is None \
+ and obj.mode == 'EDIT'
+
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+ layout.use_property_decorate = False
+ obj = context.object
+ id_store = context.window_manager
+
+ # Build types list
+ build_type_list(context, id_store.rigify_types)
+
+ if id_store.rigify_active_type > len(id_store.rigify_types):
+ id_store.rigify_active_type = 0
+
+ # Rig type list
+ if len(feature_set_list.get_installed_list()) > 0:
+ layout.row().prop(obj.data, "active_feature_set")
+ row = layout.row()
+ row.template_list("UI_UL_list", "rigify_types", id_store, "rigify_types", id_store, 'rigify_active_type')
+
+ props = layout.operator("armature.metarig_sample_add", text="Add sample")
+ props.metarig_type = id_store.rigify_types[id_store.rigify_active_type].name
class DATA_PT_rigify_layer_names(bpy.types.Panel):
@@ -788,8 +787,9 @@ class Generate(bpy.types.Operator):
return is_metarig(context.object)
def execute(self, context):
+ metarig = context.object
try:
- generate.generate_rig(context, context.object)
+ generate.generate_rig(context, metarig)
except MetarigError as rig_exception:
import traceback
traceback.print_exc()
@@ -800,6 +800,8 @@ class Generate(bpy.types.Operator):
traceback.print_exc()
self.report({'ERROR'}, 'Generation has thrown an exception: ' + str(rig_exception))
+ else:
+ self.report({'INFO'}, 'Successfully generated: "' + metarig.data.rigify_target_rig.name + '"')
finally:
bpy.ops.object.mode_set(mode='OBJECT')
@@ -1378,7 +1380,9 @@ classes = (
DATA_MT_rigify_bone_groups_context_menu,
DATA_PT_rigify_bone_groups,
DATA_PT_rigify_layer_names,
- DATA_PT_rigify_buttons,
+ DATA_PT_rigify_generate,
+ DATA_PT_rigify_generate_advanced,
+ DATA_PT_rigify_samples,
BONE_PT_rigify_buttons,
VIEW3D_PT_rigify_animation_tools,
VIEW3D_PT_tools_rigify_dev,