1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
|
# 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
|