Separate classe in new file, reduce register/unregister code length
This commit is contained in:
parent
56daf65b80
commit
8f5034fbf6
@ -13,12 +13,8 @@
|
|||||||
|
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import os
|
|
||||||
import bpy
|
import bpy
|
||||||
from bpy.types import AddonPreferences, PropertyGroup, Operator
|
from .classes.ots import CustomTemplatesPreferences, TemplateItem, OT_SelectTemplatePopup, OT_AddTemplatePopup, OT_AddTemplateItem, OT_RemoveTemplateItem, OT_MoveDownTemplateItem, OT_MoveUpTemplateItem, OT_OpenAddonPreferences
|
||||||
from bpy.props import CollectionProperty, IntProperty, StringProperty
|
|
||||||
|
|
||||||
|
|
||||||
bl_info = {
|
bl_info = {
|
||||||
"id": "custom_templates",
|
"id": "custom_templates",
|
||||||
@ -31,191 +27,12 @@ bl_info = {
|
|||||||
"blender_manifest": "blender_manifest.toml"
|
"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):
|
def draw_addon_separator(layout):
|
||||||
layout.separator()
|
layout.separator()
|
||||||
layout.label(text="Custom Templates")
|
layout.label(text="Custom Templates")
|
||||||
layout.separator()
|
layout.separator()
|
||||||
|
|
||||||
|
def draw_file_new_templates(self, context):
|
||||||
def draw_new_menu(self, context):
|
|
||||||
layout = self.layout
|
layout = self.layout
|
||||||
prefs = context.preferences.addons[__package__].preferences
|
prefs = context.preferences.addons[__package__].preferences
|
||||||
|
|
||||||
@ -226,54 +43,43 @@ def draw_new_menu(self, context):
|
|||||||
layout.operator(
|
layout.operator(
|
||||||
"wm.read_homefile", text=project.name).filepath = project.path
|
"wm.read_homefile", text=project.name).filepath = project.path
|
||||||
|
|
||||||
|
def draw_file_default_operators(self, context):
|
||||||
# File > Defaults > Add-On Buttons
|
|
||||||
def draw_add_template(self, context):
|
|
||||||
layout = self.layout
|
layout = self.layout
|
||||||
|
|
||||||
draw_addon_separator(layout)
|
draw_addon_separator(layout)
|
||||||
|
|
||||||
# Manage Template
|
# Manage Template
|
||||||
layout.operator("custom_templates.open_preferences",
|
layout.operator("custom_templates.open_preferences",
|
||||||
text="Manage templates")
|
text="Manage templates")
|
||||||
# Select new custom template
|
# Select new custom template
|
||||||
layout.operator("wm.select_template_popup",
|
layout.operator("custom_templates.select_template_popup",
|
||||||
text="Select new custom template")
|
text="Select new custom template")
|
||||||
|
# Use current as new template (only with an active saved .blend file opened)
|
||||||
if bpy.data.filepath != "":
|
if bpy.data.filepath != "":
|
||||||
# Use current as new template (only with an active saved .blend file opened)
|
layout.operator("custom_templates.add_template_popup",
|
||||||
layout.operator("wm.add_template_popup",
|
|
||||||
text="Use current as new template")
|
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():
|
def register():
|
||||||
bpy.utils.register_class(TemplateItem)
|
for c in classes:
|
||||||
bpy.utils.register_class(OT_MoveUpTemplateItem)
|
bpy.utils.register_class(c)
|
||||||
bpy.utils.register_class(OT_MoveDownTemplateItem)
|
bpy.types.TOPBAR_MT_file_new.remove(draw_file_new_templates)
|
||||||
bpy.utils.register_class(OT_AddTemplateItem)
|
bpy.types.TOPBAR_MT_file_new.remove(draw_file_default_operators)
|
||||||
bpy.utils.register_class(OT_RemoveTemplateItem)
|
bpy.types.TOPBAR_MT_file_new.append(draw_file_new_templates)
|
||||||
bpy.utils.register_class(OT_AddTemplatePopup)
|
bpy.types.TOPBAR_MT_file_defaults.append(draw_file_default_operators)
|
||||||
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)
|
|
||||||
|
|
||||||
|
|
||||||
def unregister():
|
def unregister():
|
||||||
bpy.utils.unregister_class(CustomTemplatesPreferences)
|
for c in reversed(classes):
|
||||||
bpy.utils.unregister_class(OT_MoveUpTemplateItem)
|
bpy.utils.unregister_class(c)
|
||||||
bpy.utils.unregister_class(OT_MoveDownTemplateItem)
|
bpy.types.TOPBAR_MT_file_new.remove(draw_file_new_templates)
|
||||||
bpy.utils.unregister_class(OT_AddTemplateItem)
|
bpy.types.TOPBAR_MT_file_defaults.remove(draw_file_default_operators)
|
||||||
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)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
register()
|
register()
|
||||||
|
173
addon/classes/ots.py
Normal file
173
addon/classes/ots.py
Normal file
@ -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'}
|
Loading…
x
Reference in New Issue
Block a user