633 lines
23 KiB
Python
633 lines
23 KiB
Python
# SPDX-FileCopyrightText: 2023 Blender Studio Tools Authors
|
|
#
|
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
import bpy
|
|
import shutil
|
|
from .. import bkglobals, prefs, cache
|
|
from pathlib import Path
|
|
from typing import List, Any, Tuple, Set, cast
|
|
from . import core, config
|
|
from ..context import core as context_core
|
|
|
|
from ..edit.core import edit_export_import_latest
|
|
from .file_save import save_shot_builder_file
|
|
from .template import replace_workspace_with_template
|
|
from .assets import get_shot_assets
|
|
from .hooks import Hooks
|
|
|
|
ACTIVE_PROJECT = None
|
|
|
|
|
|
def get_shots_for_seq(self: Any, context: bpy.types.Context) -> List[Tuple[str, str, str]]:
|
|
if self.seq_id != '':
|
|
seq = ACTIVE_PROJECT.get_sequence(self.seq_id)
|
|
shot_enum = cache.get_shots_enum_for_seq(self, context, seq)
|
|
if shot_enum != []:
|
|
return shot_enum
|
|
return [('NONE', "No Shots Found", '')]
|
|
|
|
|
|
def get_tasks_for_shot(self: Any, context: bpy.types.Context) -> List[Tuple[str, str, str]]:
|
|
global ACTIVE_PROJECT
|
|
if not (self.shot_id == '' or self.shot_id == 'NONE'):
|
|
shot = ACTIVE_PROJECT.get_shot(self.shot_id)
|
|
task_enum = cache.get_shot_task_types_enum_for_shot(self, context, shot)
|
|
if task_enum != []:
|
|
return task_enum
|
|
return [('NONE', "No Tasks Found", '')]
|
|
|
|
|
|
class KITSU_OT_build_config_base_class(bpy.types.Operator):
|
|
@classmethod
|
|
def poll(cls, context: bpy.types.Context) -> bool:
|
|
addon_prefs = prefs.addon_prefs_get(context)
|
|
if not prefs.session_auth(context):
|
|
cls.poll_message_set("Login to a Kitsu Server")
|
|
if not cache.project_active_get():
|
|
cls.poll_message_set("Select an active project")
|
|
return False
|
|
if not addon_prefs.is_project_root_valid:
|
|
cls.poll_message_set(
|
|
"Check project root directory is configured in 'Blender Kitsu' addon preferences."
|
|
)
|
|
return False
|
|
return True
|
|
|
|
|
|
class KITSU_OT_build_config_save_hooks(KITSU_OT_build_config_base_class):
|
|
bl_idname = "kitsu.build_config_save_hooks"
|
|
bl_label = "Save Shot Builder Hook File"
|
|
bl_description = "Save hook.py file to `your_project_name/svn/pro/config/shot_builder` directory. Hooks are used to customize shot builder behaviour."
|
|
|
|
def execute(self, context: bpy.types.Context):
|
|
hooks_target_filepath = config.filepath_get(bkglobals.BUILD_HOOKS_FILENAME)
|
|
if hooks_target_filepath.exists():
|
|
self.report(
|
|
{'WARNING'},
|
|
f"{hooks_target_filepath.name} already exists, cannot overwrite",
|
|
)
|
|
return {'CANCELLED'}
|
|
|
|
hooks_example = config.example_filepath_get(bkglobals.BUILD_HOOKS_FILENAME)
|
|
if not hooks_example.exists():
|
|
self.report(
|
|
{'ERROR'},
|
|
f"Cannot find {hooks_target_filepath.name} example file",
|
|
)
|
|
return {'CANCELLED'}
|
|
|
|
config.copy_json_file(hooks_example, hooks_target_filepath)
|
|
self.report({'INFO'}, f"Hook File saved to {str(hooks_target_filepath)}")
|
|
return {'FINISHED'}
|
|
|
|
|
|
class KITSU_OT_build_config_save_settings(KITSU_OT_build_config_base_class):
|
|
bl_idname = "kitsu.build_config_save_settings"
|
|
bl_label = "Save Shot Builder Settings File"
|
|
bl_description = "Save settings.json file to `your_project_name/svn/pro/config/shot_builder` Config are used to customize shot builder behaviour."
|
|
|
|
def execute(self, context: bpy.types.Context):
|
|
settings_target_filepath = config.filepath_get(bkglobals.BUILD_SETTINGS_FILENAME)
|
|
if settings_target_filepath.exists():
|
|
self.report(
|
|
{'WARNING'},
|
|
f"{settings_target_filepath.name} already exists, cannot overwrite",
|
|
)
|
|
return {'CANCELLED'}
|
|
|
|
settings_example = config.example_filepath_get(bkglobals.BUILD_SETTINGS_FILENAME)
|
|
if not settings_example.exists():
|
|
self.report(
|
|
{'ERROR'},
|
|
"Cannot find example settings file",
|
|
)
|
|
return {'CANCELLED'}
|
|
|
|
config.copy_json_file(settings_example, settings_target_filepath)
|
|
self.report({'INFO'}, f"Settings File saved to {str(settings_target_filepath)}")
|
|
return {'FINISHED'}
|
|
|
|
|
|
class KITSU_OT_build_config_save_templates(KITSU_OT_build_config_base_class):
|
|
bl_idname = "kitsu.build_config_save_templates"
|
|
bl_label = "Create Shot Builder Template Files"
|
|
bl_description = (
|
|
"Save template files for shot builder in config directory."
|
|
"Templates are used to customize the workspaces for each per task type"
|
|
"Template names match each task type found on Kitsu Server"
|
|
)
|
|
|
|
def execute(self, context: bpy.types.Context):
|
|
source_dir = config.template_example_dir_get()
|
|
target_dir = config.template_dir_get()
|
|
|
|
# Ensure Target Directory Exists
|
|
target_dir.mkdir(parents=True, exist_ok=True)
|
|
|
|
source_files = list(source_dir.glob('*.blend')) + list(source_dir.glob('*.md'))
|
|
for source_file in source_files:
|
|
target_file = target_dir.joinpath(source_file.name)
|
|
if target_file.exists():
|
|
print(f"Cannot overwrite file {str(target_file)}")
|
|
continue
|
|
shutil.copy2(source_file, target_dir.joinpath(source_file.name))
|
|
|
|
self.report({'INFO'}, f"Saved template files to {str(target_dir)}")
|
|
return {'FINISHED'}
|
|
|
|
|
|
class KITSU_OT_build_new_file_baseclass(bpy.types.Operator):
|
|
bl_idname = "kitsu.build_new_file"
|
|
bl_label = "Build New File"
|
|
bl_description = "Build a new file based on the current context and save it"
|
|
bl_options = {"REGISTER"}
|
|
|
|
_kitsu_context_type = "" # Default context for this operator
|
|
_current_kitsu_context = ""
|
|
|
|
production_name: bpy.props.StringProperty( # type: ignore
|
|
name="Production",
|
|
description="Name of the production to create a shot file for",
|
|
options=set(),
|
|
)
|
|
|
|
save_file: bpy.props.BoolProperty( # type:ignore
|
|
name="Save after building.",
|
|
description="Automatically save build file after 'Shot Builder' is complete.",
|
|
default=True,
|
|
)
|
|
|
|
def invoke(self, context: bpy.types.Context, event: bpy.types.Event) -> Set[str]:
|
|
global ACTIVE_PROJECT
|
|
|
|
# Temporarily change kitsu context to asset
|
|
self._current_kitsu_context = context.scene.kitsu.category
|
|
context.scene.kitsu.category = self._kitsu_context_type
|
|
|
|
addon_prefs = prefs.addon_prefs_get(bpy.context)
|
|
project = cache.project_active_get()
|
|
ACTIVE_PROJECT = project
|
|
|
|
if addon_prefs.session.is_auth() is False:
|
|
self.report(
|
|
{'ERROR'},
|
|
"Must be logged into Kitsu to continue. \nCheck login status in 'Blender Kitsu' addon preferences.",
|
|
)
|
|
return {'CANCELLED'}
|
|
|
|
if project.id == "":
|
|
self.report(
|
|
{'ERROR'},
|
|
"Operator is not able to determine the Kitsu production's name. \nCheck project is selected in 'Blender Kitsu' addon preferences.",
|
|
)
|
|
return {'CANCELLED'}
|
|
|
|
if not addon_prefs.is_project_root_valid:
|
|
self.report(
|
|
{'ERROR'},
|
|
"Operator is not able to determine the project root directory. \nCheck project root directory is configured in 'Blender Kitsu' addon preferences.",
|
|
)
|
|
return {'CANCELLED'}
|
|
|
|
self.production_name = project.name
|
|
|
|
return cast(Set[str], context.window_manager.invoke_props_dialog(self, width=400))
|
|
|
|
def cancel(self, context: bpy.types.Context):
|
|
# Restore kitsu context if cancelled
|
|
context.scene.kitsu.category = self._current_kitsu_context
|
|
|
|
|
|
class KITSU_OT_build_new_asset(KITSU_OT_build_new_file_baseclass):
|
|
bl_idname = "kitsu.build_new_asset"
|
|
bl_label = "Build New Asset"
|
|
bl_description = "Build a New Asset file, based on project data from Kitsu Server"
|
|
bl_options = {"REGISTER"}
|
|
|
|
_kitsu_context_type = "ASSET" # Default context for this operator
|
|
|
|
def draw(self, context: bpy.types.Context) -> None:
|
|
global ACTIVE_PROJECT
|
|
layout = self.layout
|
|
layout.use_property_split = True
|
|
layout.use_property_decorate = False
|
|
flow = layout.grid_flow(
|
|
row_major=True, columns=0, even_columns=True, even_rows=False, align=False
|
|
)
|
|
col = flow.column()
|
|
row = col.row()
|
|
row.enabled = False
|
|
row.prop(self, "production_name")
|
|
|
|
context_core.draw_asset_type_selector(context, col)
|
|
context_core.draw_asset_selector(context, col)
|
|
col.prop(self, "save_file")
|
|
|
|
def execute(self, context: bpy.types.Context):
|
|
# Get Properties
|
|
scene = context.scene
|
|
asset_type = cache.asset_type_active_get()
|
|
asset = cache.asset_active_get()
|
|
|
|
if asset_type.id == "" or asset.id == "":
|
|
self.report({'ERROR'}, "Please select a asset type and asset to build a shot file")
|
|
return {'CANCELLED'}
|
|
|
|
asset_file_path_str = asset.get_filepath(context)
|
|
|
|
replace_workspace_with_template(context, "Asset")
|
|
|
|
# Remove All Collections from Scene
|
|
for collection in context.scene.collection.children:
|
|
context.scene.collection.children.unlink(collection)
|
|
bpy.data.collections.remove(collection)
|
|
|
|
# Remove All Objects from Scene
|
|
for object in context.scene.objects:
|
|
context.scene.objects.unlink(object)
|
|
bpy.data.objects.remove(object)
|
|
|
|
bpy.ops.outliner.orphans_purge(do_local_ids=True, do_linked_ids=True, do_recursive=True)
|
|
|
|
asset_collection = bpy.data.collections.new(asset.get_collection_name())
|
|
context.scene.collection.children.link(asset_collection)
|
|
|
|
# Set Kitsu Context
|
|
scene.kitsu.category = "ASSET"
|
|
scene.kitsu.asset_type_active_name = asset_type.name
|
|
scene.kitsu.asset_active_name = asset.name
|
|
scene.kitsu.asset_col = asset_collection
|
|
|
|
relative_path = Path(asset_file_path_str).relative_to(prefs.project_root_dir_get(context))
|
|
asset.set_asset_path(str(relative_path), asset_collection.name)
|
|
|
|
# Save File
|
|
if self.save_file:
|
|
if not save_shot_builder_file(file_path=asset_file_path_str):
|
|
self.report(
|
|
{"WARNING"},
|
|
f"Failed to save file at path `{asset_file_path_str}`",
|
|
)
|
|
return {"FINISHED"}
|
|
|
|
self.report({"INFO"}, f"Successfully Built Shot:`{asset.name}`")
|
|
return {"FINISHED"}
|
|
|
|
|
|
class KITSU_OT_open_asset_file(KITSU_OT_build_new_file_baseclass):
|
|
bl_idname = "kitsu.open_asset_file"
|
|
bl_label = "Open Asset File"
|
|
bl_description = "Open an Asset File from the current project"
|
|
|
|
_kitsu_context_type = "ASSET"
|
|
|
|
save_current: bpy.props.BoolProperty( # type: ignore
|
|
name="Save Current File",
|
|
description="Automatically save the current file before opening a new one.",
|
|
default=True,
|
|
)
|
|
|
|
def draw(self, context: bpy.types.Context) -> None:
|
|
global ACTIVE_PROJECT
|
|
layout = self.layout
|
|
layout.use_property_split = True
|
|
layout.use_property_decorate = False
|
|
flow = layout.grid_flow(
|
|
row_major=True, columns=0, even_columns=True, even_rows=False, align=False
|
|
)
|
|
col = flow.column()
|
|
row = col.row()
|
|
row.enabled = False
|
|
row.prop(self, "production_name")
|
|
context_core.draw_asset_type_selector(context, col)
|
|
context_core.draw_asset_selector(context, col)
|
|
|
|
if bpy.data.is_dirty:
|
|
col.prop(self, "save_current")
|
|
|
|
def execute(self, context: bpy.types.Context):
|
|
asset = cache.asset_active_get()
|
|
asset_file_path_str = asset.get_filepath(context)
|
|
if not Path(asset_file_path_str).exists():
|
|
self.report({'ERROR'}, f"Asset file does not exist: {asset_file_path_str}")
|
|
return {'CANCELLED'}
|
|
|
|
if bpy.data.is_dirty and self.save_current:
|
|
bpy.ops.wm.save_mainfile()
|
|
|
|
bpy.ops.wm.open_mainfile(filepath=asset_file_path_str)
|
|
return {'FINISHED'}
|
|
|
|
|
|
class KITSU_OT_build_new_shot(KITSU_OT_build_new_file_baseclass):
|
|
bl_idname = "kitsu.build_new_shot"
|
|
bl_label = "Build New Shot"
|
|
bl_description = "Build a New Shot file, based on project information found on Kitsu Server"
|
|
bl_options = {"REGISTER"}
|
|
|
|
_kitsu_context_type = "SHOT"
|
|
|
|
def draw(self, context: bpy.types.Context) -> None:
|
|
global ACTIVE_PROJECT
|
|
layout = self.layout
|
|
layout.use_property_split = True
|
|
layout.use_property_decorate = False
|
|
flow = layout.grid_flow(
|
|
row_major=True, columns=0, even_columns=True, even_rows=False, align=False
|
|
)
|
|
col = flow.column()
|
|
row = col.row()
|
|
row.enabled = False
|
|
row.prop(self, "production_name")
|
|
if ACTIVE_PROJECT.production_type == bkglobals.KITSU_TV_PROJECT:
|
|
context_core.draw_episode_selector(context, col)
|
|
context_core.draw_sequence_selector(context, col)
|
|
context_core.draw_shot_selector(context, col)
|
|
context_core.draw_task_type_selector(context, col)
|
|
col.prop(self, "save_file")
|
|
|
|
def _get_task_type_for_shot(self, context, shot):
|
|
for task_type in shot.get_all_task_types():
|
|
if task_type.id == self.task_type:
|
|
return task_type
|
|
|
|
def _frame_range_invalid(self, context, shot) -> bool:
|
|
if not (getattr(shot, "data") or getattr(shot, "nb_frames")):
|
|
return True
|
|
|
|
try:
|
|
shot.data.get("frame_in")
|
|
except AttributeError:
|
|
return True
|
|
|
|
def execute(self, context: bpy.types.Context):
|
|
# Get Properties
|
|
active_project = cache.project_active_get()
|
|
seq = cache.sequence_active_get()
|
|
shot = cache.shot_active_get()
|
|
task_type = cache.task_type_active_get()
|
|
config.settings_load()
|
|
|
|
if seq.id == "" or shot.id == "" or task_type.id == "":
|
|
self.report(
|
|
{'ERROR'}, "Please select a sequence, shot and task type to build a shot file"
|
|
)
|
|
return {'CANCELLED'}
|
|
|
|
if self._frame_range_invalid(context, shot):
|
|
self.report(
|
|
{'WARNING'}, F"Shot {shot.name} is missing frame range data on Kitsu Server"
|
|
)
|
|
|
|
task_type_short_name = task_type.get_short_name()
|
|
shot_file_path_str = shot.get_filepath(context, task_type_short_name)
|
|
|
|
# Open Template File
|
|
replace_workspace_with_template(context, task_type.name)
|
|
|
|
# Set Up Scene + Naming
|
|
shot_task_name = shot.get_task_name(task_type.get_short_name())
|
|
scene = core.set_shot_scene(context, shot_task_name)
|
|
core.remove_all_data()
|
|
core.set_resolution_and_fps(active_project, scene)
|
|
core.set_frame_range(shot, scene)
|
|
|
|
# Set Render Settings
|
|
if task_type_short_name == 'anim': # TODO get anim from a constant instead
|
|
core.set_render_engine(context.scene, 'BLENDER_WORKBENCH')
|
|
else:
|
|
core.set_render_engine(context.scene)
|
|
|
|
# Create Output Collection & Link Camera
|
|
if config.OUTPUT_COL_CREATE.get(task_type_short_name):
|
|
output_col = core.create_task_type_output_collection(context.scene, shot, task_type)
|
|
if task_type_short_name == 'anim' or task_type_short_name == 'layout':
|
|
core.link_camera_rig(context.scene, output_col)
|
|
|
|
# Load Assets
|
|
get_shot_assets(scene=scene, output_collection=output_col, shot=shot)
|
|
|
|
# Link External Output Collections
|
|
core.link_task_type_output_collections(shot, task_type)
|
|
|
|
if config.LOAD_EDITORIAL_REF.get(task_type_short_name):
|
|
edit_export_import_latest(context, shot)
|
|
|
|
# Run Hooks
|
|
hooks_instance = Hooks()
|
|
hooks_instance.load_hooks(context)
|
|
hooks_instance.execute_hooks(
|
|
match_task_type=task_type_short_name,
|
|
scene=context.scene,
|
|
shot=shot,
|
|
prod_path=prefs.project_root_dir_get(context),
|
|
shot_path=shot_file_path_str,
|
|
)
|
|
|
|
# Set Kitsu Context
|
|
scene.kitsu.category = "SHOT"
|
|
scene.kitsu.sequence_active_name = seq.name
|
|
scene.kitsu.shot_active_name = shot.name
|
|
scene.kitsu.task_type_active_name = task_type.name
|
|
|
|
# Save File
|
|
if self.save_file:
|
|
if not save_shot_builder_file(file_path=shot_file_path_str):
|
|
self.report(
|
|
{"WARNING"},
|
|
f"Failed to save file at path `{shot_file_path_str}`",
|
|
)
|
|
return {"FINISHED"}
|
|
|
|
self.report({"INFO"}, f"Successfully Built Shot:`{shot.name}` Task: `{task_type.name}`")
|
|
return {"FINISHED"}
|
|
|
|
|
|
class KITSU_OT_open_shot_file(KITSU_OT_build_new_file_baseclass):
|
|
bl_idname = "kitsu.open_shot_file"
|
|
bl_label = "Open Shot File"
|
|
bl_description = "Open a Shot File from the current project"
|
|
|
|
_kitsu_context_type = "SHOT"
|
|
|
|
save_current: bpy.props.BoolProperty( # type: ignore
|
|
name="Save Current File",
|
|
description="Automatically save the current file before opening a new one.",
|
|
default=True,
|
|
)
|
|
|
|
def draw(self, context: bpy.types.Context) -> None:
|
|
global ACTIVE_PROJECT
|
|
layout = self.layout
|
|
layout.use_property_split = True
|
|
layout.use_property_decorate = False
|
|
flow = layout.grid_flow(
|
|
row_major=True, columns=0, even_columns=True, even_rows=False, align=False
|
|
)
|
|
col = flow.column()
|
|
row = col.row()
|
|
row.enabled = False
|
|
row.prop(self, "production_name")
|
|
if ACTIVE_PROJECT.production_type == bkglobals.KITSU_TV_PROJECT:
|
|
context_core.draw_episode_selector(context, col)
|
|
context_core.draw_sequence_selector(context, col)
|
|
context_core.draw_shot_selector(context, col)
|
|
context_core.draw_task_type_selector(context, col)
|
|
|
|
if bpy.data.is_dirty:
|
|
col.prop(self, "save_current")
|
|
|
|
def execute(self, context: bpy.types.Context):
|
|
shot = cache.shot_active_get()
|
|
task_type = cache.task_type_active_get()
|
|
|
|
task_type_short_name = task_type.get_short_name()
|
|
shot_file_path_str = shot.get_filepath(context, task_type_short_name)
|
|
if not Path(shot_file_path_str).exists():
|
|
self.report({'ERROR'}, f"Shot file does not exist: {shot_file_path_str}")
|
|
return {'CANCELLED'}
|
|
|
|
if bpy.data.is_dirty and self.save_current:
|
|
bpy.ops.wm.save_mainfile()
|
|
|
|
bpy.ops.wm.open_mainfile(filepath=shot_file_path_str)
|
|
return {'FINISHED'}
|
|
|
|
|
|
class KITSU_OT_create_edit_file(KITSU_OT_build_new_file_baseclass):
|
|
bl_idname = "kitsu.create_edit_file"
|
|
bl_label = "Create Edit File"
|
|
bl_description = "Create a new .blend file for editing using Blender's Video Editing template"
|
|
|
|
_edit_entity = None
|
|
_production_name = None
|
|
_kitsu_context_type = "EDIT"
|
|
|
|
create_kitsu_edit: bpy.props.BoolProperty( # type: ignore
|
|
name="Create Kitsu Edit if none exists.",
|
|
description="Automatically create a Kitsu edit for the edit.",
|
|
default=True,
|
|
)
|
|
|
|
def draw(self, context: bpy.types.Context) -> None:
|
|
global ACTIVE_PROJECT
|
|
layout = self.layout
|
|
if ACTIVE_PROJECT.production_type == bkglobals.KITSU_TV_PROJECT:
|
|
context_core.draw_episode_selector(context, layout)
|
|
layout.prop(self, "create_kitsu_edit")
|
|
layout.prop(self, "save_file")
|
|
|
|
def execute(self, context):
|
|
scene = context.scene
|
|
active_project = cache.project_active_get()
|
|
self._edit_entity = cache.edit_default_get(
|
|
create=self.create_kitsu_edit, episode_id=context.scene.kitsu.episode_active_id
|
|
)
|
|
self._edit_entity.set_edit_task()
|
|
task_type = self._edit_entity.get_task_type()
|
|
|
|
if not self._edit_entity:
|
|
self.report({'ERROR'}, "Failed to create Kitsu edit entity.")
|
|
return {'CANCELLED'}
|
|
|
|
edit_file_path_str = self._edit_entity.get_filepath(context)
|
|
|
|
# Create a new file using the Video Editing template
|
|
replace_workspace_with_template(context, task_type.name)
|
|
core.set_resolution_and_fps(active_project, scene)
|
|
|
|
cache.reset_all_edits_enum_for_active_project()
|
|
|
|
scene.kitsu.category = "EDIT"
|
|
scene.kitsu.edit_active_name = context_core.get_versioned_file_basename(
|
|
Path(edit_file_path_str).stem
|
|
)
|
|
scene.kitsu.task_type_active_name = bkglobals.EDIT_TASK_TYPE
|
|
|
|
# Save File
|
|
if self.save_file:
|
|
if not save_shot_builder_file(file_path=edit_file_path_str):
|
|
self.report(
|
|
{"WARNING"},
|
|
f"Failed to save file at path `{edit_file_path_str}`",
|
|
)
|
|
return {"FINISHED"}
|
|
|
|
self.report({'INFO'}, f"Created edit file at {edit_file_path_str}")
|
|
|
|
return {'FINISHED'}
|
|
|
|
|
|
class KITSU_OT_open_edit_file(KITSU_OT_build_new_file_baseclass):
|
|
bl_idname = "kitsu.open_edit_file"
|
|
bl_label = "Open Edit File"
|
|
bl_description = "Open Latest Edit File from the current project"
|
|
|
|
_kitsu_context_type = "EDIT"
|
|
|
|
save_current: bpy.props.BoolProperty( # type: ignore
|
|
name="Save Current File",
|
|
description="Automatically save the current file before opening a new one.",
|
|
default=True,
|
|
)
|
|
|
|
def draw(self, context: bpy.types.Context) -> None:
|
|
global ACTIVE_PROJECT
|
|
layout = self.layout
|
|
layout.use_property_split = True
|
|
layout.use_property_decorate = False
|
|
flow = layout.grid_flow(
|
|
row_major=True, columns=0, even_columns=True, even_rows=False, align=False
|
|
)
|
|
col = flow.column()
|
|
row = col.row()
|
|
row.enabled = False
|
|
row.prop(self, "production_name")
|
|
if ACTIVE_PROJECT.production_type == bkglobals.KITSU_TV_PROJECT:
|
|
context_core.draw_episode_selector(context, col)
|
|
context_core.draw_edit_selector(context, col)
|
|
|
|
if bpy.data.is_dirty:
|
|
col.prop(self, "save_current")
|
|
|
|
def execute(self, context: bpy.types.Context):
|
|
edit_entity = cache.edit_default_get(episode_id=context.scene.kitsu.episode_active_id)
|
|
if not edit_entity:
|
|
self.report({'ERROR'}, "No edit task found on Kitsu Server.")
|
|
return {'CANCELLED'}
|
|
|
|
edit_file_path_str = edit_entity.get_filepath(context)
|
|
if not Path(edit_file_path_str).exists():
|
|
self.report({'ERROR'}, f"Edit file does not exist: {edit_file_path_str}")
|
|
return {'CANCELLED'}
|
|
|
|
if bpy.data.is_dirty and self.save_current:
|
|
bpy.ops.wm.save_mainfile()
|
|
|
|
bpy.ops.wm.open_mainfile(filepath=edit_file_path_str)
|
|
return {'FINISHED'}
|
|
|
|
|
|
classes = [
|
|
KITSU_OT_build_new_shot,
|
|
KITSU_OT_build_new_asset,
|
|
KITSU_OT_build_config_save_hooks,
|
|
KITSU_OT_build_config_save_settings,
|
|
KITSU_OT_build_config_save_templates,
|
|
KITSU_OT_create_edit_file,
|
|
KITSU_OT_open_edit_file,
|
|
KITSU_OT_open_shot_file,
|
|
KITSU_OT_open_asset_file,
|
|
]
|
|
|
|
|
|
def register():
|
|
for cls in classes:
|
|
bpy.utils.register_class(cls)
|
|
|
|
|
|
def unregister():
|
|
for cls in reversed(classes):
|
|
bpy.utils.unregister_class(cls)
|