Cleanup: quiet warnings with descriptions ending with a '.'
[blender-addons.git] / power_sequencer / operators / grab_closest_handle_or_cut.py
blob7a7a056d02a71fe2687909b234b69d31fe228311
1 # SPDX-License-Identifier: GPL-3.0-or-later
2 # Copyright (C) 2016-2020 by Nathan Lovato, Daniel Oakey, Razvan Radulescu, and contributors
3 """
4 Selects and grabs the strip handle or cut closest to the mouse cursor.
5 Hover near a cut and use this operator to slide it.
6 """
7 import bpy
9 from math import floor
11 from .utils.functions import calculate_distance
12 from .utils.doc import doc_name, doc_idname, doc_brief, doc_description
15 class POWER_SEQUENCER_OT_grab_closest_cut(bpy.types.Operator):
16 """
17 *brief* Grab the handles that form the closest cut
20 Selects and grabs the strip handle or cut closest to the mouse cursor.
21 Hover near a cut and fire this tool to slide it.
22 """
24 doc = {
25 "name": doc_name(__qualname__),
26 "demo": "",
27 "description": doc_description(__doc__),
28 "shortcuts": [
30 {"type": "G", "value": "PRESS", "shift": True, "alt": True},
31 {},
32 "Grab closest handle or cut",
35 "keymap": "Sequencer",
37 bl_idname = doc_idname(__qualname__)
38 bl_label = doc["name"]
39 bl_description = doc_brief(doc["description"])
40 bl_options = {"REGISTER", "UNDO"}
42 select_linked: bpy.props.BoolProperty(
43 name="Select Linked", description="Select strips that are linked in time", default=True
46 @classmethod
47 def poll(cls, context):
48 return context.sequences
50 def invoke(self, context, event):
51 sequencer = bpy.ops.sequencer
53 mouse_x, mouse_y = event.mouse_region_x, event.mouse_region_y
54 frame, channel = self.find_cut_closest_to_mouse(context, mouse_x, mouse_y)
56 matching_strips = [
58 for s in context.sequences
59 if (abs(s.frame_final_start - frame) <= 1 or abs(s.frame_final_end - frame) <= 1)
61 if not self.select_linked:
62 matching_strips = [s for s in matching_strips if s.channel == channel]
63 sequencer.select_all(action="DESELECT")
64 for s in matching_strips:
65 s.select = True
66 return bpy.ops.power_sequencer.grab_sequence_handles(frame=frame)
68 def find_cut_closest_to_mouse(self, context, mouse_x, mouse_y):
69 """
70 Takes the mouse's coordinates in the sequencer area and returns the two
71 strips who share the cut closest to the mouse. Use it to find the
72 handle(s) to select with the grab on the fly operator
73 """
74 view2d = context.region.view2d
76 closest_cut = (None, None)
77 distance_to_closest_cut = 1000000.0
79 for s in context.sequences:
80 channel_offset = s.channel + 0.5
81 start_x, start_y = view2d.view_to_region(s.frame_final_start, channel_offset)
82 end_x, end_y = view2d.view_to_region(s.frame_final_start, channel_offset)
84 distance_to_start = calculate_distance(start_x, start_y, mouse_x, mouse_y)
85 distance_to_end = calculate_distance(end_x, end_y, mouse_x, mouse_y)
87 if distance_to_start < distance_to_closest_cut:
88 closest_cut = (start_x, start_y)
89 distance_to_closest_cut = distance_to_start
90 if distance_to_end < distance_to_closest_cut:
91 closest_cut = (end_x, end_y)
92 distance_to_closest_cut = distance_to_end
94 closest_cut_local_coords = view2d.region_to_view(closest_cut[0], closest_cut[1])
95 frame, channel = (round(closest_cut_local_coords[0]), floor(closest_cut_local_coords[1]))
96 return frame, channel