feat: move audio editor selection with ctrl drag

This commit is contained in:
2026-07-04 21:41:35 +02:00
parent 443ba225cd
commit a1e90f135f
2 changed files with 84 additions and 2 deletions
+47 -2
View File
@@ -4101,6 +4101,8 @@ class AudioWaveform(QWidget):
self._playhead: float | None = None
self._markers: list[float] = []
self._drag_anchor: float | None = None
self._drag_mode: str | None = None
self._drag_orig_sel: tuple[float, float] | None = None
self._press_x: float | None = None
self.setFixedHeight(96)
self.setToolTip("Waveform of the current audio area (↻ to refresh)")
@@ -4153,6 +4155,8 @@ class AudioWaveform(QWidget):
self._playhead = None
self._markers = []
self._drag_anchor = None
self._drag_mode = None
self._drag_orig_sel = None
self._press_x = None
self.update()
@@ -4208,18 +4212,50 @@ class AudioWaveform(QWidget):
return self._sel[0] # drag end; pivot on start
return None
def _selection_contains_x(self, x: float) -> bool:
if self._sel is None or self._view_dur <= 0:
return False
xs = self._t_to_px(self._sel[0])
xe = self._t_to_px(self._sel[1])
return min(xs, xe) <= x <= max(xs, xe)
def _begin_move_at_x(self, x: float) -> None:
if self._sel is None:
return
self._drag_mode = "move"
self._drag_anchor = self._px_to_t(x)
self._drag_orig_sel = self._sel
def _begin_drag_at_x(self, x: float) -> None:
t = self._px_to_t(x)
anchor = self._selection_handle_anchor(x)
if anchor is None:
anchor = t
self._drag_mode = "select"
self._drag_anchor = anchor
self._drag_orig_sel = self._sel
self._drag_to_x(x)
def _drag_to_x(self, x: float) -> None:
if self._drag_anchor is None:
return
t = self._px_to_t(x)
if self._drag_mode == "move" and self._drag_orig_sel is not None:
s0, e0 = self._drag_orig_sel
width = e0 - s0
delta = t - self._drag_anchor
lo = s0 + delta
hi = e0 + delta
vs, ve = self._view_start, self._view_start + self._view_dur
if self._view_dur > 0:
if lo < vs:
lo = vs
hi = lo + width
if hi > ve:
hi = ve
lo = hi - width
self.set_selection(lo, hi)
return
lo, hi = min(self._drag_anchor, t), max(self._drag_anchor, t)
vs, ve = self._view_start, self._view_start + self._view_dur
if self._view_dur > 0:
@@ -4236,6 +4272,8 @@ class AudioWaveform(QWidget):
if self._drag_anchor is None:
return
self._drag_anchor = None
self._drag_mode = None
self._drag_orig_sel = None
if self._sel is not None:
self.selection_changed.emit(self._sel[0], self._sel[1])
@@ -4261,7 +4299,10 @@ class AudioWaveform(QWidget):
if e.button() == Qt.MouseButton.LeftButton:
x = e.position().x()
self._press_x = x
if self._selection_handle_anchor(x) is not None:
if (e.modifiers() & Qt.KeyboardModifier.ControlModifier
and self._selection_contains_x(x)):
self._begin_move_at_x(x)
elif self._selection_handle_anchor(x) is not None:
self._begin_drag_at_x(x)
def mouseMoveEvent(self, e):
@@ -4271,7 +4312,11 @@ class AudioWaveform(QWidget):
elif (e.buttons() & Qt.MouseButton.LeftButton
and self._press_x is not None
and abs(x - self._press_x) >= self.CLICK_DRAG_PX):
self._begin_drag_at_x(self._press_x)
if (e.modifiers() & Qt.KeyboardModifier.ControlModifier
and self._selection_contains_x(self._press_x)):
self._begin_move_at_x(self._press_x)
else:
self._begin_drag_at_x(self._press_x)
self._drag_to_x(x)
def mouseReleaseEvent(self, e):