from bpy.types import PropertyGroup from bpy.props import ( StringProperty, IntProperty, CollectionProperty, PointerProperty, ) import bpy, json from .util import get_pretty_stack class BlenderLog_Entry(PropertyGroup): """Container for storing information about a single metarig warning/error. A CollectionProperty of CloudRigLogEntries are added to the armature datablock in cloud_generator.register(). This CollectionProperty is then populated by a BlenderLog_Manager instance created by CloudRig_Generator, which is created by the Generate operator. """ name: StringProperty(name="Name", description="Name of issue", default="") category: StringProperty( name="Category", description="For internal categorization of log entries", default="" ) icon: StringProperty(name="Icon", description="Icon for this log entry", default='ERROR') description: StringProperty(name="Description", description="Description of issue", default="") pretty_stack: StringProperty( name="Pretty Stack", description="Stack trace in the code of where this log entry was added. For internal use only", ) operator: StringProperty( name="Operator", description="Operator that can fix the issue", default='' ) op_kwargs: StringProperty( name="Operator Arguments", description="Keyword arguments that will be passed to the operator. This should be a string that can be eval()'d into a python dict", default='', ) op_text: StringProperty( name="Operator Text", description="Text to display on the operator button", default='', ) op_icon: StringProperty( name="Operator Icon", description="Icon to display on the operator button", default='', ) class BlenderLog_Category(PropertyGroup): name: StringProperty() icon: StringProperty() active_log_index: IntProperty() logs: CollectionProperty(type=BlenderLog_Entry) @property def active_log(self): if self.active_log_index > len(self.logs) - 1: return return self.logs[self.active_log_index] def get_index(self, log): for i, l in enumerate(self.logs): if l == log: return i def clear(self): self.logs.clear() self.active_log_index = 0 class BlenderLog_Manager(PropertyGroup): """Class to manage BlenderLog_Entry CollectionProperty on metarigs. This class is instanced once per rig generation, by the CloudRig_Generator class. """ categories: CollectionProperty(type=BlenderLog_Category) active_cat_index: IntProperty() @property def active_category(self): if self.active_cat_index > len(self.categories) - 1: return return self.categories[self.active_cat_index] @property def active_log(self): return self.active_category.active_log @property def all_logs(self): for cat in self.categories: for log in cat.logs: yield log def add( self, name: str, *, description="No description.", icon='ERROR', category="Uncategorized", category_icon="", operator='', op_kwargs={}, op_text="", op_icon="", ): """Low-level function to add a log entry to the metarig object's data.""" cat_entry = self.categories.get(category) if not cat_entry: cat_entry = self.categories.add() cat_entry.name = category cat_entry.icon = category_icon or icon entry = cat_entry.logs.add() entry.pretty_stack = get_pretty_stack() entry.name = name entry.description = description entry.category = category entry.icon = icon entry.operator = operator entry.op_kwargs = json.dumps(op_kwargs) entry.op_text = op_text entry.op_icon = op_icon return entry def remove(self, log): removed = False for cat in self.categories: for other_log in cat.logs: if log == other_log: cat.logs.remove(cat.get_index(log)) removed = True break if removed: break if removed and len(cat.logs) == 0: self.clear_category(cat.name) def remove_active(self): self.remove(self.active_log) def remove_category(self, cat): self.categories.remove(self.get_index(cat)) def get_category(self, cat_name: str): for cat in self.categories: if cat.name == cat_name: return cat def get_index(self, cat): for i, c in enumerate(self.categories): if c == cat: return i def clear_category(self, cat_name: str): cat = self.get_category(cat_name) if cat: cat.clear() self.categories.remove(self.get_index(cat)) registry = [ BlenderLog_Entry, BlenderLog_Category, BlenderLog_Manager, ] def register(): bpy.types.Scene.blender_log = PointerProperty(type=BlenderLog_Manager) def unregister(): del bpy.types.Scene.blender_log