238 lines
9.0 KiB
Python
238 lines
9.0 KiB
Python
from .. import __package__ as base_package
|
|
import os
|
|
import bpy
|
|
import json
|
|
from bpy.types import Operator, PropertyGroup, AddonPreferences
|
|
from bpy.props import StringProperty, CollectionProperty, IntProperty, BoolProperty
|
|
|
|
# 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
|
|
|
|
override_splash: BoolProperty(default=True, name="Override Splash Screen's 'New File' list", description="Override splashscreen's 'New File' list")
|
|
projects: CollectionProperty(type=TemplateItem)
|
|
active_template_index: IntProperty(
|
|
description="Index of the selected template")
|
|
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
|
|
layout.label(text="Your custom templates:")
|
|
row = layout.row()
|
|
row.template_list("UI_UL_list", "custom_templates",
|
|
self, "projects", self, "active_template_index")
|
|
|
|
col = row.column(align=True)
|
|
col.menu("CT_MT_export", icon='DOWNARROW_HLT', text="")
|
|
col.separator()
|
|
col.operator("ct.add", icon='ADD', text="")
|
|
if self.projects:
|
|
col.operator("ct.remove", icon='REMOVE', text="")
|
|
col.separator()
|
|
col.operator("ct.move_up", icon='TRIA_UP', text="")
|
|
col.operator("ct.move_down", icon='TRIA_DOWN', text="")
|
|
|
|
if self.projects:
|
|
project = self.projects[self.active_template_index]
|
|
layout.prop(project, "name")
|
|
layout.prop(project, "path")
|
|
|
|
layout.prop(self, "override_splash")
|
|
box = layout.box()
|
|
if self.override_splash and len(self.projects) == 0:
|
|
box.label(text="There are currently no templates.")
|
|
elif self.override_splash:
|
|
box.label(text="Custom templates will be shown in the Splash Screen.")
|
|
|
|
if not self.override_splash or len(self.projects) == 0:
|
|
box.label(text="The default Blender list will be shown in the Splash Screen.")
|
|
|
|
if len(self.projects) > 5:
|
|
box.label(text="Note: Only the first 5 templates in the list will be shown in the splash screen.")
|
|
|
|
class CT_MT_export(bpy.types.Menu):
|
|
bl_label = "Import/Export custom templates"
|
|
bl_description = "Allows you to save al load your custom templates (using json format)"
|
|
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
layout.operator("ct.export_templates", text="Export templates")
|
|
layout.operator("ct.import_templates", text="Import templates")
|
|
|
|
class CT_OT_export_templates(bpy.types.Operator):
|
|
bl_idname = "ct.export_templates"
|
|
bl_label = "Export custom templates"
|
|
bl_description = "Export the current list of templates to JSON file"
|
|
|
|
filepath: StringProperty(subtype="FILE_PATH", description="Select the path for the exported file", default="templates.json")
|
|
|
|
def execute(self, context):
|
|
prefs = context.preferences.addons[base_package].preferences
|
|
with open(self.filepath, 'w') as f:
|
|
projects = [{"name": project.name, "path": project.path} for project in prefs.projects]
|
|
json.dump(projects, f, indent=4)
|
|
|
|
self.report({'INFO'}, f"Templates exported to {self.filepath}")
|
|
return {'FINISHED'}
|
|
|
|
def invoke(self, context, event):
|
|
context.window_manager.fileselect_add(self)
|
|
return {'RUNNING_MODAL'}
|
|
|
|
class CT_OT_import_templates(bpy.types.Operator):
|
|
bl_idname = "ct.import_templates"
|
|
bl_label = "Import custom templates"
|
|
bl_description = "Import a list of templates from JSON file (note that this will override the current templates list)"
|
|
|
|
filepath: StringProperty(subtype="FILE_PATH", description="Select the .json file to load")
|
|
|
|
def execute(self, context):
|
|
prefs = context.preferences.addons[base_package].preferences
|
|
|
|
if os.path.exists(self.filepath):
|
|
with open(self.filepath, 'r') as f:
|
|
projects = json.load(f)
|
|
|
|
prefs.projects.clear()
|
|
for project in projects:
|
|
item = prefs.projects.add()
|
|
item.name = project["name"]
|
|
item.path = project["path"]
|
|
prefs.active_template_index = 0
|
|
|
|
self.report({'INFO'}, f"Projects imported from {self.filepath}")
|
|
else:
|
|
self.report({'WARNING'}, f"Import cancelled: path not found ({self.filepath})")
|
|
return {'FINISHED'}
|
|
|
|
def invoke(self, context, event):
|
|
context.window_manager.fileselect_add(self)
|
|
return {'RUNNING_MODAL'}
|
|
|
|
# Templates list oeprators
|
|
class CT_OT_add(Operator):
|
|
bl_idname = "ct.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
|
|
return {'FINISHED'}
|
|
|
|
class CT_OT_remove(Operator):
|
|
bl_idname = "ct.remove"
|
|
bl_label = "Remove Template"
|
|
bl_description = "Remove selected template"
|
|
|
|
def execute(self, context):
|
|
prefs = context.preferences.addons[base_package].preferences
|
|
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 CT_OT_move_up(Operator):
|
|
bl_idname = "ct.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
|
|
else:
|
|
self.report({'WARNING'}, "Template is already at the top")
|
|
|
|
return {'FINISHED'}
|
|
|
|
class CT_OT_move_down(Operator):
|
|
bl_idname = "ct.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
|
|
else:
|
|
self.report({'WARNING'}, "Template is already at the bottom")
|
|
|
|
return {'FINISHED'}
|
|
|
|
# Popups of File > Defaults
|
|
def already_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 CT_OT_add_template_popup(Operator):
|
|
bl_idname = "ct.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 not already_present(self, prefs, current_file_path):
|
|
if current_file_path:
|
|
new_project = prefs.projects.add()
|
|
new_project.name = self.project_name
|
|
new_project.path = current_file_path
|
|
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 CT_OT_select_template_popup(Operator):
|
|
bl_idname = "ct.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 not already_present(self, prefs, self.project_path):
|
|
new_project = prefs.projects.add()
|
|
new_project.name = self.project_name
|
|
new_project.path = self.project_path
|
|
return {'FINISHED'}
|
|
|
|
def invoke(self, context, event):
|
|
return context.window_manager.invoke_props_dialog(self)
|
|
|
|
# Open Preferences
|
|
class CT_OT_open_preferences(Operator):
|
|
bl_idname = "ct.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'}
|