From 8f5034fbf6feff8564d1d03783daf7bffa702412 Mon Sep 17 00:00:00 2001 From: doc-code Date: Sat, 17 Aug 2024 16:47:09 +0200 Subject: [PATCH] Separate classe in new file, reduce register/unregister code length --- addon/__init__.py | 244 +++++-------------------------------------- addon/classes/ots.py | 173 ++++++++++++++++++++++++++++++ 2 files changed, 198 insertions(+), 219 deletions(-) create mode 100644 addon/classes/ots.py diff --git a/addon/__init__.py b/addon/__init__.py index 1b28cd9..093ea78 100644 --- a/addon/__init__.py +++ b/addon/__init__.py @@ -13,12 +13,8 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . - -import os import bpy -from bpy.types import AddonPreferences, PropertyGroup, Operator -from bpy.props import CollectionProperty, IntProperty, StringProperty - +from .classes.ots import CustomTemplatesPreferences, TemplateItem, OT_SelectTemplatePopup, OT_AddTemplatePopup, OT_AddTemplateItem, OT_RemoveTemplateItem, OT_MoveDownTemplateItem, OT_MoveUpTemplateItem, OT_OpenAddonPreferences bl_info = { "id": "custom_templates", @@ -31,191 +27,12 @@ bl_info = { "blender_manifest": "blender_manifest.toml" } - -class TemplateItem(PropertyGroup): - name: StringProperty( - name="Name", description="Display name for this template") - path: StringProperty( - name="Path", description="Path to the .blend file for this template", subtype='FILE_PATH') - - -class OT_SelectTemplatePopup(Operator): - bl_idname = "wm.select_template_popup" - bl_label = "Select a new custom template" - bl_description = "Create a new template occurency by selecting an existing .blend file" - - project_name: StringProperty(name="Project Name") - project_path: StringProperty(name="Project Path", subtype="FILE_PATH") - - def execute(self, context): - prefs = context.preferences.addons[__package__].preferences - for p in prefs.projects: - if p.path == self.project_path: - already_present = True - self.report( - {'WARNING'}, f'Selected file is already in the templates list as "{p.name}".') - return {'FINISHED'} - - new_project = prefs.projects.add() - new_project.name = self.project_name - new_project.path = self.project_path - self.report( - {'INFO'}, f"Template '{self.project_name}' selected and added successfully!") - - return {'FINISHED'} - - def invoke(self, context, event): - return context.window_manager.invoke_props_dialog(self) - - -class OT_AddTemplatePopup(Operator): - bl_idname = "wm.add_template_popup" - bl_label = "Use as template" - bl_description = "Use the current .blend file to create a new template occurency" - - project_name: StringProperty(name="Project Name") - - def execute(self, context): - prefs = context.preferences.addons[__package__].preferences - current_file_path = bpy.data.filepath - for p in prefs.projects: - if p.path == current_file_path: - already_present = True - self.report( - {'WARNING'}, f'Current file is already in the templates list as "{p.name}".') - return {'FINISHED'} - - if current_file_path: - new_project = prefs.projects.add() - new_project.name = self.project_name - new_project.path = current_file_path - self.report( - {'INFO'}, f"Template '{self.project_name}' added successfully!") - else: - self.report({'ERROR'}, "Current file is not saved on disk.") - - return {'FINISHED'} - - def invoke(self, context, event): - return context.window_manager.invoke_props_dialog(self) - - -class OT_AddTemplateItem(Operator): - bl_idname = "custom_templates.add" - bl_label = "Add Template" - bl_description = "Add new template" - - def execute(self, context): - prefs = context.preferences.addons[__package__].preferences - prefs.projects.add() - prefs.active_template_index = len(prefs.projects) - 1 - self.report({'INFO'}, f"Empty template added") - return {'FINISHED'} - - -class OT_RemoveTemplateItem(Operator): - bl_idname = "custom_templates.remove" - bl_label = "Remove Template" - bl_description = "Remove selected template" - - def execute(self, context): - prefs = context.preferences.addons[__package__].preferences - self.report( - {'INFO'}, f'Template "{prefs.projects[prefs.active_template_index].name}" removed{" (`"+prefs.projects[prefs.active_template_index].path+"`)" if prefs.projects[prefs.active_template_index].path != "" else "" }') - prefs.projects.remove(prefs.active_template_index) - prefs.active_template_index = min( - max(0, prefs.active_template_index - 1), len(prefs.projects) - 1) - return {'FINISHED'} - - -class OT_MoveUpTemplateItem(bpy.types.Operator): - bl_idname = "custom_templates.move_up" - bl_label = "Move Up" - bl_description = "Move the selected template up in the list" - - def execute(self, context): - prefs = context.preferences.addons[__package__].preferences - index = prefs.active_template_index - - if index > 0: - prefs.projects.move(index, index - 1) - prefs.active_template_index -= 1 - self.report({'INFO'}, f"Templates list re-ordered") - else: - self.report({'WARNING'}, "Template is already at the top") - - return {'FINISHED'} - - -class OT_MoveDownTemplateItem(bpy.types.Operator): - bl_idname = "custom_templates.move_down" - bl_label = "Move Down" - bl_description = "Move the selected template down in the list" - - def execute(self, context): - prefs = context.preferences.addons[__package__].preferences - index = prefs.active_template_index - - if index < len(prefs.projects) - 1: - prefs.projects.move(index, index + 1) - prefs.active_template_index += 1 - self.report({'INFO'}, f"Templates list re-ordered") - else: - self.report({'WARNING'}, "Template is already at the bottom") - - return {'FINISHED'} - -class OT_OpenAddonPreferences(bpy.types.Operator): - bl_idname = "custom_templates.open_preferences" - bl_label = "Open Custom Templates Preferences" - bl_description = "Open the preferences for the Custom Templates add-on" - - def execute(self, context): - bpy.ops.screen.userpref_show('INVOKE_DEFAULT') - context.preferences.active_section = 'ADDONS' - context.window_manager.addon_search = "Custom Templates" - return {'FINISHED'} - -# Add-On Preferences -class CustomTemplatesPreferences(AddonPreferences): - bl_idname = __package__ - - projects: CollectionProperty(type=TemplateItem) - active_template_index: IntProperty( - description="Index of the selected template") - - def draw(self, context): - layout = self.layout - - layout.label( - text="Here you can setup your own .blend files that will be shown in the `File > New` menu.") - layout.label( - text="You can also use `File > Defaults > Select new custom template` and `File > Defaults > Use current as new template` to update this preferences.") - - row = layout.row() - row.template_list("UI_UL_list", "custom_templates", - self, "projects", self, "active_template_index") - - col = row.column(align=True) - col.operator("custom_templates.add", icon='ADD', text="") - col.operator("custom_templates.remove", icon='REMOVE', text="") - col.operator("custom_templates.move_up", icon='TRIA_UP', text="") - col.operator("custom_templates.move_down", icon='TRIA_DOWN', text="") - - if self.projects: - project = self.projects[self.active_template_index] - layout.prop(project, "name") - layout.prop(project, "path") - - - def draw_addon_separator(layout): layout.separator() layout.label(text="Custom Templates") layout.separator() - -def draw_new_menu(self, context): +def draw_file_new_templates(self, context): layout = self.layout prefs = context.preferences.addons[__package__].preferences @@ -226,54 +43,43 @@ def draw_new_menu(self, context): layout.operator( "wm.read_homefile", text=project.name).filepath = project.path - -# File > Defaults > Add-On Buttons -def draw_add_template(self, context): +def draw_file_default_operators(self, context): layout = self.layout - draw_addon_separator(layout) - # Manage Template layout.operator("custom_templates.open_preferences", text="Manage templates") # Select new custom template - layout.operator("wm.select_template_popup", + layout.operator("custom_templates.select_template_popup", text="Select new custom template") + # Use current as new template (only with an active saved .blend file opened) if bpy.data.filepath != "": - # Use current as new template (only with an active saved .blend file opened) - layout.operator("wm.add_template_popup", + layout.operator("custom_templates.add_template_popup", text="Use current as new template") +classes = [TemplateItem, + OT_MoveUpTemplateItem, + OT_MoveDownTemplateItem, + OT_AddTemplateItem, + OT_RemoveTemplateItem, + OT_AddTemplatePopup, + OT_SelectTemplatePopup, + OT_OpenAddonPreferences, + CustomTemplatesPreferences] def register(): - bpy.utils.register_class(TemplateItem) - bpy.utils.register_class(OT_MoveUpTemplateItem) - bpy.utils.register_class(OT_MoveDownTemplateItem) - bpy.utils.register_class(OT_AddTemplateItem) - bpy.utils.register_class(OT_RemoveTemplateItem) - bpy.utils.register_class(OT_AddTemplatePopup) - bpy.utils.register_class(OT_SelectTemplatePopup) - bpy.utils.register_class(OT_OpenAddonPreferences) - bpy.utils.register_class(CustomTemplatesPreferences) - bpy.types.TOPBAR_MT_file_new.remove(draw_new_menu) - bpy.types.TOPBAR_MT_file_new.remove(draw_add_template) - bpy.types.TOPBAR_MT_file_new.append(draw_new_menu) - bpy.types.TOPBAR_MT_file_defaults.append(draw_add_template) - + for c in classes: + bpy.utils.register_class(c) + bpy.types.TOPBAR_MT_file_new.remove(draw_file_new_templates) + bpy.types.TOPBAR_MT_file_new.remove(draw_file_default_operators) + bpy.types.TOPBAR_MT_file_new.append(draw_file_new_templates) + bpy.types.TOPBAR_MT_file_defaults.append(draw_file_default_operators) def unregister(): - bpy.utils.unregister_class(CustomTemplatesPreferences) - bpy.utils.unregister_class(OT_MoveUpTemplateItem) - bpy.utils.unregister_class(OT_MoveDownTemplateItem) - bpy.utils.unregister_class(OT_AddTemplateItem) - bpy.utils.unregister_class(OT_AddTemplatePopup) - bpy.utils.unregister_class(OT_RemoveTemplateItem) - bpy.utils.unregister_class(OT_SelectTemplatePopup) - bpy.utils.unregister_class(OT_OpenAddonPreferences) - bpy.utils.unregister_class(TemplateItem) - bpy.types.TOPBAR_MT_file_new.remove(draw_new_menu) - bpy.types.TOPBAR_MT_file_defaults.remove(draw_add_template) - + for c in reversed(classes): + bpy.utils.unregister_class(c) + bpy.types.TOPBAR_MT_file_new.remove(draw_file_new_templates) + bpy.types.TOPBAR_MT_file_defaults.remove(draw_file_default_operators) if __name__ == "__main__": register() diff --git a/addon/classes/ots.py b/addon/classes/ots.py new file mode 100644 index 0000000..e23a770 --- /dev/null +++ b/addon/classes/ots.py @@ -0,0 +1,173 @@ +from .. import __package__ as base_package +import bpy +from bpy.types import Operator, PropertyGroup, AddonPreferences +from bpy.props import StringProperty, CollectionProperty, IntProperty + +# Preferences +class TemplateItem(PropertyGroup): + name: StringProperty( + name="Name", description="Display name for this template") + path: StringProperty( + name="Path", description="Path to the .blend file for this template", subtype='FILE_PATH') + +class CustomTemplatesPreferences(AddonPreferences): + bl_idname = base_package + + projects: CollectionProperty(type=TemplateItem) + active_template_index: IntProperty( + description="Index of the selected template") + + def draw(self, context): + layout = self.layout + + layout.label( + text="Here you can setup your own .blend files that will be shown in the `File > New` menu.") + layout.label( + text="You can also use `File > Defaults > Select new custom template` and `File > Defaults > Use current as new template` to update this preferences.") + + row = layout.row() + row.template_list("UI_UL_list", "custom_templates", + self, "projects", self, "active_template_index") + + col = row.column(align=True) + col.operator("custom_templates.add", icon='ADD', text="") + col.operator("custom_templates.remove", icon='REMOVE', text="") + col.operator("custom_templates.move_up", icon='TRIA_UP', text="") + col.operator("custom_templates.move_down", icon='TRIA_DOWN', text="") + + if self.projects: + project = self.projects[self.active_template_index] + layout.prop(project, "name") + layout.prop(project, "path") + +# Templates list oeprators +class OT_AddTemplateItem(Operator): + bl_idname = "custom_templates.add" + bl_label = "Add Template" + bl_description = "Add new template" + + def execute(self, context): + prefs = context.preferences.addons[base_package].preferences + prefs.projects.add() + prefs.active_template_index = len(prefs.projects) - 1 + self.report({'INFO'}, f"Empty template added") + return {'FINISHED'} + +class OT_RemoveTemplateItem(Operator): + bl_idname = "custom_templates.remove" + bl_label = "Remove Template" + bl_description = "Remove selected template" + + def execute(self, context): + prefs = context.preferences.addons[base_package].preferences + self.report( + {'INFO'}, f'Template "{prefs.projects[prefs.active_template_index].name}" removed{" (`"+prefs.projects[prefs.active_template_index].path+"`)" if prefs.projects[prefs.active_template_index].path != "" else "" }') + prefs.projects.remove(prefs.active_template_index) + prefs.active_template_index = min( + max(0, prefs.active_template_index - 1), len(prefs.projects) - 1) + return {'FINISHED'} + +class OT_MoveUpTemplateItem(Operator): + bl_idname = "custom_templates.move_up" + bl_label = "Move Up" + bl_description = "Move the selected template up in the list" + + def execute(self, context): + prefs = context.preferences.addons[base_package].preferences + index = prefs.active_template_index + + if index > 0: + prefs.projects.move(index, index - 1) + prefs.active_template_index -= 1 + self.report({'INFO'}, f"Templates list re-ordered") + else: + self.report({'WARNING'}, "Template is already at the top") + + return {'FINISHED'} + +class OT_MoveDownTemplateItem(Operator): + bl_idname = "custom_templates.move_down" + bl_label = "Move Down" + bl_description = "Move the selected template down in the list" + + def execute(self, context): + prefs = context.preferences.addons[base_package].preferences + index = prefs.active_template_index + + if index < len(prefs.projects) - 1: + prefs.projects.move(index, index + 1) + prefs.active_template_index += 1 + self.report({'INFO'}, f"Templates list re-ordered") + else: + self.report({'WARNING'}, "Template is already at the bottom") + + return {'FINISHED'} + +# Popups of File > Defaults +def check_if_present(self, prefs, path): + for p in prefs.projects: + if p.path == path: + already_present = True + self.report( + {'WARNING'}, f'Current file is already in the templates list as "{p.name}".') + return True + return False + +class OT_AddTemplatePopup(Operator): + bl_idname = "custom_templates.add_template_popup" + bl_label = "Use as template" + bl_description = "Use the current .blend file to create a new template occurency" + + project_name: StringProperty(name="Project Name") + + def execute(self, context): + prefs = context.preferences.addons[base_package].preferences + current_file_path = bpy.data.filepath + if check_if_present(self, prefs, current_file_path): + return {'FINISHED'} + if current_file_path: + new_project = prefs.projects.add() + new_project.name = self.project_name + new_project.path = current_file_path + self.report( + {'INFO'}, f"Template '{self.project_name}' added successfully!") + else: + self.report({'ERROR'}, "Current file is not saved on disk.") + return {'FINISHED'} + + def invoke(self, context, event): + return context.window_manager.invoke_props_dialog(self) + +class OT_SelectTemplatePopup(Operator): + bl_idname = "custom_templates.select_template_popup" + bl_label = "Select a new custom template" + bl_description = "Create a new template occurency by selecting an existing .blend file" + + project_name: StringProperty(name="Project Name") + project_path: StringProperty(name="Project Path", subtype="FILE_PATH") + + def execute(self, context): + prefs = context.preferences.addons[base_package].preferences + if check_if_present(self, prefs, self.project_path): + return {'FINISHED'} + new_project = prefs.projects.add() + new_project.name = self.project_name + new_project.path = self.project_path + self.report( + {'INFO'}, f"Template '{self.project_name}' selected and added successfully!") + return {'FINISHED'} + + def invoke(self, context, event): + return context.window_manager.invoke_props_dialog(self) + +# Open Preferences +class OT_OpenAddonPreferences(Operator): + bl_idname = "custom_templates.open_preferences" + bl_label = "Open Custom Templates Preferences" + bl_description = "Open the preferences for the Custom Templates add-on" + + def execute(self, context): + bpy.ops.screen.userpref_show('INVOKE_DEFAULT') + context.preferences.active_section = 'ADDONS' + context.window_manager.addon_search = "Custom Templates" + return {'FINISHED'}