1 # SPDX-FileCopyrightText: 2016-2020 by Nathan Lovato, Daniel Oakey, Razvan Radulescu, and contributors
3 # SPDX-License-Identifier: GPL-3.0-or-later
7 from .utils
.functions
import find_sequences_after
8 from .utils
.functions
import convert_duration_to_frames
9 from .utils
.global_settings
import SequenceTypes
10 from .utils
.doc
import doc_name
, doc_idname
, doc_brief
, doc_description
13 class POWER_SEQUENCER_OT_crossfade_add(bpy
.types
.Operator
):
15 *brief* Adds cross fade between selected sequence and the closest sequence to its right
17 Based on the active strip, finds the closest next sequence of a similar type, moves it
18 so it overlaps the active strip, and adds a gamma cross effect between them. Works with
19 MOVIE, IMAGE and META strips
23 "name": doc_name(__qualname__
),
24 "demo": "https://i.imgur.com/ZyEd0jD.gif",
25 "description": doc_description(__doc__
),
27 ({"type": "C", "value": "PRESS", "ctrl": True, "alt": True}, {}, "Add Crossfade")
29 "keymap": "Sequencer",
31 bl_idname
= doc_idname(__qualname__
)
32 bl_label
= doc
["name"]
33 bl_description
= doc_brief(doc
["description"])
34 bl_options
= {"REGISTER", "UNDO"}
36 crossfade_duration
: bpy
.props
.FloatProperty(
37 name
="Crossfade Duration", description
="The duration of the crossfade", default
=0.5, min=0
39 auto_move_strip
: bpy
.props
.BoolProperty(
40 name
="Auto Move Strip",
42 "When true, moves the second strip so the crossfade"
43 " is of the length set in 'Crossfade Length'"
49 def poll(cls
, context
):
50 return context
.selected_sequences
52 def execute(self
, context
):
53 sorted_selection
= sorted(context
.selected_sequences
, key
=lambda s
: s
.frame_final_start
)
54 for s
in sorted_selection
:
55 s_next
= self
.get_next_sequence_after(context
, s
)
56 s_to_offset
= s_next
.input_1
if hasattr(s_next
, "input_1") else s_next
58 if self
.auto_move_strip
:
59 offset
= s_to_offset
.frame_final_start
- s
.frame_final_end
60 s_to_offset
.frame_start
-= offset
62 if s_to_offset
.frame_final_start
== s
.frame_final_end
:
63 self
.offset_sequence_handles(context
, s
, s_to_offset
)
65 self
.apply_crossfade(context
, s
, s_next
)
68 def get_next_sequence_after(self
, context
, sequence
):
70 Returns the first sequence after `sequence` by frame_final_start
74 s
for s
in find_sequences_after(context
, sequence
) if s
.channel
== sequence
.channel
76 next_transitionable
= (s
for s
in next_in_channel
if s
.type in SequenceTypes
.TRANSITIONABLE
)
78 next_sequence
= min(next_transitionable
, key
=lambda s
: s
.frame_final_start
)
83 def apply_crossfade(self
, context
, strip_from
, strip_to
):
84 for s
in bpy
.context
.selected_sequences
:
86 strip_from
.select
= True
87 strip_to
.select
= True
88 context
.scene
.sequence_editor
.active_strip
= strip_to
89 bpy
.ops
.sequencer
.effect_strip_add(type="GAMMA_CROSS")
91 def offset_sequence_handles(self
, context
, sequence_1
, sequence_2
):
93 Moves the handles of the two sequences before adding the crossfade
95 fade_duration
= convert_duration_to_frames(context
, self
.crossfade_duration
)
96 fade_offset
= int(fade_duration
/ 2)
98 if hasattr(sequence_1
, "input_1"):
99 sequence_1
.input_1
.frame_final_end
-= fade_offset
101 sequence_1
.frame_final_end
-= fade_offset
103 if hasattr(sequence_2
, "input_1"):
104 sequence_2
.input_1
.frame_final_start
+= fade_offset
106 sequence_2
.frame_final_start
+= fade_offset