Blender Kitsu: Use new Kitsu Context UI in Multi Edit / Metadata #280

Merged
Nick Alberelli merged 11 commits from TinyNick/blender-studio-pipeline:fix/blender-kitsu-multi-edit into main 2024-04-08 17:51:04 +02:00
8 changed files with 211 additions and 60 deletions

Binary file not shown.

Binary file not shown.

View File

@ -13,7 +13,7 @@ blender-kitsu is a Blender Add-on to interact with Kitsu from within Blender. It
- [Metadata](#metadata) - [Metadata](#metadata)
- [Push](#push) - [Push](#push)
- [Pull](#pull) - [Pull](#pull)
- [Multi Edit](#multi-edit) - [Multi Edit Metadata](#multi-edit-metadata)
- [Import Media](#import-media) - [Import Media](#import-media)
- [General Sequence Editor Tools](#general-sequence-editor-tools) - [General Sequence Editor Tools](#general-sequence-editor-tools)
- [Context](#context) - [Context](#context)
@ -185,13 +185,25 @@ As a result a bigger edit with nice sequence_colors can look pretty cool:
![image info](/media/addons/blender_kitsu/sqe_sequence_colors.jpg) ![image info](/media/addons/blender_kitsu/sqe_sequence_colors.jpg)
##### Multi Edit ##### Multi Edit Metadata
The `Multi Edit` panel only appears when you select multiple metadata strips that are all `initialized` but not `linked` yet. <br/> The `Multi Edit Metadata` panel only appears when you select multiple metadata strips that are all `initialized` but not `linked` yet. <br/>
![image info](/media/addons/blender_kitsu/sqe_multi_edit.jpg) ![image info](/media/addons/blender_kitsu/sqe_multi_edit.jpg)
It is meant to be way to quickly setup lots of shots if they don't exist on Kitsu yet. You specify the sequence all shots should belong to and adjust the `Shot Counter Start` value. In the preview property you can see how all shots will be named when you execute the `Multi Edit Strip` operator. <br/> It is meant to be way to quickly setup lots of shots if they don't exist on Kitsu yet. You specify the sequence all shots should belong to and adjust the `Shot Counter Start` value. In the preview property you can see how all shots will be named when you execute the `Multi Edit Strip` operator. <br/>
###### Advanced Settings
If you enable the `Advanced` mode (via the screwdriver/wrench icon) next to the counter value, you have access to advance settings to customize the operator even more.
![image info](/media/addons/blender_kitsu/sqe_multi_edit_advanced.jpg)
You can adjust the number of counter digits, the increment size and also the `Pattern` it will use to generate the shot name. <br/>
>**Pattern**: supports 3 wildcards. `<Sequence>`, `<Counter>`, `<Project>`, `Episode` that can be used multiple times in any order. <br/>
**Custom Sequence Variable**: specify a custom string that should be used in the `<Sequence>` wildcard instead of the sequence name. <br/>
**Custom Project Variable**: specify a custom string that should be used in the `<Project>` wildcard instead of the project name. <br/>
##### Import Media ##### Import Media
A collection of operators to Import media based on the Shot associated with the selected metadata strip(s). <br/> A collection of operators to Import media based on the Shot associated with the selected metadata strip(s). <br/>
@ -208,16 +220,6 @@ With a metadata strip selected `Import Image Sequence` Operator will find an ima
Use this operator to import image sequences that have been approved via the [Render Review Add-On](/addons/render_review) Image Sequences can be loaded as either `EXR` or `JPG` sequences. Use this operator to import image sequences that have been approved via the [Render Review Add-On](/addons/render_review) Image Sequences can be loaded as either `EXR` or `JPG` sequences.
###### Advanced Settings
If you check the `Advanced` checkbox next to the counter value, you have access to advance settings to customize the operator even more.
![image info](/media/addons/blender_kitsu/sqe_multi_edit_advanced.jpg)
You can adjust the number of counter digits, the increment size and also the `Pattern` it will use to generate the shot name. <br/>
>**Pattern**: supports 3 wildcards. `<Sequence>`, `<Counter>`, `<Project>` that can be used multiple times in any order. <br/>
**Custom Sequence Variable**: specify a custom string that should be used in the `<Sequence>` wildcard instead of the sequence name. <br/>
**Custom Project Variable**: specify a custom string that should be used in the `<Project>` wildcard instead of the project name. <br/>
##### General Sequence Editor Tools ##### General Sequence Editor Tools
In the general tab you can find some tools that don't directly relate to Kitsu but are useful for editing. In the general tab you can find some tools that don't directly relate to Kitsu but are useful for editing.

View File

@ -316,10 +316,26 @@ class KITSU_addon_preferences(bpy.types.AddonPreferences):
description="Show advanced settings that should already have good defaults", description="Show advanced settings that should already have good defaults",
) )
def set_shot_pattern(self, input):
self['shot_pattern'] = input
return
def get_shot_pattern(
self,
) -> str:
active_project = cache.project_active_get()
if get_safely_string_prop(self, 'shot_pattern') == "":
if active_project.production_type == bkglobals.KITSU_TV_PROJECT:
return "<Episode>_<Sequence>_<Counter>"
return "<Sequence>_<Counter>"
return get_safely_string_prop(self, 'shot_pattern')
shot_pattern: bpy.props.StringProperty( # type: ignore shot_pattern: bpy.props.StringProperty( # type: ignore
name="Shot Pattern", name="Shot Pattern",
description="Pattern to define how Bulk Init will name the shots. Supported wildcards: <Project>, <Sequence>, <Counter>", description="Pattern to define how Bulk Init will name the shots. Supported wildcards: <Project>, <Episode>, <Sequence>, <Counter>",
default="<Sequence>_<Counter>_A", default="<Sequence>_<Counter>",
get=get_shot_pattern,
set=set_shot_pattern,
) )
shot_counter_digits: bpy.props.IntProperty( # type: ignore shot_counter_digits: bpy.props.IntProperty( # type: ignore

View File

@ -27,6 +27,7 @@ from bpy.app.handlers import persistent
from . import propsdata, bkglobals from . import propsdata, bkglobals
from .logger import LoggerFactory from .logger import LoggerFactory
from . import cache from . import cache
from .types import Sequence
logger = LoggerFactory.getLogger() logger = LoggerFactory.getLogger()
@ -49,21 +50,98 @@ class KITSU_property_group_sequence(bpy.types.PropertyGroup):
They hold metadata that will be used to compose a data structure that can They hold metadata that will be used to compose a data structure that can
be pushed to backend. be pushed to backend.
""" """
def _get_shot_description(self): def _get_shot_description(self):
return self.shot_description return self.shot_description
def _get_sequence_name(self): def _get_sequence_entity(self):
return self.sequence_name try:
return Sequence.by_id(self.sequence_id)
except AttributeError:
return None
# Shot. # Shot.
shot_id: bpy.props.StringProperty(name="Shot ID") # type: ignore shot_id: bpy.props.StringProperty(name="Shot ID") # type: ignore
shot_name: bpy.props.StringProperty(name="Shot", default="") # type: ignore shot_name: bpy.props.StringProperty(name="Shot", default="") # type: ignore
###########
# Shot
###########
shot_id: bpy.props.StringProperty( # type: ignore
name="Shot ID",
description="ID that refers to the strip's shot on server",
default="",
)
def get_shot_via_name(self):
return get_safely_string_prop(self, "shot_name")
def set_shot_via_name(self, input):
seq = self._get_sequence_entity()
if seq is None:
return
set_kitsu_entity_id_via_enum_name(
self=self,
input_name=input,
items=cache.get_shots_enum_for_seq(self, bpy.context, seq),
name_prop='shot_name',
id_prop='shot_id',
)
return
def get_shot_search_list(self, context, edit_text):
seq = self._get_sequence_entity()
if seq is None:
return []
return get_enum_item_names(cache.get_shots_enum_for_seq(self, bpy.context, seq))
shot_name: bpy.props.StringProperty( # type: ignore
name="Shot",
description="Name that refers to the strip's shot on server",
default="",
get=get_shot_via_name,
set=set_shot_via_name,
options=set(),
search=get_shot_search_list,
search_options={'SORT'},
)
shot_description: bpy.props.StringProperty(name="Description", default="", options={"HIDDEN"}) # type: ignore shot_description: bpy.props.StringProperty(name="Description", default="", options={"HIDDEN"}) # type: ignore
# Sequence. ###########
sequence_name: bpy.props.StringProperty(name="Sequence", default="") # type: ignore # Sequence
sequence_id: bpy.props.StringProperty(name="Seq ID", default="") # type: ignore ###########
sequence_id: bpy.props.StringProperty( # type: ignore
name="Seq ID",
description="ID that refers to the active sequence on server",
default="",
)
def get_sequences_via_name(self):
return get_safely_string_prop(self, "sequence_name")
def set_sequences_via_name(self, input):
key = set_kitsu_entity_id_via_enum_name(
self=self,
input_name=input,
items=cache.get_sequences_enum_list(self, bpy.context),
name_prop='sequence_name',
id_prop='sequence_id',
)
return
def get_sequence_search_list(self, context, edit_text):
return get_enum_item_names(cache.get_sequences_enum_list(self, bpy.context))
sequence_name: bpy.props.StringProperty( # type: ignore
name="Sequence",
description="Sequence",
default="",
get=get_sequences_via_name,
set=set_sequences_via_name,
options=set(),
search=get_sequence_search_list,
search_options={'SORT'},
)
# Project. # Project.
project_name: bpy.props.StringProperty(name="Project", default="") # type: ignore project_name: bpy.props.StringProperty(name="Project", default="") # type: ignore
@ -89,7 +167,6 @@ class KITSU_property_group_sequence(bpy.types.PropertyGroup):
# Display props. # Display props.
shot_description_display: bpy.props.StringProperty(name="Description", get=_get_shot_description) # type: ignore shot_description_display: bpy.props.StringProperty(name="Description", get=_get_shot_description) # type: ignore
sequence_name_display: bpy.props.StringProperty(name="Sequence", get=_get_sequence_name) # type: ignore
def to_dict(self): def to_dict(self):
return { return {
@ -266,6 +343,8 @@ class KITSU_property_group_scene(bpy.types.PropertyGroup):
if key: if key:
cache.episode_active_set_by_id(bpy.context, key) cache.episode_active_set_by_id(bpy.context, key)
else:
cache.episode_active_reset_entity()
return return
def get_episode_search_list(self, context, edit_text): def get_episode_search_list(self, context, edit_text):
@ -670,10 +749,44 @@ def _add_window_manager_props():
get=propsdata._get_project_active, get=propsdata._get_project_active,
) )
bpy.types.WindowManager.sequence_enum = bpy.props.EnumProperty( ###########
name="Sequences", # Sequence
items=propsdata._get_sequences, ###########
bpy.types.WindowManager.selected_sequence_id = bpy.props.StringProperty( # type: ignore
name="Active Sequence ID",
description="ID that refers to the active sequence on server",
default="",
)
def get_sequences_via_name(self):
return get_safely_string_prop(self, "selected_sequence_name")
def set_sequences_via_name(self, input):
key = set_kitsu_entity_id_via_enum_name(
self=self,
input_name=input,
items=cache.get_sequences_enum_list(self, bpy.context),
name_prop='selected_sequence_name',
id_prop='selected_sequence_id',
)
if key:
cache.sequence_active_set_by_id(bpy.context, key)
else:
cache.sequence_active_reset_entity()
return
def get_sequence_search_list(self, context, edit_text):
return get_enum_item_names(cache.get_sequences_enum_list(self, bpy.context))
bpy.types.WindowManager.selected_sequence_name = bpy.props.StringProperty(
name="Sequence",
description="Name of Sequence the generated Shots will be assinged to", description="Name of Sequence the generated Shots will be assinged to",
default="", # type: ignore
get=get_sequences_via_name,
set=set_sequences_via_name,
options=set(),
search=get_sequence_search_list,
search_options={'SORT'},
) )
# Advanced delete props. # Advanced delete props.
@ -693,7 +806,8 @@ def _clear_window_manager_props():
del bpy.types.WindowManager.shot_counter_start del bpy.types.WindowManager.shot_counter_start
del bpy.types.WindowManager.shot_preview del bpy.types.WindowManager.shot_preview
del bpy.types.WindowManager.var_project_active del bpy.types.WindowManager.var_project_active
del bpy.types.WindowManager.sequence_enum del bpy.types.WindowManager.selected_sequence_id
del bpy.types.WindowManager.selected_sequence_name
def _calc_kitsu_3d_start(self): def _calc_kitsu_3d_start(self):

View File

@ -77,12 +77,17 @@ def _gen_shot_preview(self: Any) -> str:
shot_counter_start = self.shot_counter_start shot_counter_start = self.shot_counter_start
shot_pattern = addon_prefs.shot_pattern shot_pattern = addon_prefs.shot_pattern
examples: List[str] = [] examples: List[str] = []
sequence = self.sequence_enum sequence = self.selected_sequence_name
episode = cache.episode_active_get()
var_project = ( var_project = (
self.var_project_custom if self.var_use_custom_project else self.var_project_active self.var_project_custom if self.var_use_custom_project else self.var_project_active
) )
var_sequence = self.var_sequence_custom if self.var_use_custom_seq else sequence var_sequence = self.var_sequence_custom if self.var_use_custom_seq else sequence
var_lookup_table = {"Sequence": var_sequence, "Project": var_project} var_lookup_table = {
"Sequence": var_sequence,
"Project": var_project,
"Episode": episode.name,
}
for count in range(3): for count in range(3):
counter_number = shot_counter_start + (shot_counter_increment * count) counter_number = shot_counter_start + (shot_counter_increment * count)

View File

@ -528,8 +528,6 @@ class KITSU_OT_sqe_link_shot(bpy.types.Operator):
bl_description = "Links selected sequence strip to shot on server. Pulls all metadata of shot from server" bl_description = "Links selected sequence strip to shot on server. Pulls all metadata of shot from server"
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
sequence_enum: bpy.props.EnumProperty(items=cache.get_sequences_enum_list, name="Sequence") # type: ignore
shots_enum: bpy.props.EnumProperty(items=opsdata.get_shots_enum_for_link_shot_op, name="Shot") # type: ignore
use_url: bpy.props.BoolProperty( use_url: bpy.props.BoolProperty(
name="Use URL", name="Use URL",
description="Use URL of shot on server to initiate strip. Paste complete URL", description="Use URL of shot on server to initiate strip. Paste complete URL",
@ -540,6 +538,8 @@ class KITSU_OT_sqe_link_shot(bpy.types.Operator):
default="", default="",
) )
_strip = None
@classmethod @classmethod
def poll(cls, context: bpy.types.Context) -> bool: def poll(cls, context: bpy.types.Context) -> bool:
sqe = context.scene.sequence_editor sqe = context.scene.sequence_editor
@ -555,9 +555,8 @@ class KITSU_OT_sqe_link_shot(bpy.types.Operator):
) )
def execute(self, context: bpy.types.Context) -> Set[str]: def execute(self, context: bpy.types.Context) -> Set[str]:
strip = context.scene.sequence_editor.active_strip
shot_id = self.shots_enum shot_id = self._strip.kitsu.shot_id
# By url. # By url.
if self.use_url: if self.use_url:
@ -567,8 +566,8 @@ class KITSU_OT_sqe_link_shot(bpy.types.Operator):
# By shot enum. # By shot enum.
else: else:
shot_id = self.shots_enum shot_id = self._strip.kitsu.shot_id
if not shot_id: if shot_id == "":
self.report({"WARNING"}, "Invalid selection. Please choose a shot") self.report({"WARNING"}, "Invalid selection. Please choose a shot")
return {"CANCELLED"} return {"CANCELLED"}
@ -585,10 +584,10 @@ class KITSU_OT_sqe_link_shot(bpy.types.Operator):
return {"CANCELLED"} return {"CANCELLED"}
# Pull shot meta. # Pull shot meta.
pull.shot_meta(strip, shot) pull.shot_meta(self._strip, shot)
# Rename strip. # Rename strip.
strip.name = shot.name self._strip.name = shot.name
# Pull sequence color. # Pull sequence color.
seq = Sequence.by_id(shot.parent_id) seq = Sequence.by_id(shot.parent_id)
@ -596,7 +595,7 @@ class KITSU_OT_sqe_link_shot(bpy.types.Operator):
# Log. # Log.
t = "Linked strip: %s to shot: %s with ID: %s" % ( t = "Linked strip: %s to shot: %s with ID: %s" % (
strip.name, self._strip.name,
shot.name, shot.name,
shot.id, shot.id,
) )
@ -609,6 +608,7 @@ class KITSU_OT_sqe_link_shot(bpy.types.Operator):
def invoke(self, context: bpy.types.Context, event: bpy.types.Event) -> Set[str]: def invoke(self, context: bpy.types.Context, event: bpy.types.Event) -> Set[str]:
if context.window_manager.clipboard: if context.window_manager.clipboard:
self.url = context.window_manager.clipboard self.url = context.window_manager.clipboard
self._strip = context.scene.sequence_editor.active_strip
return context.window_manager.invoke_props_dialog( # type: ignore return context.window_manager.invoke_props_dialog( # type: ignore
self, width=400 self, width=400
@ -624,9 +624,9 @@ class KITSU_OT_sqe_link_shot(bpy.types.Operator):
row.prop(self, "url", text="") row.prop(self, "url", text="")
else: else:
row = layout.row() row = layout.row()
row.prop(self, "sequence_enum") row.prop(self._strip.kitsu, "sequence_name")
row = layout.row() row = layout.row()
row.prop(self, "shots_enum") row.prop(self._strip.kitsu, "shot_name")
row = layout.row() row = layout.row()
@ -647,10 +647,12 @@ class KITSU_OT_sqe_multi_edit_strip(bpy.types.Operator):
# and they all have the same sequence name. # and they all have the same sequence name.
sel_shots = context.selected_sequences sel_shots = context.selected_sequences
if not sel_shots: if not sel_shots:
cls.poll_message_set("No sequences are selected")
return False return False
nr_of_shots = len(sel_shots) nr_of_shots = len(sel_shots)
if nr_of_shots < 1: if nr_of_shots < 1:
cls.poll_message_set("Please more than one sequence")
return False return False
seq_name = sel_shots[0].kitsu.sequence_name seq_name = sel_shots[0].kitsu.sequence_name
@ -660,8 +662,14 @@ class KITSU_OT_sqe_multi_edit_strip(bpy.types.Operator):
or not s.kitsu.initialized or not s.kitsu.initialized
or not checkstrip.is_valid_type(s) or not checkstrip.is_valid_type(s)
): ):
cls.poll_message_set(
"Please select unlinked, initialized strips, of either MOVIE or COLOR type"
)
return False return False
if s.kitsu.sequence_name != seq_name: if s.kitsu.sequence_name != seq_name:
cls.poll_message_set(
"Strips have conflicting sequence names. Please select strips with the same sequence name, or no sequence"
)
return False return False
return True return True
@ -672,7 +680,7 @@ class KITSU_OT_sqe_multi_edit_strip(bpy.types.Operator):
shot_counter_start = context.window_manager.shot_counter_start shot_counter_start = context.window_manager.shot_counter_start
shot_pattern = addon_prefs.shot_pattern shot_pattern = addon_prefs.shot_pattern
strip = context.scene.sequence_editor.active_strip strip = context.scene.sequence_editor.active_strip
sequence = context.window_manager.sequence_enum sequence = context.window_manager.selected_sequence_name
var_project = ( var_project = (
addon_prefs.var_project_custom addon_prefs.var_project_custom
if context.window_manager.var_use_custom_project if context.window_manager.var_use_custom_project
@ -692,12 +700,14 @@ class KITSU_OT_sqe_multi_edit_strip(bpy.types.Operator):
selected_sequences = sorted( selected_sequences = sorted(
selected_sequences, key=lambda x: x.frame_final_start selected_sequences, key=lambda x: x.frame_final_start
) )
episode = cache.episode_active_get()
for idx, strip in enumerate(selected_sequences): for idx, strip in enumerate(selected_sequences):
# Gen data for resolver. # Gen data for resolver.
counter_number = shot_counter_start + (shot_counter_increment * idx) counter_number = shot_counter_start + (shot_counter_increment * idx)
counter = str(counter_number).rjust(shot_counter_digits, "0") counter = str(counter_number).rjust(shot_counter_digits, "0")
var_lookup_table = { var_lookup_table = {
"Episode": episode.name,
"Sequence": var_sequence, "Sequence": var_sequence,
"Project": var_project, "Project": var_project,
"Counter": counter, "Counter": counter,
@ -708,7 +718,9 @@ class KITSU_OT_sqe_multi_edit_strip(bpy.types.Operator):
# Set metadata. # Set metadata.
strip.kitsu.sequence_name = sequence strip.kitsu.sequence_name = sequence
strip.kitsu.sequence_id = context.window_manager.selected_sequence_id
strip.kitsu.shot_name = shot strip.kitsu.shot_name = shot
strip.name = shot
succeeded.append(strip) succeeded.append(strip)
logger.info( logger.info(

View File

@ -20,7 +20,7 @@
import bpy import bpy
from .. import cache, prefs, ui from .. import cache, prefs, ui, bkglobals
from ..sqe import checkstrip from ..sqe import checkstrip
from ..context import core as context_core from ..context import core as context_core
from ..logger import LoggerFactory from ..logger import LoggerFactory
@ -105,6 +105,11 @@ class KITSU_PT_sqe_shot_tools(bpy.types.Panel):
return bool(prefs.session_auth(context) or (sqe and sqe.sequences_all)) return bool(prefs.session_auth(context) or (sqe and sqe.sequences_all))
def draw(self, context: bpy.types.Context) -> None: 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): if self.poll_error(context):
self.draw_error(context) self.draw_error(context)
@ -300,17 +305,13 @@ class KITSU_PT_sqe_shot_tools(bpy.types.Panel):
if not strip.kitsu.sequence_id: if not strip.kitsu.sequence_id:
sub_row = split.row(align=True) sub_row = split.row(align=True)
sub_row.prop(strip.kitsu, "sequence_name_display", text="") sub_row.prop(strip.kitsu, "sequence_name", text="")
sub_row.operator(KITSU_OT_sqe_link_sequence.bl_idname, text="", icon="DOWNARROW_HLT")
sub_row.operator(KITSU_OT_sqe_push_new_sequence.bl_idname, text="", icon="ADD") sub_row.operator(KITSU_OT_sqe_push_new_sequence.bl_idname, text="", icon="ADD")
else: else:
# Lots of splitting because color prop is too big by default # Lots of splitting because color prop is too big by default
sub_split = split.split(factor=0.6, align=True) sub_split = split.split(factor=0.8, align=True)
sub_split.prop(strip.kitsu, "sequence_name_display", text="") sub_split.prop(strip.kitsu, "sequence_name", text="") # TODO Use new dropdown here too
sub_split = sub_split.split(factor=0.3, align=True)
sub_split.operator(KITSU_OT_sqe_link_sequence.bl_idname, text="", icon="DOWNARROW_HLT")
sub_sub_split = sub_split.split(factor=0.4, align=True) 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") sub_sub_split.operator(KITSU_OT_sqe_push_new_sequence.bl_idname, text="", icon="ADD")
@ -354,6 +355,8 @@ class KITSU_PT_sqe_shot_tools(bpy.types.Panel):
@classmethod @classmethod
def poll_multi_edit(cls, context: bpy.types.Context) -> bool: def poll_multi_edit(cls, context: bpy.types.Context) -> bool:
if not prefs.session_auth(context):
return False
sel_shots = context.selected_sequences sel_shots = context.selected_sequences
nr_of_shots = len(sel_shots) nr_of_shots = len(sel_shots)
unvalid = [s for s in sel_shots if s.kitsu.linked or not s.kitsu.initialized] unvalid = [s for s in sel_shots if s.kitsu.linked or not s.kitsu.initialized]
@ -366,26 +369,25 @@ class KITSU_PT_sqe_shot_tools(bpy.types.Panel):
""" """
addon_prefs = prefs.addon_prefs_get(context) addon_prefs = prefs.addon_prefs_get(context)
nr_of_shots = len(context.selected_sequences) nr_of_shots = len(context.selected_sequences)
noun = get_selshots_noun(nr_of_shots) noun = get_selshots_noun(nr_of_shots)
# Create box. # Create box.
layout = self.layout layout = self.layout
box = layout.box() box = layout.box()
box.label(text="Multi Edit", icon="PROPERTIES") box.label(text="Multi Edit Metadata", icon="PROPERTIES")
# Sequence # Sequence
# TODO: use link sequence operator instead or sequence_enum ?
col = box.column() col = box.column()
sub_row = col.row(align=True) sub_row = col.row(align=True)
# Sub_row.prop(context.window_manager, "sequence_name_display"). sub_row.prop(context.window_manager, "selected_sequence_name", text="Sequence")
sub_row.prop(context.window_manager, "sequence_enum", text="Sequence")
sub_row.operator(KITSU_OT_sqe_push_new_sequence.bl_idname, text="", icon="ADD") sub_row.operator(KITSU_OT_sqe_push_new_sequence.bl_idname, text="", icon="ADD")
# Counter. # Counter.
row = box.row() row = box.row()
row.prop(context.window_manager, "shot_counter_start", text="Shot Counter Start") row.prop(context.window_manager, "shot_counter_start", text="Shot Counter Start")
row.prop(context.window_manager, "show_advanced", text="") row.prop(context.window_manager, "show_advanced", text="", icon="TOOL_SETTINGS")
if context.window_manager.show_advanced: if context.window_manager.show_advanced:
# Counter. # Counter.
@ -422,8 +424,8 @@ class KITSU_PT_sqe_shot_tools(bpy.types.Panel):
row = box.row(align=True) row = box.row(align=True)
row.operator( row.operator(
KITSU_OT_sqe_multi_edit_strip.bl_idname, KITSU_OT_sqe_multi_edit_strip.bl_idname,
text=f"Edit {noun}", text=f"Set Metadata for {noun}",
icon="TRIA_RIGHT", icon="ALIGN_LEFT",
) )
@classmethod @classmethod
@ -445,7 +447,7 @@ class KITSU_PT_sqe_shot_tools(bpy.types.Panel):
strips_to_tb.append(s) strips_to_tb.append(s)
strips_to_meta.append(s) strips_to_meta.append(s)
elif s.kitsu.initialized: elif s.kitsu.initialized and s.kitsu.shot_id != "":
strips_to_submit.append(s) strips_to_submit.append(s)
return bool(strips_to_meta or strips_to_tb or strips_to_submit) return bool(strips_to_meta or strips_to_tb or strips_to_submit)