79 lines
2.4 KiB
Python
79 lines
2.4 KiB
Python
# SPDX-FileCopyrightText: 2021 Blender Studio Tools Authors
|
|
#
|
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
from typing import Dict, List
|
|
|
|
import bpy
|
|
|
|
|
|
def _do_ranges_collide(range1: range, range2: range) -> bool:
|
|
"""Whether the two ranges collide with each other ."""
|
|
# Usual strip setup strip1(101, 120)|strip2(120, 130)|strip3(130, 140)
|
|
# first and last frame can be the same for each strip.
|
|
range2 = range(range2.start + 1, range2.stop - 1)
|
|
|
|
if not range1:
|
|
return True # Empty range is subset of anything.
|
|
|
|
if not range2:
|
|
return False # Non-empty range can't be subset of empty range.
|
|
|
|
if len(range1) > 1 and range1.step % range2.step:
|
|
return False # Must have a single value or integer multiple step.
|
|
|
|
if range(range1.start + 1, range1.stop - 1) == range2:
|
|
return True
|
|
|
|
if range2.start in range1 or range2[-1] in range1:
|
|
return True
|
|
|
|
return range1.start in range2 or range1[-1] in range2
|
|
|
|
|
|
def get_occupied_ranges(context: bpy.types.Context) -> Dict[str, List[range]]:
|
|
"""
|
|
Scans sequence editor and returns a dictionary. It contains a key for each channel
|
|
and a list of ranges with the occupied frame ranges as values.
|
|
"""
|
|
# {'1': [(101, 213), (300, 320)]}.
|
|
ranges: Dict[str, List[range]] = {}
|
|
|
|
# Populate ranges.
|
|
for strip in context.scene.sequence_editor.sequences_all:
|
|
ranges.setdefault(str(strip.channel), [])
|
|
ranges[str(strip.channel)].append(
|
|
range(strip.frame_final_start, strip.frame_final_end + 1)
|
|
)
|
|
|
|
# Sort ranges tuple list.
|
|
for channel in ranges:
|
|
liste = ranges[channel]
|
|
ranges[channel] = sorted(liste, key=lambda item: item.start)
|
|
|
|
return ranges
|
|
|
|
|
|
def get_occupied_ranges_for_strips(sequences: List["bpy.types.Strip"]) -> List[range]:
|
|
"""
|
|
Scans input list of sequences and returns a list of ranges that represent the occupied frame ranges.
|
|
"""
|
|
ranges: List[range] = []
|
|
|
|
# Populate ranges.
|
|
for strip in sequences:
|
|
ranges.append(range(strip.frame_final_start, strip.frame_final_end + 1))
|
|
|
|
# Sort ranges tuple list.
|
|
ranges.sort(key=lambda item: item.start)
|
|
return ranges
|
|
|
|
|
|
def is_range_occupied(range_to_check: range, occupied_ranges: List[range]) -> bool:
|
|
for r in occupied_ranges:
|
|
# Range(101, 150).
|
|
if _do_ranges_collide(range_to_check, r):
|
|
return True
|
|
continue
|
|
return False
|