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 <demeter@blender.studio>2022-01-20 16:21:16 +0300
committerDemeter Dzadik <demeter@blender.studio>2022-01-25 12:58:39 +0300
commite641ac2d8a2baa146478d902a4222a3243a4f764 (patch)
treedbb2166df6ff849a8fa0d2ce58e0a9b13f8721bc
parent84f5f4699232decc2f1a8694312680b9e5159462 (diff)
Rigify: Add ability to disable installed feature sets
This patch is a continuation of D8519, was also suggested in T88711#1170152. It adds a checkbox for each feature set in the Rigify Preferences, to disable/enable that feature set without having to completely remove it from the file system. Challenges that were hopefully successfully tackled: - Keep list in sync when user manually adds or removes things through the file system instead of the "add/remove feature set" buttons in the UI. - Avoid re-building the feature set list all the time so that the checkbox states can actually be stored when the user exits Blender. - Disabling a feature set means calling its unregister function, then rebuilding the rig types and metarigs lists/menus. - Some renaming slipped in because I found the variable name "feature_set" a bit confusing. If needed, I could split this change into a separate patch or just forget about it, but I think the longer names help here. Testing would be welcome, since things turned out a bit more tricky than expected. In a follow-up patch I would like to do a code quality pass, to split the code a bit better here. There is a bit too much stuff in __init__.py in particular. I will get started on that when this gets close to being finalized. Reviewed By: angavrilov Differential Revision: https://developer.blender.org/D12260
-rw-r--r--rigify/__init__.py89
-rw-r--r--rigify/feature_set_list.py52
-rw-r--r--rigify/metarig_menu.py7
-rw-r--r--rigify/ui.py6
4 files changed, 110 insertions, 44 deletions
diff --git a/rigify/__init__.py b/rigify/__init__.py
index 20e18a42..5d8782d4 100644
--- a/rigify/__init__.py
+++ b/rigify/__init__.py
@@ -149,6 +149,33 @@ class RigifyFeatureSets(bpy.types.PropertyGroup):
name: bpy.props.StringProperty()
module_name: bpy.props.StringProperty()
+ def toggle_featureset(self, context):
+ feature_set_list.call_register_function(self.module_name, self.enabled)
+ context.preferences.addons[__package__].preferences.update_external_rigs()
+
+ enabled: bpy.props.BoolProperty(
+ name = "Enabled",
+ description = "Whether this feature-set is registered or not",
+ update = toggle_featureset,
+ default = True
+ )
+
+
+class RIGIFY_UL_FeatureSets(bpy.types.UIList):
+ def draw_item(self, context, layout, data, item, icon, active_data, active_propname):
+ rigify_prefs = data
+ feature_sets = rigify_prefs.rigify_feature_sets
+ active_set = feature_sets[rigify_prefs.active_feature_set_index]
+ feature_set_entry = item
+ if self.layout_type in {'DEFAULT', 'COMPACT'}:
+ row = layout.row()
+ row.prop(feature_set_entry, 'name', text="", emboss=False)
+
+ icon = 'CHECKBOX_HLT' if feature_set_entry.enabled else 'CHECKBOX_DEHLT'
+ row.enabled = feature_set_entry.enabled
+ layout.prop(feature_set_entry, 'enabled', text="", icon=icon, emboss=False)
+ elif self.layout_type in {'GRID'}:
+ pass
class RigifyPreferences(AddonPreferences):
# this must match the addon name, use '__package__'
@@ -157,32 +184,50 @@ class RigifyPreferences(AddonPreferences):
def register_feature_sets(self, register):
"""Call register or unregister of external feature sets"""
- for set_name in feature_set_list.get_installed_list():
+ for set_name in feature_set_list.get_enabled_modules_names():
feature_set_list.call_register_function(set_name, register)
- def update_external_rigs(self, force=False):
+ def refresh_installed_feature_sets(self):
+ """Synchronize preferences entries with what's actually in the file system."""
+ feature_set_prefs = self.rigify_feature_sets
+
+ module_names = feature_set_list.get_installed_modules_names()
+
+ # If there is a feature set preferences entry with no corresponding
+ # installed module, user must've manually removed it from the filesystem,
+ # so let's remove such entries.
+ to_delete = [ i for i, fs in enumerate(feature_set_prefs) if fs.module_name not in module_names ]
+ for i in reversed(to_delete):
+ feature_set_prefs.remove(i)
+
+ # If there is an installed feature set in the file system but no corresponding
+ # entry, user must've installed it manually. Make sure it has an entry.
+ for module_name in module_names:
+ for fs in feature_set_prefs:
+ if module_name == fs.module_name:
+ break
+ else:
+ fs = feature_set_prefs.add()
+ fs.name = feature_set_list.get_ui_name(module_name)
+ fs.module_name = module_name
+
+ def update_external_rigs(self):
"""Get external feature sets"""
- set_list = feature_set_list.get_installed_list()
- # Update feature set list
- self.rigify_feature_sets.clear()
+ self.refresh_installed_feature_sets()
- for s in set_list:
- list_entry = self.rigify_feature_sets.add()
- list_entry.name = feature_set_list.get_ui_name(s)
- list_entry.module_name = s
+ set_list = feature_set_list.get_enabled_modules_names()
- if force or len(set_list) > 0:
- # Reload rigs
- print('Reloading external rigs...')
- rig_lists.get_external_rigs(set_list)
+ # Reload rigs
+ print('Reloading external rigs...')
+ rig_lists.get_external_rigs(set_list)
- # Reload metarigs
- print('Reloading external metarigs...')
- metarig_menu.get_external_metarigs(set_list)
+ # Reload metarigs
+ print('Reloading external metarigs...')
+ metarig_menu.get_external_metarigs(set_list)
- # Re-register rig parameters
- register_rig_parameters()
+ # Re-register rig parameters
+ register_rig_parameters()
rigify_feature_sets: bpy.props.CollectionProperty(type=RigifyFeatureSets)
active_feature_set_index: IntProperty()
@@ -196,8 +241,8 @@ class RigifyPreferences(AddonPreferences):
row = layout.row()
row.template_list(
- "UI_UL_list",
- "rigify_feature_sets",
+ 'RIGIFY_UL_FeatureSets',
+ '',
self, "rigify_feature_sets",
self, 'active_feature_set_index'
)
@@ -259,8 +304,7 @@ def draw_feature_set_prefs(layout, context, featureset: RigifyFeatureSets):
op = row.operator('wm.url_open', text="Report a Bug", icon='URL')
op.url = info['tracker_url']
- op = row.operator("wm.rigify_remove_feature_set", text="Remove", icon='CANCEL')
- op.featureset = featureset.module_name
+ row.operator("wm.rigify_remove_feature_set", text="Remove", icon='CANCEL')
class RigifyName(bpy.types.PropertyGroup):
@@ -443,6 +487,7 @@ classes = (
RigifyColorSet,
RigifySelectionColors,
RigifyArmatureLayer,
+ RIGIFY_UL_FeatureSets,
RigifyFeatureSets,
RigifyPreferences,
)
diff --git a/rigify/feature_set_list.py b/rigify/feature_set_list.py
index a50bd010..cb46f5c6 100644
--- a/rigify/feature_set_list.py
+++ b/rigify/feature_set_list.py
@@ -16,6 +16,8 @@
#
#======================= END GPL LICENSE BLOCK ========================
+from typing import List
+
import bpy
from bpy.props import StringProperty
import os
@@ -44,7 +46,8 @@ def get_install_path(*, create=False):
return INSTALL_PATH
-def get_installed_list():
+def get_installed_modules_names() -> List[str]:
+ """Return a list of module names of all feature sets in the file system."""
features_path = get_install_path()
if not features_path:
return []
@@ -60,6 +63,17 @@ def get_installed_list():
return sets
+def get_enabled_modules_names() -> List[str]:
+ """Return a list of module names of all enabled feature sets."""
+ rigify_prefs = bpy.context.preferences.addons[__package__].preferences
+ installed_module_names = get_installed_modules_names()
+ rigify_feature_sets = rigify_prefs.rigify_feature_sets
+
+ enabled_module_names = { fs.module_name for fs in rigify_feature_sets if fs.enabled }
+
+ return [name for name in installed_module_names if name in enabled_module_names]
+
+
def get_module(feature_set):
return importlib.import_module('.'.join([*NAME_PREFIX, feature_set]))
@@ -88,17 +102,17 @@ def get_info_dict(feature_set):
return {}
-def call_function_safe(feature_set, name, args=[], kwargs={}):
- module = get_module_safe(feature_set)
+def call_function_safe(module_name, func_name, args=[], kwargs={}):
+ module = get_module_safe(module_name)
if module:
- func = getattr(module, name, None)
+ func = getattr(module, func_name, None)
if callable(func):
try:
return func(*args, **kwargs)
except Exception:
- print("Rigify Error: Could not call function '%s' of feature set '%s': exception occurred.\n" % (name, feature_set))
+ print(f"Rigify Error: Could not call function '{func_name}' of feature set '{module_name}': exception occurred.\n")
traceback.print_exc()
print("")
@@ -128,7 +142,7 @@ def feature_set_items(scene, context):
('rigify', 'Rigify Built-in', 'Rigs bundled with Rigify'),
]
- for fs in get_installed_list():
+ for fs in get_enabled_modules_names():
ui_name = get_ui_name(fs)
items.append((fs, ui_name, ui_name))
@@ -222,8 +236,7 @@ class DATA_OT_rigify_add_feature_set(bpy.types.Operator):
addon_prefs.update_external_rigs()
- new_index = addon_prefs.rigify_feature_sets.find(get_ui_name(fixed_dirname))
- addon_prefs.active_feature_set_index = new_index
+ addon_prefs.active_feature_set_index = len(addon_prefs.rigify_feature_sets)-1
return {'FINISHED'}
@@ -234,8 +247,6 @@ class DATA_OT_rigify_remove_feature_set(bpy.types.Operator):
bl_description = "Remove external feature set (rigs, metarigs, ui templates)"
bl_options = {"REGISTER", "UNDO", "INTERNAL"}
- featureset: StringProperty(maxlen=1024, options={'HIDDEN', 'SKIP_SAVE'})
-
@classmethod
def poll(cls, context):
return True
@@ -245,18 +256,29 @@ class DATA_OT_rigify_remove_feature_set(bpy.types.Operator):
def execute(self, context):
addon_prefs = context.preferences.addons[__package__].preferences
+ feature_sets = addon_prefs.rigify_feature_sets
+ active_idx = addon_prefs.active_feature_set_index
+ active_fs = feature_sets[active_idx]
- # Call the unregister callback of the set being removed
- call_register_function(self.featureset, False)
+ # Call the unregister callback of the set being removed.
+ if active_fs.enabled:
+ call_register_function(active_fs.module_name, register=False)
+ # Remove the feature set's folder from the file system.
rigify_config_path = get_install_path()
if rigify_config_path:
- set_path = os.path.join(rigify_config_path, self.featureset)
+ set_path = os.path.join(rigify_config_path, active_fs.module_name)
if os.path.exists(set_path):
rmtree(set_path)
- addon_prefs.update_external_rigs(force=True)
- addon_prefs.active_feature_set_index = 0
+ # Remove the feature set's entry from the addon preferences.
+ feature_sets.remove(active_idx)
+
+ # Remove the feature set's entries from the metarigs and rig types.
+ addon_prefs.update_external_rigs()
+
+ # Update active index.
+ addon_prefs.active_feature_set_index -= 1
return {'FINISHED'}
diff --git a/rigify/metarig_menu.py b/rigify/metarig_menu.py
index 48da1e89..7a48df44 100644
--- a/rigify/metarig_menu.py
+++ b/rigify/metarig_menu.py
@@ -214,17 +214,16 @@ def unregister():
for mf in menu_funcs:
bpy.types.VIEW3D_MT_armature_add.remove(mf)
-def get_external_metarigs(set_list):
+def get_external_metarigs(feature_module_names):
unregister()
# Clear and fill metarigs public variables
metarigs.clear()
get_internal_metarigs()
-
- for feature_set in set_list:
+ for module_name in feature_module_names:
try:
- base_dir, base_path = feature_set_list.get_dir_path(feature_set, METARIG_DIR)
+ base_dir, base_path = feature_set_list.get_dir_path(module_name, METARIG_DIR)
get_metarigs(metarigs['external'], base_dir, base_path)
except Exception:
diff --git a/rigify/ui.py b/rigify/ui.py
index 59dbf9b6..eac8b673 100644
--- a/rigify/ui.py
+++ b/rigify/ui.py
@@ -54,7 +54,7 @@ def build_type_list(context, rigify_types):
for r in sorted(rig_lists.rigs):
if (context.object.data.active_feature_set in ('all', rig_lists.rigs[r]['feature_set'])
- or len(feature_set_list.get_installed_list()) == 0
+ or len(feature_set_list.get_enabled_modules_names()) == 0
):
a = rigify_types.add()
a.name = r
@@ -191,7 +191,7 @@ class DATA_PT_rigify_samples(bpy.types.Panel):
id_store.rigify_active_type = 0
# Rig type list
- if len(feature_set_list.get_installed_list()) > 0:
+ if len(feature_set_list.get_enabled_modules_names()) > 0:
row = layout.row()
row.prop(context.object.data, "active_feature_set")
row = layout.row()
@@ -609,7 +609,7 @@ class BONE_PT_rigify_buttons(bpy.types.Panel):
build_type_list(context, id_store.rigify_types)
# Rig type field
- if len(feature_set_list.get_installed_list()) > 0:
+ if len(feature_set_list.get_enabled_modules_names()) > 0:
row = layout.row()
row.prop(context.object.data, "active_feature_set")
row = layout.row()