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:
Diffstat (limited to 'rigify/operators/generic_ui_list.py')
-rw-r--r--rigify/operators/generic_ui_list.py187
1 files changed, 187 insertions, 0 deletions
diff --git a/rigify/operators/generic_ui_list.py b/rigify/operators/generic_ui_list.py
new file mode 100644
index 00000000..46f093b3
--- /dev/null
+++ b/rigify/operators/generic_ui_list.py
@@ -0,0 +1,187 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+from bpy.types import Operator, UILayout, Context
+from bpy.props import EnumProperty, StringProperty
+
+
+def get_context_attr(context: Context, data_path):
+ return context.path_resolve(data_path)
+
+
+def set_context_attr(context: Context, data_path, value):
+ items = data_path.split('.')
+ setattr(context.path_resolve('.'.join(items[:-1])), items[-1], value)
+
+
+class GenericUIListOperator(Operator):
+ bl_options = {'REGISTER', 'UNDO', 'INTERNAL'}
+
+ list_context_path: StringProperty()
+ active_idx_context_path: StringProperty()
+
+ def get_list(self, context):
+ return get_context_attr(context, self.list_context_path)
+
+ def get_active_index(self, context):
+ return get_context_attr(context, self.active_idx_context_path)
+
+ def set_active_index(self, context, index):
+ set_context_attr(context, self.active_idx_context_path, index)
+
+
+class UILIST_OT_entry_remove(GenericUIListOperator):
+ """Remove the selected entry from the list"""
+
+ bl_idname = "ui.rigify_list_entry_remove"
+ bl_label = "Remove Selected Entry"
+
+ def execute(self, context):
+ my_list = self.get_list(context)
+ active_index = self.get_active_index(context)
+
+ my_list.remove(active_index)
+
+ to_index = min(active_index, len(my_list) - 1)
+
+ self.set_active_index(context, to_index)
+
+ return {'FINISHED'}
+
+
+class UILIST_OT_entry_add(GenericUIListOperator):
+ """Add an entry to the list"""
+
+ bl_idname = "ui.rigify_list_entry_add"
+ bl_label = "Add Entry"
+
+ def execute(self, context):
+ my_list = self.get_list(context)
+ active_index = self.get_active_index(context)
+
+ to_index = min(len(my_list), active_index + 1)
+
+ my_list.add()
+ my_list.move(len(my_list) - 1, to_index)
+ self.set_active_index(context, to_index)
+
+ return {'FINISHED'}
+
+
+class UILIST_OT_entry_move(GenericUIListOperator):
+ """Move an entry in the list up or down"""
+
+ bl_idname = "ui.rigify_list_entry_move"
+ bl_label = "Move Entry"
+
+ direction: EnumProperty(
+ name="Direction",
+ items=[('UP', 'UP', 'UP'),
+ ('DOWN', 'DOWN', 'DOWN')],
+ default='UP'
+ )
+
+ def execute(self, context):
+ my_list = self.get_list(context)
+ active_index = self.get_active_index(context)
+
+ to_index = active_index + (1 if self.direction == 'DOWN' else -1)
+
+ if to_index > len(my_list) - 1:
+ to_index = 0
+ elif to_index < 0:
+ to_index = len(my_list) - 1
+
+ my_list.move(active_index, to_index)
+ self.set_active_index(context, to_index)
+
+ return {'FINISHED'}
+
+
+def draw_ui_list(
+ layout, context, class_name="UI_UL_list", *,
+ list_context_path: str, # Eg. "object.vertex_groups".
+ active_idx_context_path: str, # Eg., "object.vertex_groups.active_index".
+ insertion_operators=True,
+ move_operators=True,
+ menu_class_name="",
+ **kwargs) -> UILayout:
+ """
+ This is intended as a replacement for row.template_list().
+ By changing the requirements of the parameters, we can provide the Add, Remove and Move Up/Down
+ operators without the person implementing the UIList having to worry about that stuff.
+ """
+ row = layout.row()
+
+ list_owner = get_context_attr(context, ".".join(list_context_path.split(".")[:-1]))
+ list_prop_name = list_context_path.split(".")[-1]
+ idx_owner = get_context_attr(context, ".".join(active_idx_context_path.split(".")[:-1]))
+ idx_prop_name = active_idx_context_path.split(".")[-1]
+
+ my_list = get_context_attr(context, list_context_path)
+
+ row.template_list(
+ class_name,
+ list_context_path if class_name == 'UI_UL_list' else "",
+ list_owner, list_prop_name,
+ idx_owner, idx_prop_name,
+ rows=4 if len(my_list) > 0 else 1,
+ **kwargs
+ )
+
+ col = row.column()
+
+ if insertion_operators:
+ add_op = col.operator(UILIST_OT_entry_add.bl_idname, text="", icon='ADD')
+ add_op.list_context_path = list_context_path
+ add_op.active_idx_context_path = active_idx_context_path
+
+ row = col.row()
+ row.enabled = len(my_list) > 0
+ remove_op = row.operator(UILIST_OT_entry_remove.bl_idname, text="", icon='REMOVE')
+ remove_op.list_context_path = list_context_path
+ remove_op.active_idx_context_path = active_idx_context_path
+
+ col.separator()
+
+ if menu_class_name != '':
+ # noinspection SpellCheckingInspection
+ col.menu(menu_class_name, icon='DOWNARROW_HLT', text="")
+ col.separator()
+
+ if move_operators and len(my_list) > 0:
+ col = col.column()
+ col.enabled = len(my_list) > 1
+ move_up_op = col.operator(UILIST_OT_entry_move.bl_idname, text="", icon='TRIA_UP')
+ move_up_op.direction = 'UP'
+ move_up_op.list_context_path = list_context_path
+ move_up_op.active_idx_context_path = active_idx_context_path
+
+ move_down_op = col.operator(UILIST_OT_entry_move.bl_idname, text="", icon='TRIA_DOWN')
+ move_down_op.direction = 'DOWN'
+ move_down_op.list_context_path = list_context_path
+ move_down_op.active_idx_context_path = active_idx_context_path
+
+ # Return the right-side column.
+ return col
+
+
+# =============================================
+# Registration
+
+classes = (
+ UILIST_OT_entry_remove,
+ UILIST_OT_entry_add,
+ UILIST_OT_entry_move,
+)
+
+
+def register():
+ from bpy.utils import register_class
+ for cls in classes:
+ register_class(cls)
+
+
+def unregister():
+ from bpy.utils import unregister_class
+ for cls in classes:
+ unregister_class(cls)