771 lines
26 KiB
Python
771 lines
26 KiB
Python
# SPDX-FileCopyrightText: 2021 Blender Studio Tools Authors
|
|
#
|
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
import bpy
|
|
|
|
from .. import cache, prefs, ui, bkglobals
|
|
from ..sqe import checkstrip
|
|
from ..context import core as context_core
|
|
from ..logger import LoggerFactory
|
|
from ..sqe.ops import (
|
|
KITSU_OT_sqe_push_new_sequence,
|
|
KITSU_OT_sqe_push_new_shot,
|
|
KITSU_OT_sqe_push_shot_meta,
|
|
KITSU_OT_sqe_uninit_strip,
|
|
KITSU_OT_sqe_unlink_shot,
|
|
KITSU_OT_sqe_init_strip,
|
|
KITSU_OT_sqe_link_shot,
|
|
KITSU_OT_sqe_link_sequence,
|
|
KITSU_OT_sqe_set_thumbnail_task_type,
|
|
KITSU_OT_sqe_set_sqe_render_task_type,
|
|
KITSU_OT_sqe_push_render_still,
|
|
KITSU_OT_sqe_push_render,
|
|
KITSU_OT_sqe_push_del_shot,
|
|
KITSU_OT_sqe_pull_shot_meta,
|
|
KITSU_OT_sqe_multi_edit_strip,
|
|
KITSU_OT_sqe_debug_duplicates,
|
|
KITSU_OT_sqe_debug_not_linked,
|
|
KITSU_OT_sqe_debug_multi_project,
|
|
KITSU_OT_sqe_pull_edit,
|
|
KITSU_OT_sqe_init_strip_start_frame,
|
|
KITSU_OT_sqe_create_metadata_strip,
|
|
KITSU_OT_sqe_fix_metadata_strips,
|
|
KITSU_OT_sqe_add_sequence_color,
|
|
KITSU_OT_sqe_scan_for_media_updates,
|
|
KITSU_OT_sqe_change_strip_source,
|
|
KITSU_OT_sqe_clear_update_indicators,
|
|
KITSU_OT_sqe_import_image_sequence,
|
|
KITSU_OT_sqe_import_playblast,
|
|
)
|
|
from pathlib import Path
|
|
|
|
logger = LoggerFactory.getLogger()
|
|
|
|
|
|
def get_selshots_noun(nr_of_shots: int, prefix: str = "Active") -> str:
|
|
if not nr_of_shots:
|
|
noun = "All"
|
|
elif nr_of_shots == 1:
|
|
noun = f"{prefix} Shot"
|
|
else:
|
|
noun = "%i Shots" % nr_of_shots
|
|
return noun
|
|
|
|
|
|
class KITSU_MT_sqe_advanced_delete(bpy.types.Menu):
|
|
bl_label = "Advanced Delete"
|
|
|
|
def draw(self, context: bpy.types.Context) -> None:
|
|
selshots = context.selected_sequences
|
|
strips_to_unlink = [s for s in selshots if s.kitsu.linked]
|
|
|
|
layout = self.layout
|
|
layout.operator(
|
|
KITSU_OT_sqe_push_del_shot.bl_idname,
|
|
text=f"Unlink and Delete {len(strips_to_unlink)} Shots",
|
|
icon="CANCEL",
|
|
)
|
|
|
|
|
|
class KITSU_PT_sqe_shot_tools(bpy.types.Panel):
|
|
"""
|
|
Panel in sequence editor that shows all kinds of tools related to Kitsu and sequence strips
|
|
"""
|
|
|
|
# TODO: Because each draw function was previously a seperate Panel there might be a lot of
|
|
# code duplication now, needs to be refactored at some point
|
|
|
|
bl_category = "Kitsu"
|
|
bl_label = "Shot Tools"
|
|
bl_space_type = "SEQUENCE_EDITOR"
|
|
bl_region_type = "UI"
|
|
bl_order = 20
|
|
|
|
@classmethod
|
|
def poll(cls, context: bpy.types.Context) -> bool:
|
|
if not context_core.is_edit_context():
|
|
return False
|
|
sqe = context.scene.sequence_editor
|
|
return bool(prefs.session_auth(context) or (sqe and sqe.sequences_all))
|
|
|
|
def draw(self, context: bpy.types.Context) -> None:
|
|
active_project = cache.project_active_get()
|
|
if active_project.production_type == bkglobals.KITSU_TV_PROJECT:
|
|
if not cache.episode_active_get():
|
|
self.layout.label(text="Please Set Active Episode", icon="ERROR")
|
|
return
|
|
if self.poll_error(context):
|
|
self.draw_error(context)
|
|
|
|
if self.poll_setup(context):
|
|
self.draw_setup(context)
|
|
|
|
if self.poll_metadata(context):
|
|
self.draw_metadata(context)
|
|
|
|
if self.poll_offline_metadata(context):
|
|
self.draw_offline_metadata(context)
|
|
|
|
if self.poll_multi_edit(context):
|
|
self.draw_multi_edit(context)
|
|
|
|
if self.poll_push(context):
|
|
self.draw_push(context)
|
|
|
|
if self.poll_pull(context):
|
|
self.draw_pull(context)
|
|
self.draw_media(context)
|
|
|
|
if self.poll_debug(context):
|
|
self.draw_debug(context)
|
|
|
|
@classmethod
|
|
def poll_error(cls, context: bpy.types.Context) -> bool:
|
|
project_active = cache.project_active_get()
|
|
addon_prefs = prefs.addon_prefs_get(context)
|
|
|
|
if not prefs.session_auth(context):
|
|
return False
|
|
|
|
return bool(not project_active or not addon_prefs.is_project_root_valid)
|
|
|
|
def draw_error(self, context: bpy.types.Context) -> None:
|
|
layout = self.layout
|
|
project_active = cache.project_active_get()
|
|
box = ui.draw_error_box(layout)
|
|
addon_prefs = prefs.addon_prefs_get(context)
|
|
|
|
if not project_active:
|
|
ui.draw_error_active_project_unset(box)
|
|
|
|
if not addon_prefs.is_project_root_valid:
|
|
ui.draw_error_invalid_project_root_dir(box)
|
|
|
|
@classmethod
|
|
def poll_setup(cls, context: bpy.types.Context) -> bool:
|
|
return bool(context.selected_sequences)
|
|
|
|
def draw_setup(self, context: bpy.types.Context) -> None:
|
|
"""
|
|
Panel in SQE that shows operators to setup shots. That includes initialization,
|
|
uninitizialization, linking and unlinking.
|
|
"""
|
|
|
|
strip = context.scene.sequence_editor.active_strip
|
|
selshots = context.selected_sequences
|
|
nr_of_shots = len(selshots)
|
|
noun = get_selshots_noun(nr_of_shots)
|
|
project_active = cache.project_active_get()
|
|
|
|
strips_to_init = []
|
|
strips_to_uninit = []
|
|
strips_to_unlink = []
|
|
|
|
for s in selshots:
|
|
if s.type not in checkstrip.VALID_STRIP_TYPES:
|
|
continue
|
|
if not s.kitsu.initialized:
|
|
strips_to_init.append(s)
|
|
elif s.kitsu.linked:
|
|
strips_to_unlink.append(s)
|
|
elif s.kitsu.initialized:
|
|
strips_to_uninit.append(s)
|
|
|
|
# Create box.
|
|
layout = self.layout
|
|
box = layout.box()
|
|
box.label(text="Setup Shots", icon="TOOL_SETTINGS")
|
|
|
|
# Production.
|
|
if prefs.session_auth(context):
|
|
box.row().label(text=f"Production: {project_active.name}")
|
|
|
|
# Single Selection.
|
|
if nr_of_shots == 1:
|
|
row = box.row(align=True)
|
|
|
|
# Initialize.
|
|
if strip.type not in checkstrip.VALID_STRIP_TYPES:
|
|
row.label(text=f"Only sequence strips of types: {checkstrip.VALID_STRIP_TYPES }")
|
|
return
|
|
|
|
if not strip.kitsu.initialized:
|
|
# Init active.
|
|
row.operator(KITSU_OT_sqe_init_strip.bl_idname, text=f"Init {noun}", icon="ADD")
|
|
# Link active.
|
|
row.operator(
|
|
KITSU_OT_sqe_link_shot.bl_idname,
|
|
text=f"Link {noun}",
|
|
icon="LINKED",
|
|
)
|
|
# Create metadata strip from uninitialized strip.
|
|
row = box.row(align=True)
|
|
row.operator(
|
|
KITSU_OT_sqe_create_metadata_strip.bl_idname,
|
|
text=f"Create Metadata Strip from {noun}",
|
|
)
|
|
|
|
# Unlink.
|
|
elif strip.kitsu.linked:
|
|
row = box.row(align=True)
|
|
row.operator(
|
|
KITSU_OT_sqe_unlink_shot.bl_idname,
|
|
text=f"Unlink {noun}",
|
|
icon="UNLINKED",
|
|
)
|
|
row.menu("KITSU_MT_sqe_advanced_delete", icon="DOWNARROW_HLT", text="")
|
|
|
|
# Uninitialize.
|
|
else:
|
|
row = box.row(align=True)
|
|
# Unlink active.
|
|
row.operator(
|
|
KITSU_OT_sqe_uninit_strip.bl_idname,
|
|
text=f"Uninitialize {noun}",
|
|
icon="REMOVE",
|
|
)
|
|
|
|
# Multiple Selection.
|
|
elif nr_of_shots > 1:
|
|
row = box.row(align=True)
|
|
|
|
# Init.
|
|
if strips_to_init:
|
|
row.operator(
|
|
KITSU_OT_sqe_init_strip.bl_idname,
|
|
text=f"Init {len(strips_to_init)} Shots",
|
|
icon="ADD",
|
|
)
|
|
row = box.row(align=True)
|
|
row.operator(
|
|
KITSU_OT_sqe_create_metadata_strip.bl_idname,
|
|
text=f"Create {len(strips_to_init)} Metadata Strips",
|
|
)
|
|
|
|
# Make row.
|
|
if strips_to_uninit or strips_to_unlink:
|
|
row = box.row(align=True)
|
|
|
|
# Uninitialize.
|
|
if strips_to_uninit:
|
|
row.operator(
|
|
KITSU_OT_sqe_uninit_strip.bl_idname,
|
|
text=f"Uninitialize {len(strips_to_uninit)} Shots",
|
|
icon="REMOVE",
|
|
)
|
|
|
|
# Unlink all.
|
|
if strips_to_unlink:
|
|
row.operator(
|
|
KITSU_OT_sqe_unlink_shot.bl_idname,
|
|
text=f"Unlink {len(strips_to_unlink)} Shots",
|
|
icon="UNLINKED",
|
|
)
|
|
row.menu("KITSU_MT_sqe_advanced_delete", icon="DOWNARROW_HLT", text="")
|
|
|
|
@classmethod
|
|
def poll_metadata(cls, context: bpy.types.Context) -> bool:
|
|
nr_of_shots = len(context.selected_sequences)
|
|
strip = context.scene.sequence_editor.active_strip
|
|
if nr_of_shots == 1:
|
|
return strip.kitsu.initialized
|
|
return False
|
|
|
|
def draw_metadata(self, context: bpy.types.Context) -> None:
|
|
"""
|
|
Panel in sequence editor that shows .kitsu properties of active strip. (shot, sequence)
|
|
"""
|
|
split_factor = 0.2
|
|
|
|
strip = context.scene.sequence_editor.active_strip
|
|
|
|
# Create box.
|
|
layout = self.layout
|
|
box = layout.box()
|
|
box.label(text="Metadata", icon="ALIGN_LEFT")
|
|
|
|
col = box.column(align=True)
|
|
|
|
# Sequence.
|
|
split = col.split(factor=split_factor, align=True)
|
|
split.label(text="Sequence")
|
|
|
|
if not strip.kitsu.sequence_id:
|
|
sub_row = split.row(align=True)
|
|
sub_row.prop(strip.kitsu, "sequence_name", text="")
|
|
sub_row.operator(KITSU_OT_sqe_push_new_sequence.bl_idname, text="", icon="ADD")
|
|
|
|
else:
|
|
# Lots of splitting because color prop is too big by default
|
|
sub_split = split.split(factor=0.8, align=True)
|
|
sub_split.prop(strip.kitsu, "sequence_name", text="") # TODO Use new dropdown here too
|
|
|
|
sub_sub_split = sub_split.split(factor=0.4, align=True)
|
|
sub_sub_split.operator(KITSU_OT_sqe_push_new_sequence.bl_idname, text="", icon="ADD")
|
|
|
|
try:
|
|
sequence_color_item = context.scene.kitsu.sequence_colors[strip.kitsu.sequence_id]
|
|
except KeyError:
|
|
sub_sub_split.operator(
|
|
KITSU_OT_sqe_add_sequence_color.bl_idname, text="", icon="COLOR"
|
|
)
|
|
|
|
else:
|
|
sub_sub_split.prop(sequence_color_item, "color", text="")
|
|
|
|
# Shot.
|
|
split = col.split(factor=split_factor, align=True)
|
|
split.label(text="Shot")
|
|
if not strip.kitsu.shot_id:
|
|
placeholder = strip.kitsu.shot_name or ''
|
|
split.prop(strip.kitsu, "manual_shot_name", text="", placeholder=placeholder)
|
|
else:
|
|
split.prop(strip.kitsu, "shot_name", text="")
|
|
|
|
# Description.
|
|
split = col.split(factor=split_factor, align=True)
|
|
split.label(text="Description")
|
|
split.prop(strip.kitsu, "shot_description_display", text="")
|
|
split.enabled = False if not strip.kitsu.initialized else True
|
|
|
|
# Frame range.
|
|
split = col.split(factor=split_factor)
|
|
split.label(text="Frame Range")
|
|
row = split.row(align=False)
|
|
row.prop(strip, "kitsu_3d_start", text="In")
|
|
row.prop(strip, "kitsu_frame_end", text="Out")
|
|
row.prop(strip, "kitsu_frame_duration", text="Duration")
|
|
row.operator(KITSU_OT_sqe_init_strip_start_frame.bl_idname, text="", icon="FILE_REFRESH")
|
|
|
|
"""
|
|
split = col.split(factor=split_factor)
|
|
split.label(text="Offsets")
|
|
row = split.row(align=False)
|
|
row.prop(strip.kitsu, "frame_start_offset", text="In")
|
|
"""
|
|
|
|
def poll_offline_metadata(cls, context: bpy.types.Context) -> bool:
|
|
offline_metadata_strips = [
|
|
strip
|
|
for strip in context.scene.sequence_editor.sequences
|
|
if strip.kitsu.shot_id != '' and not Path(strip.filepath).is_file()
|
|
]
|
|
|
|
return len(offline_metadata_strips) > 0
|
|
|
|
def draw_offline_metadata(self, context: bpy.types.Context) -> None:
|
|
# Create box.
|
|
layout = self.layout
|
|
box = layout.box()
|
|
box.label(text="Fix Metadata Strips", icon="ERROR")
|
|
offline_metadata_strips = [
|
|
strip
|
|
for strip in context.selected_sequences
|
|
if strip.kitsu.shot_id != '' and not Path(strip.filepath).is_file()
|
|
]
|
|
if len(offline_metadata_strips) == 0:
|
|
text = "Fix All Missing Media"
|
|
else:
|
|
text = f"Fix {len(offline_metadata_strips)} Missing Media"
|
|
box.operator(KITSU_OT_sqe_fix_metadata_strips.bl_idname, text=text)
|
|
|
|
@classmethod
|
|
def poll_multi_edit(cls, context: bpy.types.Context) -> bool:
|
|
if not prefs.session_auth(context):
|
|
return False
|
|
sel_shots = context.selected_sequences
|
|
nr_of_shots = len(sel_shots)
|
|
unvalid = [s for s in sel_shots if s.kitsu.linked or not s.kitsu.initialized]
|
|
return bool(not unvalid and nr_of_shots > 1)
|
|
|
|
def draw_multi_edit(self, context: bpy.types.Context) -> None:
|
|
"""
|
|
Panel in sequence editor that can edit properties of multiple strips at one.
|
|
Mostly used to quickly initialize lots of shots with an increasing counter.
|
|
"""
|
|
|
|
addon_prefs = prefs.addon_prefs_get(context)
|
|
|
|
nr_of_shots = len(context.selected_sequences)
|
|
noun = get_selshots_noun(nr_of_shots)
|
|
|
|
# Create box.
|
|
layout = self.layout
|
|
box = layout.box()
|
|
box.label(text="Multi Edit Metadata", icon="PROPERTIES")
|
|
|
|
# Sequence
|
|
col = box.column()
|
|
sub_row = col.row(align=True)
|
|
sub_row.prop(context.window_manager, "selected_sequence_name", text="Sequence")
|
|
sub_row.operator(KITSU_OT_sqe_push_new_sequence.bl_idname, text="", icon="ADD")
|
|
|
|
# Counter.
|
|
row = box.row()
|
|
row.prop(context.window_manager, "shot_counter_start", text="Shot Counter Start")
|
|
row.prop(context.window_manager, "show_advanced", text="", icon="TOOL_SETTINGS")
|
|
|
|
if context.window_manager.show_advanced:
|
|
# Counter.
|
|
box.row().prop(addon_prefs, "shot_counter_digits", text="Shot Counter Digits")
|
|
box.row().prop(addon_prefs, "shot_counter_increment", text="Shot Counter Increment")
|
|
|
|
# Variables.
|
|
row = box.row(align=True)
|
|
row.prop(
|
|
context.window_manager,
|
|
"var_use_custom_seq",
|
|
text="Custom Sequence Variable",
|
|
)
|
|
if context.window_manager.var_use_custom_seq:
|
|
row.prop(context.window_manager, "var_sequence_custom", text="")
|
|
|
|
# Project.
|
|
row = box.row(align=True)
|
|
row.prop(
|
|
context.window_manager,
|
|
"var_use_custom_project",
|
|
text="Custom Project Variable",
|
|
)
|
|
if context.window_manager.var_use_custom_project:
|
|
row.prop(context.window_manager, "var_project_custom", text="")
|
|
|
|
# Shot pattern.
|
|
box.row().prop(addon_prefs, "shot_pattern", text="Shot Pattern")
|
|
|
|
# Preview.
|
|
row = box.row()
|
|
row.prop(context.window_manager, "shot_preview", text="Preview")
|
|
|
|
row = box.row(align=True)
|
|
row.operator(
|
|
KITSU_OT_sqe_multi_edit_strip.bl_idname,
|
|
text=f"Set Metadata for {noun}",
|
|
icon="ALIGN_LEFT",
|
|
)
|
|
|
|
@classmethod
|
|
def poll_push(cls, context: bpy.types.Context) -> bool:
|
|
# If only one strip is selected and it is not init then hide panel.
|
|
if not prefs.session_auth(context):
|
|
return False
|
|
|
|
selshots = context.selected_sequences
|
|
if not selshots:
|
|
selshots = context.scene.sequence_editor.sequences_all
|
|
|
|
strips_to_meta = []
|
|
strips_to_tb = []
|
|
strips_to_submit = []
|
|
|
|
for s in selshots:
|
|
if s.kitsu.linked:
|
|
strips_to_tb.append(s)
|
|
strips_to_meta.append(s)
|
|
|
|
elif s.kitsu.initialized and (s.kitsu.manual_shot_name != "" or s.kitsu.shot_name):
|
|
strips_to_submit.append(s)
|
|
|
|
return bool(strips_to_meta or strips_to_tb or strips_to_submit)
|
|
|
|
def draw_push(self, context: bpy.types.Context) -> None:
|
|
"""
|
|
Panel that shows operator to sync sequence editor metadata with backend.
|
|
"""
|
|
nr_of_shots = len(context.selected_sequences)
|
|
layout = self.layout
|
|
strip = context.scene.sequence_editor.active_strip
|
|
|
|
selshots = context.selected_sequences
|
|
if not selshots:
|
|
selshots = context.scene.sequence_editor.sequences_all
|
|
|
|
strips_to_meta = []
|
|
strips_to_tb = []
|
|
strips_to_submit = []
|
|
strips_to_delete = []
|
|
|
|
for s in selshots:
|
|
if s.kitsu.linked:
|
|
strips_to_tb.append(s)
|
|
strips_to_meta.append(s)
|
|
strips_to_delete.append(s)
|
|
|
|
elif s.kitsu.initialized:
|
|
if s.kitsu.shot_name and s.kitsu.sequence_name:
|
|
strips_to_submit.append(s)
|
|
|
|
# Create box.
|
|
layout = self.layout
|
|
box = layout.box()
|
|
box.label(text="Push", icon="EXPORT")
|
|
# Special case if one shot is selected and it is init but not linked
|
|
# shows the operator but it is not enabled until user types in required metadata.
|
|
if nr_of_shots == 1 and not strip.kitsu.linked:
|
|
# New operator.
|
|
row = box.row()
|
|
col = row.column(align=True)
|
|
col.operator(
|
|
KITSU_OT_sqe_push_new_shot.bl_idname,
|
|
text="Submit New Shot",
|
|
icon="ADD",
|
|
)
|
|
return
|
|
|
|
# Either way no selection one selection but linked or multiple.
|
|
|
|
# Metadata operator.
|
|
row = box.row()
|
|
if strips_to_meta:
|
|
col = row.column(align=True)
|
|
noun = get_selshots_noun(len(strips_to_meta), prefix=f"{len(strips_to_meta)}")
|
|
col.operator(
|
|
KITSU_OT_sqe_push_shot_meta.bl_idname,
|
|
text=f"Metadata {noun}",
|
|
icon="ALIGN_LEFT",
|
|
)
|
|
|
|
# Thumbnail and seqeunce renderoperator.
|
|
if strips_to_tb:
|
|
# Upload thumbnail op.
|
|
noun = get_selshots_noun(len(strips_to_tb), prefix=f"{len(strips_to_meta)}")
|
|
split = col.split(factor=0.7, align=True)
|
|
split.operator(
|
|
KITSU_OT_sqe_push_render_still.bl_idname,
|
|
text=f"Render Still {noun}",
|
|
icon="IMAGE_DATA",
|
|
)
|
|
# Select task types op.
|
|
noun = context.scene.kitsu.task_type_thumbnail_name or "Select Task Type"
|
|
split.operator(
|
|
KITSU_OT_sqe_set_thumbnail_task_type.bl_idname,
|
|
text=noun,
|
|
icon="DOWNARROW_HLT",
|
|
)
|
|
|
|
# Sqe render op.
|
|
noun = get_selshots_noun(len(strips_to_tb), prefix=f"{len(strips_to_meta)}")
|
|
split = col.split(factor=0.7, align=True)
|
|
split.operator(
|
|
KITSU_OT_sqe_push_render.bl_idname,
|
|
text=f"Render Movie {noun}",
|
|
icon="IMAGE_DATA",
|
|
)
|
|
# Select task types op.
|
|
noun = context.scene.kitsu.task_type_sqe_render_name or "Select Task Type"
|
|
split.operator(
|
|
KITSU_OT_sqe_set_sqe_render_task_type.bl_idname,
|
|
text=noun,
|
|
icon="DOWNARROW_HLT",
|
|
)
|
|
|
|
# Submit operator.
|
|
if nr_of_shots > 0:
|
|
if strips_to_submit:
|
|
noun = get_selshots_noun(len(strips_to_submit), prefix=f"{len(strips_to_submit)}")
|
|
row = box.row()
|
|
col = row.column(align=True)
|
|
col.operator(
|
|
KITSU_OT_sqe_push_new_shot.bl_idname,
|
|
text=f"Submit {noun}",
|
|
icon="ADD",
|
|
)
|
|
|
|
@classmethod
|
|
def poll_pull(cls, context: bpy.types.Context) -> bool:
|
|
if not prefs.session_auth(context):
|
|
return False
|
|
|
|
selshots = context.selected_sequences
|
|
all_shots = context.scene.sequence_editor.sequences_all
|
|
|
|
if not selshots: # Pull entire edit.
|
|
return True
|
|
|
|
strips_to_meta_sel = [s for s in selshots if s.kitsu.linked]
|
|
strips_to_meta_all = [s for s in all_shots if s.kitsu.linked]
|
|
|
|
if not selshots:
|
|
return bool(strips_to_meta_all)
|
|
return bool(strips_to_meta_sel)
|
|
|
|
def draw_pull(self, context: bpy.types.Context) -> None:
|
|
"""
|
|
Panel that shows operator to sync sequence editor metadata with backend.
|
|
"""
|
|
|
|
selshots = context.selected_sequences
|
|
if not selshots:
|
|
selshots = context.scene.sequence_editor.sequences_all
|
|
|
|
strips_to_meta = []
|
|
|
|
for s in selshots:
|
|
if s.kitsu.linked:
|
|
strips_to_meta.append(s)
|
|
|
|
# Create box.
|
|
layout = self.layout
|
|
box = layout.box()
|
|
box.label(text="Pull", icon="IMPORT")
|
|
|
|
layout = self.layout
|
|
if strips_to_meta:
|
|
noun = get_selshots_noun(len(strips_to_meta), prefix=f"{len(strips_to_meta)}")
|
|
row = box.row()
|
|
row.operator(
|
|
KITSU_OT_sqe_pull_shot_meta.bl_idname,
|
|
text=f"Metadata {noun}",
|
|
icon="ALIGN_LEFT",
|
|
)
|
|
|
|
if not context.selected_sequences:
|
|
row = box.row()
|
|
row.operator(
|
|
KITSU_OT_sqe_pull_edit.bl_idname,
|
|
text=f"Pull entire Edit",
|
|
icon="FILE_MOVIE",
|
|
)
|
|
|
|
@classmethod
|
|
def poll_debug(cls, context: bpy.types.Context) -> bool:
|
|
return prefs.addon_prefs_get(context).enable_debug
|
|
|
|
def draw_debug(self, context: bpy.types.Context) -> None:
|
|
nr_of_shots = len(context.selected_sequences)
|
|
noun = get_selshots_noun(nr_of_shots)
|
|
|
|
# Create box.
|
|
layout = self.layout
|
|
box = layout.box()
|
|
box.label(text="Debug", icon="MODIFIER_ON")
|
|
|
|
row = box.row()
|
|
row.operator(
|
|
KITSU_OT_sqe_debug_duplicates.bl_idname,
|
|
text=f"Duplicates {noun}",
|
|
icon="MODIFIER_ON",
|
|
)
|
|
row = box.row()
|
|
row.operator(
|
|
KITSU_OT_sqe_debug_not_linked.bl_idname,
|
|
text=f"Not Linked {noun}",
|
|
icon="MODIFIER_ON",
|
|
)
|
|
row = box.row()
|
|
row.operator(
|
|
KITSU_OT_sqe_debug_multi_project.bl_idname,
|
|
text=f"Multi Projects {noun}",
|
|
icon="MODIFIER_ON",
|
|
)
|
|
|
|
def draw_media(self, context: bpy.types.Context) -> None:
|
|
sel_metadata_strips = [strip for strip in context.selected_sequences if strip.kitsu.linked]
|
|
|
|
noun = get_selshots_noun(len(sel_metadata_strips), prefix=f"{len(sel_metadata_strips)}")
|
|
playblast = "Playblast" if len(sel_metadata_strips) <= 1 else "Playblasts"
|
|
|
|
sequence = "Sequence" if len(sel_metadata_strips) <= 1 else "Sequences"
|
|
|
|
# Create box.
|
|
layout = self.layout
|
|
box = layout.box()
|
|
box.label(text="Media", icon="RENDER_ANIMATION")
|
|
box.operator(
|
|
KITSU_OT_sqe_import_playblast.bl_idname,
|
|
text=f"Import {noun} {playblast}",
|
|
icon="FILE_MOVIE",
|
|
)
|
|
box.operator(
|
|
KITSU_OT_sqe_import_image_sequence.bl_idname,
|
|
text=f"Import {noun} Image {sequence}",
|
|
icon="RENDER_RESULT",
|
|
)
|
|
|
|
|
|
class KITSU_PT_sqe_general_tools(bpy.types.Panel):
|
|
"""
|
|
Panel in sequence editor that shows tools that don't relate directly to Kitsu
|
|
"""
|
|
|
|
bl_category = "Kitsu"
|
|
bl_label = "General Tools"
|
|
bl_space_type = "SEQUENCE_EDITOR"
|
|
bl_region_type = "UI"
|
|
bl_order = 30
|
|
bl_options = {"DEFAULT_CLOSED"}
|
|
|
|
@classmethod
|
|
def poll(cls, context: bpy.types.Context) -> bool:
|
|
if not context_core.is_edit_context():
|
|
return False
|
|
selshots = context.selected_sequences
|
|
|
|
sqe = context.scene.sequence_editor
|
|
if not sqe:
|
|
return False
|
|
|
|
if not selshots:
|
|
selshots = context.scene.sequence_editor.sequences_all
|
|
movie_strips = [s for s in selshots if s.type == "MOVIE"]
|
|
return bool(movie_strips)
|
|
|
|
def draw(self, context: bpy.types.Context) -> None:
|
|
active_strip = context.scene.sequence_editor.active_strip
|
|
selshots = context.selected_sequences
|
|
if not selshots:
|
|
selshots = context.scene.sequence_editor.sequences_all
|
|
|
|
strips_to_update_media = []
|
|
|
|
for s in selshots:
|
|
if s.type == "MOVIE":
|
|
strips_to_update_media.append(s)
|
|
|
|
# Create box.
|
|
layout = self.layout
|
|
box = layout.box()
|
|
box.label(text="General", icon="MODIFIER")
|
|
|
|
# Scan for outdated media and reset operator.
|
|
row = box.row(align=True)
|
|
row.operator(
|
|
KITSU_OT_sqe_scan_for_media_updates.bl_idname,
|
|
text=f"Check media update for {len(strips_to_update_media)} {'strip' if len(strips_to_update_media) == 1 else 'strips'}",
|
|
)
|
|
row.operator(KITSU_OT_sqe_clear_update_indicators.bl_idname, text="", icon="X")
|
|
|
|
# Up down source operator. Check for to strips to accommodate linked strips
|
|
if len(selshots) <= 2 and active_strip and active_strip.type == "MOVIE":
|
|
row = box.row(align=True)
|
|
row.prop(active_strip, "filepath_display", text="")
|
|
row.operator(
|
|
KITSU_OT_sqe_change_strip_source.bl_idname, text="", icon="TRIA_UP"
|
|
).direction = "UP"
|
|
row.operator(
|
|
KITSU_OT_sqe_change_strip_source.bl_idname, text="", icon="TRIA_DOWN"
|
|
).direction = "DOWN"
|
|
row.operator(
|
|
KITSU_OT_sqe_change_strip_source.bl_idname, text="", icon="FILE_PARENT"
|
|
).go_latest = True
|
|
|
|
|
|
# ---------REGISTER ----------.
|
|
|
|
classes = [
|
|
KITSU_MT_sqe_advanced_delete,
|
|
KITSU_PT_sqe_shot_tools,
|
|
KITSU_PT_sqe_general_tools,
|
|
]
|
|
|
|
|
|
def register():
|
|
for cls in classes:
|
|
bpy.utils.register_class(cls)
|
|
|
|
|
|
def unregister():
|
|
for cls in reversed(classes):
|
|
bpy.utils.unregister_class(cls)
|