Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender-addons.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'power_sequencer/operators/utils/functions.py')
-rw-r--r--power_sequencer/operators/utils/functions.py343
1 files changed, 343 insertions, 0 deletions
diff --git a/power_sequencer/operators/utils/functions.py b/power_sequencer/operators/utils/functions.py
new file mode 100644
index 00000000..35fd900d
--- /dev/null
+++ b/power_sequencer/operators/utils/functions.py
@@ -0,0 +1,343 @@
+#
+# Copyright (C) 2016-2019 by Nathan Lovato, Daniel Oakey, Razvan Radulescu, and contributors
+#
+# This file is part of Power Sequencer.
+#
+# Power Sequencer 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 3 of the
+# License, or (at your option) any later version.
+#
+# Power Sequencer 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 Power Sequencer. If
+# not, see <https://www.gnu.org/licenses/>.
+#
+import bpy
+import subprocess
+from math import sqrt, floor
+from operator import attrgetter
+from .global_settings import SequenceTypes
+
+
+def calculate_distance(x1, y1, x2, y2):
+ return sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2)
+
+
+def convert_duration_to_frames(context, duration):
+ return round(duration * context.scene.render.fps / context.scene.render.fps_base)
+
+
+def find_linked(context, sequences, selected_sequences):
+ """
+ Takes a list of sequences and returns a list of all the sequences
+ and effects that are linked in time
+
+ Args:
+ - sequences: a list of sequences
+
+ Returns a list of all the linked sequences, but not the sequences passed to the function
+ """
+ start, end = get_frame_range(context, sequences, selected_sequences)
+ sequences_in_range = [s for s in sequences if is_in_range(context, s, start, end)]
+ effects = (s for s in sequences_in_range if s.type in SequenceTypes.EFFECT)
+ selected_effects = (s for s in sequences if s.type in SequenceTypes.EFFECT)
+
+ linked_sequences = []
+
+ # Filter down to effects that have at least one of seq as input and
+ # Append input sequences that aren't in the source list to linked_sequences
+ for e in effects:
+ if not hasattr(e, "input_2"):
+ continue
+ for s in sequences:
+ if e.input_2 == s:
+ linked_sequences.append(e)
+ if e.input_1 not in sequences:
+ linked_sequences.append(e.input_1)
+ elif e.input_1 == s:
+ linked_sequences.append(e)
+ if e.input_2 not in sequences:
+ linked_sequences.append(e.input_2)
+
+ # Find inputs of selected effects that are not selected
+ for e in selected_effects:
+ try:
+ if e.input_1 not in sequences:
+ linked_sequences.append(e.input_1)
+ if e.input_count == 2:
+ if e.input_2 not in sequences:
+ linked_sequences.append(e.input_2)
+ except AttributeError:
+ continue
+
+ return linked_sequences
+
+
+def find_neighboring_markers(context, frame=None):
+ """Returns a tuple containing the closest marker to the left and to the right of the frame"""
+ markers = context.scene.timeline_markers
+
+ if not (frame and markers):
+ return None, None
+
+ markers = sorted(markers, key=attrgetter("frame"))
+
+ previous_marker, next_marker = None, None
+ for m in markers:
+ previous_marker = m if m.frame < frame else previous_marker
+ if m.frame > frame:
+ next_marker = m
+ break
+
+ return previous_marker, next_marker
+
+
+def find_sequences_after(context, sequence):
+ """
+ Finds the strips following the sequences passed to the function
+ Args:
+ - Sequences, the sequences to check
+ Returns all the strips after the sequence in the current context
+ """
+ return [s for s in context.sequences if s.frame_final_start > sequence.frame_final_start]
+
+
+def find_snap_candidate(context, frame=0):
+ """
+ Returns the cut frame closest to the `frame` argument
+ """
+ snap_candidate = 1000000
+
+ for s in context.sequences:
+ start_to_frame = frame - s.frame_final_start
+ end_to_frame = frame - s.frame_final_end
+
+ distance_to_start = abs(start_to_frame)
+ distance_to_end = abs(end_to_frame)
+
+ candidate = (
+ frame - start_to_frame
+ if min(distance_to_start, distance_to_end) == distance_to_start
+ else frame - end_to_frame
+ )
+
+ if abs(frame - candidate) < abs(frame - snap_candidate):
+ snap_candidate = candidate
+
+ return snap_candidate
+
+
+def find_strips_mouse(context, frame, channel, select_linked=False):
+ """
+ Finds a list of sequences to select based on the frame and channel the mouse cursor is at
+
+ Args:
+ - frame: the frame the mouse or cursor is on
+ - channel: the channel the mouse is hovering
+ - select_linked: find and append the sequences linked in time if True
+
+ Returns the sequence(s) under the mouse cursor as a list
+ Returns an empty list if nothing found
+ """
+ sequences = [
+ s
+ for s in context.sequences
+ if not s.lock and s.channel == channel and s.frame_final_start <= frame <= s.frame_final_end
+ ]
+ if select_linked:
+ linked_strips = [
+ s
+ for s in context.sequences
+ if s.frame_final_start == sequences[0].frame_final_start
+ and s.frame_final_end == sequences[0].frame_final_end
+ ]
+ sequences.extend(linked_strips)
+ return sequences
+
+
+def get_frame_range(context, sequences=[], get_from_start=False):
+ """
+ Returns a tuple with the minimum and maximum frames of the
+ list of passed sequences.
+ Args:
+ - sequences, the sequences to use
+ - get_from_start, the returned start frame is set to 1 if
+ this boolean is True
+ """
+ start, end = -1, -1
+ start = (
+ 1
+ if get_from_start
+ else min(sequences, key=attrgetter("frame_final_start")).frame_final_start
+ )
+ end = max(sequences, key=attrgetter("frame_final_end")).frame_final_end
+ return start, end
+
+
+def get_mouse_frame_and_channel(context, event):
+ """
+ Convert mouse coordinates from the event, from
+ pixels to frame, channel.
+ Returns a tuple of frame, channel as integers
+ """
+ view2d = context.region.view2d
+ frame, channel = view2d.region_to_view(event.mouse_region_x, event.mouse_region_y)
+ return round(frame), floor(channel)
+
+
+def is_in_range(context, sequence, start, end):
+ """
+ Checks if a single sequence's start or end is in the range
+
+ Args:
+ - sequence: the sequence to check for
+ - start, end: the start and end frames
+ Returns True if the sequence is within the range, False otherwise
+ """
+ s_start = sequence.frame_final_start
+ s_end = sequence.frame_final_end
+ return start <= s_start <= end or start <= s_end <= end
+
+
+def set_preview_range(context, start, end):
+ """Sets the preview range and timeline render range"""
+ if not (start and end) and start != 0:
+ raise AttributeError("Missing start or end parameter")
+
+ scene = context.scene
+
+ scene.frame_start = start
+ scene.frame_end = end
+ scene.frame_preview_start = start
+ scene.frame_preview_end = end
+
+
+def slice_selection(context, sequences):
+ """
+ Takes a list of sequences and breaks it down
+ into multiple lists of connected sequences
+
+ Returns a list of lists of sequences,
+ each list corresponding to a block of sequences
+ that are connected in time and sorted by frame_final_start
+ """
+ # Find when 2 sequences are not connected in time
+ if not sequences:
+ return []
+
+ break_ids = [0]
+ sorted_sequences = sorted(sequences, key=attrgetter("frame_final_start"))
+ last_sequence = sorted_sequences[0]
+ last_biggest_frame_end = last_sequence.frame_final_end
+ index = 0
+ for s in sorted_sequences:
+ if s.frame_final_start > last_biggest_frame_end + 1:
+ break_ids.append(index)
+ last_biggest_frame_end = max(last_biggest_frame_end, s.frame_final_end)
+ last_sequence = s
+ index += 1
+
+ # Create lists
+ break_ids.append(len(sorted_sequences))
+ cuts_count = len(break_ids) - 1
+ broken_selection = []
+ index = 0
+ while index < cuts_count:
+ temp_list = []
+ index_range = range(break_ids[index], break_ids[index + 1] - 1)
+ if len(index_range) == 0:
+ temp_list.append(sorted_sequences[break_ids[index]])
+ else:
+ for counter in range(break_ids[index], break_ids[index + 1]):
+ temp_list.append(sorted_sequences[counter])
+ if temp_list:
+ broken_selection.append(temp_list)
+ index += 1
+ return broken_selection
+
+
+def trim_strips(
+ context, start_frame, end_frame, select_mode, strips_to_trim=[], strips_to_delete=[]
+):
+ """
+ Remove the footage and audio between start_frame and end_frame.
+ """
+ trim_start = min(start_frame, end_frame)
+ trim_end = max(start_frame, end_frame)
+
+ strips_to_trim = [s for s in strips_to_trim if s.type in SequenceTypes.CUTABLE]
+
+ for s in strips_to_trim:
+ if s.frame_final_start < trim_start and s.frame_final_end > trim_end:
+ bpy.ops.sequencer.select_all(action="DESELECT")
+ s.select = True
+ bpy.ops.sequencer.cut(frame=trim_start, type="SOFT", side="RIGHT")
+ bpy.ops.sequencer.cut(frame=trim_end, type="SOFT", side="LEFT")
+ strips_to_delete.append(context.selected_sequences[0])
+ continue
+ elif s.frame_final_start < trim_end and s.frame_final_end > trim_end:
+ s.frame_final_start = trim_end
+ elif s.frame_final_end > trim_start and s.frame_final_start < trim_start:
+ s.frame_final_end = trim_start
+
+ if strips_to_delete != []:
+ bpy.ops.sequencer.select_all(action="DESELECT")
+ for s in strips_to_delete:
+ s.select = True
+ bpy.ops.sequencer.delete()
+ return {"FINISHED"}
+
+
+def find_closest_surrounding_cuts(context, frame):
+ """
+ Returns a tuple of (strip_before, strip_after), the two closest sequences around a gap.
+ If the frame is in the middle of a strip, both strips may be the same.
+ """
+ strip_before = max(
+ context.sequences,
+ key=lambda s: s.frame_final_end
+ if s.frame_final_end <= frame
+ else s.frame_final_start
+ if s.frame_final_start <= frame
+ else 0,
+ )
+ strip_after = min(
+ context.sequences,
+ key=lambda s: s.frame_final_start
+ if s.frame_final_start >= frame
+ else s.frame_final_end
+ if s.frame_final_end >= frame
+ else 1000000,
+ )
+ return strip_before, strip_after
+
+
+def find_closest_surrounding_cuts_frames(context, frame):
+ before, after = find_closest_surrounding_cuts(context, frame)
+ if before == after:
+ frame_left, frame_right = before.frame_final_start, before.frame_final_end
+ else:
+ frame_left, frame_right = before.frame_final_end, after.frame_final_start
+ return frame_left, frame_right
+
+
+def get_sequences_under_cursor(context):
+ frame = context.scene.frame_current
+ under_cursor = [
+ s
+ for s in context.sequences
+ if s.frame_final_start <= frame and s.frame_final_end >= frame and not s.lock
+ ]
+ return under_cursor
+
+
+def sequencer_workaround_2_80_audio_bug(context):
+ for s in context.sequences:
+ if s.lock:
+ continue
+ s.select = True
+ bpy.ops.transform.seq_slide(value=(0, 0))
+ s.select = False
+ break