# SPDX-License-Identifier: GPL-3.0-or-later # Copyright (C) 2016-2020 by Nathan Lovato, Daniel Oakey, Razvan Radulescu, and contributors """ Selects and grabs the strip handle or cut closest to the mouse cursor. Hover near a cut and use this operator to slide it. """ import bpy from math import floor from .utils.functions import calculate_distance from .utils.doc import doc_name, doc_idname, doc_brief, doc_description class POWER_SEQUENCER_OT_grab_closest_cut(bpy.types.Operator): """ *brief* Grab the handles that form the closest cut Selects and grabs the strip handle or cut closest to the mouse cursor. Hover near a cut and fire this tool to slide it. """ doc = { "name": doc_name(__qualname__), "demo": "", "description": doc_description(__doc__), "shortcuts": [ ( {"type": "G", "value": "PRESS", "shift": True, "alt": True}, {}, "Grab closest handle or cut", ) ], "keymap": "Sequencer", } bl_idname = doc_idname(__qualname__) bl_label = doc["name"] bl_description = doc_brief(doc["description"]) bl_options = {"REGISTER", "UNDO"} select_linked: bpy.props.BoolProperty( name="Select Linked", description="Select strips that are linked in time", default=True ) @classmethod def poll(cls, context): return context.sequences def invoke(self, context, event): sequencer = bpy.ops.sequencer mouse_x, mouse_y = event.mouse_region_x, event.mouse_region_y frame, channel = self.find_cut_closest_to_mouse(context, mouse_x, mouse_y) matching_strips = [ s for s in context.sequences if (abs(s.frame_final_start - frame) <= 1 or abs(s.frame_final_end - frame) <= 1) ] if not self.select_linked: matching_strips = [s for s in matching_strips if s.channel == channel] sequencer.select_all(action="DESELECT") for s in matching_strips: s.select = True return bpy.ops.power_sequencer.grab_sequence_handles(frame=frame) def find_cut_closest_to_mouse(self, context, mouse_x, mouse_y): """ Takes the mouse's coordinates in the sequencer area and returns the two strips who share the cut closest to the mouse. Use it to find the handle(s) to select with the grab on the fly operator """ view2d = context.region.view2d closest_cut = (None, None) distance_to_closest_cut = 1000000.0 for s in context.sequences: channel_offset = s.channel + 0.5 start_x, start_y = view2d.view_to_region(s.frame_final_start, channel_offset) end_x, end_y = view2d.view_to_region(s.frame_final_start, channel_offset) distance_to_start = calculate_distance(start_x, start_y, mouse_x, mouse_y) distance_to_end = calculate_distance(end_x, end_y, mouse_x, mouse_y) if distance_to_start < distance_to_closest_cut: closest_cut = (start_x, start_y) distance_to_closest_cut = distance_to_start if distance_to_end < distance_to_closest_cut: closest_cut = (end_x, end_y) distance_to_closest_cut = distance_to_end closest_cut_local_coords = view2d.region_to_view(closest_cut[0], closest_cut[1]) frame, channel = (round(closest_cut_local_coords[0]), floor(closest_cut_local_coords[1])) return frame, channel