Added "Open in new Blender" button for movie strips with metadata.
The metadata requires the following fields: "BLENDER:BLEND_FILE" (to open the file) "BLENDER:START_FRAME" and "BLENDER:END_FRAME" (just to display)
This commit is contained in:
parent
6f970a41e5
commit
f73671c4f0
@ -404,6 +404,80 @@ class AttractShotSubmitSelected(AttractOperatorMixin, Operator):
|
|||||||
return self.submit_update(strip)
|
return self.submit_update(strip)
|
||||||
|
|
||||||
|
|
||||||
|
class ATTRACT_OT_open_meta_blendfile(AttractOperatorMixin, Operator):
|
||||||
|
bl_idname = 'attract.open_meta_blendfile'
|
||||||
|
bl_label = 'Open Blendfile'
|
||||||
|
bl_description = 'Open Blendfile from movie strip metadata'
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def poll(cls, context):
|
||||||
|
return bool(any(cls.filename_from_metadata(s) for s in context.selected_sequences))
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def filename_from_metadata(strip):
|
||||||
|
"""Returns the blendfile name from the strip metadata, or None."""
|
||||||
|
|
||||||
|
# Metadata is a dict like:
|
||||||
|
# meta = {'END_FRAME': '88',
|
||||||
|
# 'BLEND_FILE': 'metadata-test.blend',
|
||||||
|
# 'SCENE': 'SüperSčene',
|
||||||
|
# 'FRAME_STEP': '1',
|
||||||
|
# 'START_FRAME': '32'}
|
||||||
|
|
||||||
|
meta = strip.get('metadata', None)
|
||||||
|
if not meta:
|
||||||
|
return None
|
||||||
|
|
||||||
|
return meta.get('BLEND_FILE', None) or None
|
||||||
|
|
||||||
|
def execute(self, context):
|
||||||
|
for s in context.selected_sequences:
|
||||||
|
fname = self.filename_from_metadata(s)
|
||||||
|
if not fname: continue
|
||||||
|
|
||||||
|
self.open_in_new_blender(fname)
|
||||||
|
|
||||||
|
return {'FINISHED'}
|
||||||
|
|
||||||
|
def open_in_new_blender(self, fname):
|
||||||
|
"""
|
||||||
|
:type fname: pathlib.Path
|
||||||
|
"""
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
|
||||||
|
cmd = [
|
||||||
|
bpy.app.binary_path,
|
||||||
|
str(fname),
|
||||||
|
]
|
||||||
|
|
||||||
|
if '--enable-new-depsgraph' in sys.argv:
|
||||||
|
cmd[1:1] = ['--enable-new-depsgraph']
|
||||||
|
|
||||||
|
subprocess.Popen(cmd)
|
||||||
|
|
||||||
|
|
||||||
|
def draw_strip_movie_meta(self, context):
|
||||||
|
strip = active_strip(context)
|
||||||
|
if not strip:
|
||||||
|
return
|
||||||
|
|
||||||
|
meta = strip.get('metadata', None)
|
||||||
|
if not meta:
|
||||||
|
return None
|
||||||
|
|
||||||
|
box = self.layout.column(align=True)
|
||||||
|
row = box.row(align=True)
|
||||||
|
fname = meta.get('BLEND_FILE', None) or None
|
||||||
|
if fname:
|
||||||
|
row.label('Original Blendfile: %s' % fname)
|
||||||
|
row.operator(ATTRACT_OT_open_meta_blendfile.bl_idname,
|
||||||
|
text='', icon='FILE_BLEND')
|
||||||
|
sfra = meta.get('START_FRAME', '?')
|
||||||
|
efra = meta.get('END_FRAME', '?')
|
||||||
|
box.label('Original frame range: %s-%s' % (sfra, efra))
|
||||||
|
|
||||||
|
|
||||||
def register():
|
def register():
|
||||||
bpy.types.Sequence.atc_is_synced = bpy.props.BoolProperty(name="Is synced")
|
bpy.types.Sequence.atc_is_synced = bpy.props.BoolProperty(name="Is synced")
|
||||||
bpy.types.Sequence.atc_object_id = bpy.props.StringProperty(name="Attract Object ID")
|
bpy.types.Sequence.atc_object_id = bpy.props.StringProperty(name="Attract Object ID")
|
||||||
@ -423,6 +497,8 @@ def register():
|
|||||||
name="Status")
|
name="Status")
|
||||||
bpy.types.Sequence.atc_order = bpy.props.IntProperty(name="Order")
|
bpy.types.Sequence.atc_order = bpy.props.IntProperty(name="Order")
|
||||||
|
|
||||||
|
bpy.types.SEQUENCER_PT_edit.append(draw_strip_movie_meta)
|
||||||
|
|
||||||
bpy.utils.register_class(ToolsPanel)
|
bpy.utils.register_class(ToolsPanel)
|
||||||
bpy.utils.register_class(AttractShotSubmitNew)
|
bpy.utils.register_class(AttractShotSubmitNew)
|
||||||
bpy.utils.register_class(AttractShotRelink)
|
bpy.utils.register_class(AttractShotRelink)
|
||||||
@ -431,6 +507,7 @@ def register():
|
|||||||
bpy.utils.register_class(AttractStripUnlink)
|
bpy.utils.register_class(AttractStripUnlink)
|
||||||
bpy.utils.register_class(AttractShotFetchUpdate)
|
bpy.utils.register_class(AttractShotFetchUpdate)
|
||||||
bpy.utils.register_class(AttractShotSubmitSelected)
|
bpy.utils.register_class(AttractShotSubmitSelected)
|
||||||
|
bpy.utils.register_class(ATTRACT_OT_open_meta_blendfile)
|
||||||
draw.callback_enable()
|
draw.callback_enable()
|
||||||
|
|
||||||
|
|
||||||
|
@ -165,7 +165,15 @@ class BlenderCloudPreferences(AddonPreferences):
|
|||||||
default=True
|
default=True
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# TODO: store local path with the Attract project, so that people
|
||||||
|
# can switch projects and the local path switches with it.
|
||||||
attract_project = PointerProperty(type=BlenderCloudProjectGroup)
|
attract_project = PointerProperty(type=BlenderCloudProjectGroup)
|
||||||
|
attract_project_local_path = StringProperty(
|
||||||
|
name='Local project path',
|
||||||
|
description='Local path of your Attract project, used to search for blend files; '
|
||||||
|
'usually best to set to an absolute path',
|
||||||
|
subtype='DIR_PATH',
|
||||||
|
default='//../')
|
||||||
|
|
||||||
def draw(self, context):
|
def draw(self, context):
|
||||||
import textwrap
|
import textwrap
|
||||||
@ -251,9 +259,7 @@ class BlenderCloudPreferences(AddonPreferences):
|
|||||||
# Attract stuff
|
# Attract stuff
|
||||||
attract_box = layout.box()
|
attract_box = layout.box()
|
||||||
attract_box.enabled = msg_icon != 'ERROR'
|
attract_box.enabled = msg_icon != 'ERROR'
|
||||||
attract_row = attract_box.row(align=True)
|
self.draw_attract_buttons(attract_box, self.attract_project)
|
||||||
attract_row.label('Attract', icon_value=icon('CLOUD'))
|
|
||||||
self.draw_attract_buttons(attract_row, self.attract_project)
|
|
||||||
|
|
||||||
def draw_subscribe_button(self, layout):
|
def draw_subscribe_button(self, layout):
|
||||||
layout.operator('pillar.subscribe', icon='WORLD')
|
layout.operator('pillar.subscribe', icon='WORLD')
|
||||||
@ -289,9 +295,12 @@ class BlenderCloudPreferences(AddonPreferences):
|
|||||||
else:
|
else:
|
||||||
row_pull.label('Cloud Sync is running.')
|
row_pull.label('Cloud Sync is running.')
|
||||||
|
|
||||||
def draw_attract_buttons(self, layout, bcp: BlenderCloudProjectGroup):
|
def draw_attract_buttons(self, attract_box, bcp: BlenderCloudProjectGroup):
|
||||||
layout.enabled = bcp.status in {'NONE', 'IDLE'}
|
attract_row = attract_box.row(align=True)
|
||||||
row_buttons = layout.row(align=True)
|
attract_row.label('Attract', icon_value=icon('CLOUD'))
|
||||||
|
|
||||||
|
attract_row.enabled = bcp.status in {'NONE', 'IDLE'}
|
||||||
|
row_buttons = attract_row.row(align=True)
|
||||||
|
|
||||||
projects = bcp.available_projects
|
projects = bcp.available_projects
|
||||||
project = bcp.project
|
project = bcp.project
|
||||||
@ -308,6 +317,8 @@ class BlenderCloudPreferences(AddonPreferences):
|
|||||||
else:
|
else:
|
||||||
row_buttons.label('Fetching available projects.')
|
row_buttons.label('Fetching available projects.')
|
||||||
|
|
||||||
|
attract_box.prop(self, 'attract_project_local_path')
|
||||||
|
|
||||||
|
|
||||||
class PillarCredentialsUpdate(pillar.PillarOperatorMixin,
|
class PillarCredentialsUpdate(pillar.PillarOperatorMixin,
|
||||||
Operator):
|
Operator):
|
||||||
|
Reference in New Issue
Block a user