diff options
author | Nathan Lovato <nathan@gdquest.com> | 2019-09-05 18:22:37 +0300 |
---|---|---|
committer | Nathan Lovato <nathan@gdquest.com> | 2019-09-05 18:22:52 +0300 |
commit | 61d48c0a4be0ab8f71e6e1d35f0aa99c77fcfd33 (patch) | |
tree | f64d0ea88789184f45112b489598990d549788f2 /power_sequencer/operators/select_related_strips.py | |
parent | da5a1175e30c347fbce05e49e2f5f895be30bd5b (diff) |
Add the VSE addon Power Sequencer
Diffstat (limited to 'power_sequencer/operators/select_related_strips.py')
-rw-r--r-- | power_sequencer/operators/select_related_strips.py | 140 |
1 files changed, 140 insertions, 0 deletions
diff --git a/power_sequencer/operators/select_related_strips.py b/power_sequencer/operators/select_related_strips.py new file mode 100644 index 00000000..30a8b24a --- /dev/null +++ b/power_sequencer/operators/select_related_strips.py @@ -0,0 +1,140 @@ +# +# 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 + +from .utils.global_settings import SequenceTypes +from .utils.doc import doc_name, doc_idname, doc_brief, doc_description + + +class POWER_SEQUENCER_OT_select_related_strips(bpy.types.Operator): + """ + *brief* Find and select all strips related to the selection + + + Find and select effects related to the selection, but also inputs of selected effects. + This helps to then copy or duplicate strips with all attached effects. + """ + + doc = { + "name": doc_name(__qualname__), + "demo": "", + "description": doc_description(__doc__), + "shortcuts": [], + "keymap": "Sequencer", + } + bl_idname = doc_idname(__qualname__) + bl_label = doc["name"] + bl_description = doc_brief(doc["description"]) + bl_options = {"REGISTER", "UNDO"} + + find_all: bpy.props.BoolProperty( + name="Find All", + description=( + "Find all related strips recursively so that you can copy the selection" + " without getting an error from Blender" + ), + default=True, + ) + + @classmethod + def poll(cls, context): + return context.selected_sequences + + def execute(self, context): + if self.find_all: + related_strips = set() + for s in context.selected_sequences: + self.find_neighbours_recursive(related_strips, s, context) + else: + related_strips = [] + # Only select direct neighbours and attached effects + effects = [s for s in context.sequences if s.type in SequenceTypes.EFFECT] + found_effects = self.find_related_effects(context.selected_sequences, effects) + related_strips.extend(found_effects) + while len(found_effects) > 0: + found_effects = self.find_related_effects(found_effects, effects) + related_strips.extend(found_effects) + for s in related_strips: + s.select = True + return {"FINISHED"} + + def find_neighbours_recursive(self, visited, strip, context): + """ + Performs a depth first search traversal to the graph of strips, to find + all related strips. + Args: + - visited: A set with all the strips that have been visited. + - strip: The strip to start the search from. + """ + visited.add(strip) + neighbours = self.find_neighbours(strip, context) + for s in neighbours: + if s not in visited: + self.find_neighbours_recursive(visited, s, context) + + def find_neighbours(self, strip, context): + """ + Strips and their effect strips define a graph, where each node is a + strip and edges are their connections. It finds all the neighbours of a + strip in the graph, and *sometimes neighbours of neighbours and so on*. + *In order to find the neighbours of a strip the + bpy.ops.transform.seq_slide operator is used, and usually finds many + levels of neighbours, but always finds the first level, which is needed, + the other levels are redundant, but are included for brevity reasons. + Args: + - strip: The strip to find all its neighbours. + Returns: A list with all the neighbours of the strip and sometimes + neighbours of neighbours and so on. + """ + # Respects initial selection + init_selected_strips = [s for s in context.selected_sequences] + + neighbours = [] + bpy.ops.sequencer.select_all(action="DESELECT") + strip.select = True + bpy.ops.transform.seq_slide(value=(0, 0)) + strip.select = False + for s in context.selected_sequences: + neighbours.append(s) + + try: + neighbours.append(strip.input_1) + neighbours.append(strip.input_2) + except Exception: + pass + + bpy.ops.sequencer.select_all(action="DESELECT") + for s in init_selected_strips: + s.select = True + + return neighbours + + def find_related_effects(self, sequences, effects): + found = [] + for s in sequences: + for e in effects: + try: + if e.input_1 == s: + found.append(e) + except Exception: + continue + try: + if e.input_2 == s: + found.append(e) + except Exception: + continue + return found |