# ##### BEGIN GPL LICENSE BLOCK ##### # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software Foundation, # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # # ##### END GPL LICENSE BLOCK ##### import bpy from . import functions from bpy.types import ( Operator, ) from bpy.props import ( IntProperty, ) from bpy.app.handlers import persistent class OBJECT_OT_Setinout(Operator): bl_label = "Set IN and OUT to selected" bl_idname = "sequencerextra.setinout" bl_description = "Set IN and OUT markers to the selected strips limits" bl_options = {'REGISTER', 'UNDO'} @classmethod def poll(self, context): scn = context.scene if scn and scn.sequence_editor: return scn.sequence_editor.active_strip else: return False def execute(self, context): functions.initSceneProperties(context) scn = context.scene markers = scn.timeline_markers seq = scn.sequence_editor meta_level = len(seq.meta_stack) if meta_level > 0: seq = seq.meta_stack[meta_level - 1] # search for timeline limits tl_start = 300000 tl_end = -300000 for i in context.selected_editable_sequences: if i.select is True: start = i.frame_start + i.frame_offset_start - i.frame_still_start end = start + i.frame_final_duration if start < tl_start: tl_start = start if end > tl_end: tl_end = end # print(tl_start,tl_end) if scn.kr_auto_markers: scn.kr_in_marker = tl_start scn.kr_out_marker = tl_end else: scn.kr_in_marker = tl_start scn.kr_out_marker = tl_end if "IN" in markers: mark = markers["IN"] mark.frame = scn.kr_in_marker else: mark = markers.new(name="IN") mark.frame = scn.kr_in_marker if "OUT" in markers: mark = markers["OUT"] mark.frame = scn.kr_out_marker else: mark = markers.new(name="OUT") mark.frame = scn.kr_in_marker return {'FINISHED'} class OBJECT_OT_Triminout(Operator): bl_label = "Trim to in & out" bl_idname = "sequencerextra.triminout" bl_description = "Trim the selected strip to IN and OUT markers (if exists)" bl_options = {'REGISTER', 'UNDO'} @classmethod def poll(self, context): scn = context.scene if scn and scn.sequence_editor: if scn.sequence_editor.active_strip: markers = scn.timeline_markers if "IN" and "OUT" in markers: return True else: return False def execute(self, context): scene = context.scene seq = scene.sequence_editor meta_level = len(seq.meta_stack) if meta_level > 0: seq = seq.meta_stack[meta_level - 1] markers = scene.timeline_markers sin = markers["IN"].frame sout = markers["OUT"].frame strips = context.selected_editable_sequences # (triminout function only works fine # with one strip selected at a time) for strip in strips: # deselect all other strips for i in strips: i.select = False # select current strip strip.select = True remove = functions.triminout(strip, sin, sout) if remove is True: bpy.ops.sequencer.delete() # select all strips again for strip in strips: try: strip.select = True except ReferenceError: pass bpy.ops.sequencer.reload() return {'FINISHED'} # SOURCE IN OUT class OBJECT_OT_Sourcein(Operator): # Operator source in bl_label = "Source IN" bl_idname = "sequencerextra.sourcein" bl_description = "Add or move a marker named IN" bl_options = {'REGISTER', 'UNDO'} @classmethod def poll(self, context): scn = context.scene if scn: return scn.sequence_editor else: return False def execute(self, context): functions.initSceneProperties(context) scn = context.scene markers = scn.timeline_markers if scn.kr_auto_markers: scn.kr_in_marker = scn.frame_current else: scn.kr_in_marker = scn.frame_current if "IN" in markers: mark = markers["IN"] mark.frame = scn.kr_in_marker else: mark = markers.new(name="IN") mark.frame = scn.kr_in_marker # limit OUT marker position with IN marker if scn.kr_in_marker > scn.kr_out_marker: scn.kr_out_marker = scn.kr_in_marker if "OUT" in markers: mark = markers["OUT"] mark.frame = scn.kr_out_marker for m in markers: m.select = False if m.name in {"IN", "OUT"}: m.select = True bpy.ops.sequencer.reload() return {'FINISHED'} class OBJECT_OT_Sourceout(Operator): # Operator source out bl_label = "Source OUT" bl_idname = "sequencerextra.sourceout" bl_description = "Add or move a marker named OUT" bl_options = {'REGISTER', 'UNDO'} @classmethod def poll(self, context): scn = context.scene if scn: return scn.sequence_editor else: return False def execute(self, context): scn = context.scene functions.initSceneProperties(context) markers = scn.timeline_markers if scn.kr_auto_markers: scn.kr_out_marker = scn.frame_current else: scn.kr_out_marker = scn.frame_current # limit OUT marker position with IN marker if scn.kr_out_marker < scn.kr_in_marker: scn.kr_out_marker = scn.kr_in_marker if "OUT" in markers: mark = markers["OUT"] mark.frame = scn.kr_out_marker else: mark = markers.new(name="OUT") mark.frame = scn.kr_out_marker for m in markers: m.select = False if m.name in {"IN", "OUT"}: m.select = True bpy.ops.sequencer.reload() return {'FINISHED'} class OBJECT_OT_Setstartend(Operator): # Operator set start & end bl_label = "Set Start and End" bl_idname = "sequencerextra.setstartend" bl_description = "Set Start and End to IN and OUT marker values" bl_options = {'REGISTER', 'UNDO'} @classmethod def poll(self, context): scn = context.scene markers = scn.timeline_markers if "IN" and "OUT" in markers: return True else: return False def execute(self, context): functions.initSceneProperties(context) scn = context.scene markers = scn.timeline_markers sin = markers["IN"] sout = markers["OUT"] scn.frame_start = sin.frame scn.frame_end = sout.frame - 1 bpy.ops.sequencer.reload() return {'FINISHED'} # Copy paste class OBJECT_OT_Metacopy(Operator): # Operator copy source in/out bl_label = "Trim and Meta-Copy" bl_idname = "sequencerextra.metacopy" bl_description = ("Make meta from selected strips, trim it to in / out\n" "(if available) and copy it to clipboard") bl_options = {'REGISTER', 'UNDO'} def execute(self, context): try: # redo scene = bpy.context.scene seq = scene.sequence_editor markers = scene.timeline_markers strip1 = seq.active_strip if strip1 is None: self.report({'ERROR'}, "No strip selected") return {"CANCELLED"} if "IN" and "OUT" in markers: sin = markers["IN"].frame sout = markers["OUT"].frame bpy.ops.sequencer.meta_make() strip2 = seq.active_strip functions.triminout(strip2, sin, sout) bpy.ops.sequencer.copy() bpy.ops.sequencer.meta_separate() self.report({'INFO'}, "META2 has been trimed and copied") else: bpy.ops.sequencer.meta_make() bpy.ops.sequencer.copy() bpy.ops.sequencer.meta_separate() self.report({'WARNING'}, "No In and Out!! META has been copied") except Exception as e: functions.error_handlers(self, "sequencerextra.metacopy", e, "Trim and Meta-Copy") return {"CANCELLED"} return {'FINISHED'} class OBJECT_OT_Metapaste(Operator): # Operator paste source in/out bl_label = "Paste in current Frame" bl_idname = "sequencerextra.metapaste" bl_description = "Paste source from clipboard to current frame" bl_options = {'REGISTER', 'UNDO'} def execute(self, context): # redo scene = bpy.context.scene bpy.ops.sequencer.paste() bpy.ops.sequencer.snap(frame=scene.frame_current) strips = context.selected_editable_sequences context.scene.sequence_editor.active_strip = strips[0] context.scene.update() return {'FINISHED'} # Operator paste source in/out class OBJECT_OT_Unmetatrim(Operator): bl_label = "Paste in current Frame" bl_idname = "sequencerextra.meta_separate_trim" bl_description = "Unmeta and trim the content to meta duration" bl_options = {'REGISTER', 'UNDO'} @classmethod def poll(self, context): scn = context.scene if scn and scn.sequence_editor: if scn.sequence_editor.active_strip: return scn.sequence_editor.active_strip.type == "META" else: return False def execute(self, context): scn = context.scene seq = scn.sequence_editor markers = scn.timeline_markers # setting in and out around meta # while keeping data to restore in and out positions strip = seq.active_strip sin = strip.frame_start + strip.frame_offset_start sout = sin + strip.frame_final_duration borrarin = False borrarout = False original_in = 0 original_out = 0 if "IN" in markers: original_in = markers["IN"].frame markers["IN"].frame = sin else: mark = markers.new(name="IN") mark.frame = sin borrarin = True if "OUT" in markers: original_out = markers["OUT"].frame markers["OUT"].frame = sout else: mark = markers.new(name="OUT") mark.frame = sout borrarout = True # here starts the operator... # get all META from selected strips metastrips = [] for i in context.selected_editable_sequences: if i.type == "META": metastrips.append(i) for meta in metastrips: bpy.ops.sequencer.reload() # deselect all strips for i in context.selected_editable_sequences: i.select = False # make active current meta meta.select = True seq.active_strip = meta bpy.ops.sequencer.reload() # set in and out to meta sin = meta.frame_start + meta.frame_offset_start sout = sin + meta.frame_final_duration # print("meta: ", sin, sout) # grab meta content newstrips = [] for i in meta.sequences: newstrips.append(i) # store meta channel basechan = meta.channel # look for upper and lower channels used by strips inside the meta lowerchan = 32 upperchan = 0 for i in newstrips: if i.channel < lowerchan: lowerchan = i.channel if i.channel > upperchan: upperchan = i.channel # calculate channel increment needed deltachan = basechan - lowerchan # reorder strips inside the meta # before separate we need to store channel data delta = upperchan - lowerchan + 1 for i in newstrips: i.channel = i.channel + delta chandict = {} for i in newstrips: i.channel = i.channel + deltachan - delta chandict[i.name] = i.channel """ for i in chandict: print(i, chandict[i]) """ # go inside meta to trim strips bpy.ops.sequencer.meta_toggle() # update seq definition according to meta meta_level = len(seq.meta_stack) if meta_level > 0: seq = seq.meta_stack[meta_level - 1] # create a list to store clips outside selection # that will be removed rmlist = [] # deselect all separated strips for j in newstrips: j.select = False # print("newstrips: ",j.name, j.type) # trim each strip separately # first check special strips: # (those who can move when any other does) for i in newstrips: if i.type in {"CROSS", "SPEED", "WIPE"}: i.select = True remove = functions.triminout(i, sin, sout) if remove is True: # print("checked: ",i.name, i.type) rmlist.append(i) i.select = False # now for the rest of strips for i in newstrips: i.select = True remove = functions.triminout(i, sin, sout) if remove is True: # print("checked: ",i.name, i.type) rmlist.append(i) i.select = False # back outside the meta and separate it bpy.ops.sequencer.meta_toggle() bpy.ops.sequencer.meta_separate() # reset seq definition seq = scn.sequence_editor # remove strips from outside the meta duration for i in rmlist: # print("removing: ",i.name, i.type) for j in scn.sequence_editor.sequences_all: j.select = False i.select = True scn.sequence_editor.active_strip = i bpy.ops.sequencer.delete() # select all strips and set one of the strips as active for i in newstrips: if i not in rmlist: i.select = True scn.sequence_editor.active_strip = i bpy.ops.sequencer.reload() # restore original IN and OUT values if borrarin: markers.remove(markers['IN']) else: markers["IN"].frame = original_in if borrarout: markers.remove(markers['OUT']) else: markers["OUT"].frame = original_out scn.update() return {'FINISHED'} class OBJECT_OT_Extrasnap(Operator): # Operator paste source in/out bl_label = "Extra Snap" bl_idname = "sequencerextra.extrasnap" bl_description = "Snap the right, center or left of the strip to current frame" bl_options = {'REGISTER', 'UNDO'} # align: 0 = left snap, 1 = center snap, 2= right snap align = IntProperty( name="Align", min=0, max=2, default=1 ) @classmethod def poll(self, context): scn = context.scene if scn and scn.sequence_editor: return scn.sequence_editor.active_strip else: return False def execute(self, context): scene = bpy.context.scene bpy.ops.sequencer.snap(frame=scene.frame_current) if self.align != 0: strips = context.selected_editable_sequences for strip in strips: if self.align == 1: # center snap strip.frame_start -= strip.frame_final_duration / 2 else: # right snap strip.frame_start -= strip.frame_final_duration return {'FINISHED'} class OBJECT_OT_Extrahandles(Operator): # Operator paste source in/out bl_label = "Extra Handles" bl_idname = "sequencerextra.extrahandles" bl_description = "Snap the right, center or left of the strip to current frame" bl_options = {'REGISTER', 'UNDO'} # side: 0 = left , 1 = both, 2= right side = IntProperty( name="Side", min=0, max=2, default=1 ) @classmethod def poll(self, context): scn = context.scene if scn and scn.sequence_editor: return scn.sequence_editor.active_strip else: return False def execute(self, context): strips = context.selected_editable_sequences resetLeft = False resetRight = False changelistLeft = [] changelistRight = [] for strip in strips: if self.side == 0 or self.side == 1: if strip.select_left_handle: resetLeft = True changelistLeft.append(strip) if self.side == 1 or self.side == 2: if strip.select_right_handle: resetRight = True changelistRight.append(strip) if len(changelistLeft) == len(strips): resetLeft = False if len(changelistRight) == len(strips): resetRight = False if ((len(changelistRight) != len(strips)) or (len(changelistRight) != len(strips))) and \ self.side == 1: resetLeft = True resetRight = True for strip in strips: if resetLeft: strip.select_left_handle = False if self.side == 0 or self.side == 1: if strip.select_left_handle: strip.select_left_handle = False else: strip.select_left_handle = True if resetRight: strip.select_right_handle = False if self.side == 1 or self.side == 2: if strip.select_right_handle: strip.select_right_handle = False else: strip.select_right_handle = True return {'FINISHED'} @persistent def marker_handler(scn): context = bpy.context functions.initSceneProperties(context) if scn.kr_auto_markers: markers = scn.timeline_markers if "IN" in markers: mark = markers["IN"] mark.frame = scn.kr_in_marker else: mark = markers.new(name="IN") mark.frame = scn.kr_in_marker if "OUT" in markers: mark = markers["OUT"] mark.frame = scn.kr_out_marker else: mark = markers.new(name="OUT") mark.frame = scn.kr_out_marker # limit OUT marker position with IN marker if scn.kr_in_marker > scn.kr_out_marker: scn.kr_out_marker = scn.kr_in_marker return {'FINISHED'} else: return {'CANCELLED'} bpy.app.handlers.scene_update_post.append(marker_handler)