feat: improve audio region timeline picking

This commit is contained in:
2026-07-04 20:16:08 +02:00
parent 678f6e5cc4
commit b52b3e19be
2 changed files with 100 additions and 13 deletions
+50 -13
View File
@@ -1897,7 +1897,7 @@ class TimelineWidget(QWidget):
_RULER_H = 22 # pixels reserved for the time ruler
_HANDLE_H = 8 # height of the playhead triangle
_EDGE_PX = 3 # pixel tolerance for edge hit detection
_AUDIO_EDGE_PX = 6 # pixel tolerance for audio-band edge grab
_AUDIO_EDGE_PX = 10 # pixel tolerance for audio-band edge grab
_AUDIO_MIN_W = 0.05 # seconds — min audio-band width
def __init__(self):
@@ -2109,22 +2109,38 @@ class TimelineWidget(QWidget):
self._audio_mode = bool(on)
self.update()
def _audio_hit_at_x(self, x: float) -> str | None:
if not self._audio_mode or self._audio_region is None:
return None
a0, a1 = self._audio_region
ax0 = self._time_to_x(a0)
ax1 = self._time_to_x(a1)
if abs(x - ax0) <= self._AUDIO_EDGE_PX:
return "left"
if abs(x - ax1) <= self._AUDIO_EDGE_PX:
return "right"
if ax0 < x < ax1:
return "move"
return "create"
def _audio_begin_drag_at_x(self, x: float) -> None:
if not self._audio_mode or self._audio_region is None:
return
hit = self._audio_hit_at_x(x)
a0, a1 = self._audio_region
ax0 = self._time_to_x(a0); ax1 = self._time_to_x(a1)
if abs(x - ax0) <= self._AUDIO_EDGE_PX:
self._audio_drag = "left"
elif abs(x - ax1) <= self._AUDIO_EDGE_PX:
self._audio_drag = "right"
elif ax0 < x < ax1:
self._audio_drag = "move"
self._audio_drag_anchor = self._pos_to_time(int(x)) - a0
else:
self._audio_drag = None
t = max(0.0, min(self._pos_to_time(int(x)), self._duration))
self._audio_drag = hit
self._audio_drag_orig = self._audio_region if hit is not None else None
if hit == "move":
self._audio_drag_anchor = t - a0
elif hit == "create":
self._audio_drag_anchor = t
width = max(self._AUDIO_MIN_W, a1 - a0)
a0 = max(0.0, min(t, max(0.0, self._duration - width)))
self._audio_region = (a0, a0 + width)
self.update()
if self._audio_drag is not None:
self._audio_drag_orig = self._audio_region
return
def _audio_drag_to_x(self, x: float) -> None:
if self._audio_drag is None or self._audio_region is None:
@@ -2135,10 +2151,19 @@ class TimelineWidget(QWidget):
a0 = min(t, a1 - self._AUDIO_MIN_W)
elif self._audio_drag == "right":
a1 = max(t, a0 + self._AUDIO_MIN_W)
else: # move
elif self._audio_drag == "move":
width = a1 - a0
a0 = max(0.0, min(t - self._audio_drag_anchor, self._duration - width))
a1 = a0 + width
else: # create
anchor = self._audio_drag_anchor
a0 = max(0.0, min(anchor, t))
a1 = min(self._duration, max(anchor, t))
if a1 - a0 < self._AUDIO_MIN_W:
if a1 + self._AUDIO_MIN_W <= self._duration:
a1 = a0 + self._AUDIO_MIN_W
else:
a0 = max(0.0, a1 - self._AUDIO_MIN_W)
self._audio_region = (a0, a1)
self.update()
@@ -2393,6 +2418,8 @@ class TimelineWidget(QWidget):
p.setPen(QPen(QColor(0, 220, 190), 2))
p.drawLine(ax1, rh, ax1, h)
p.drawLine(ax2, rh, ax2, h)
p.fillRect(ax1 - 4, rh, 8, th, QColor(0, 220, 190, 120))
p.fillRect(ax2 - 4, rh, 8, th, QColor(0, 220, 190, 120))
else:
p.setPen(QPen(QColor(0, 220, 190), 1, Qt.PenStyle.DashLine))
p.drawRect(ax1, rh + 1, aw, th - 2)
@@ -2700,6 +2727,16 @@ class TimelineWidget(QWidget):
mods = event.modifiers()
if (mods & Qt.KeyboardModifier.ShiftModifier) and self._hit_scan_edge(x):
self.setCursor(Qt.CursorShape.SizeHorCursor)
elif self._audio_mode and self._audio_region is not None:
hit = self._audio_hit_at_x(x)
if hit in ("left", "right"):
self.setCursor(Qt.CursorShape.SizeHorCursor)
elif hit == "move":
self.setCursor(Qt.CursorShape.OpenHandCursor)
elif hit == "create":
self.setCursor(Qt.CursorShape.CrossCursor)
else:
self.unsetCursor()
else:
self.unsetCursor()