Merge pull request #6052 from OpenShot/tilt-scroll-wheel

Allow mouse wheel tilt (left/right) to scroll timeline
This commit is contained in:
Jonathan Thomas
2026-05-24 13:03:24 -05:00
committed by GitHub
2 changed files with 49 additions and 6 deletions
+31 -5
View File
@@ -572,10 +572,14 @@ class TimelineHelperTests(unittest.TestCase):
return self.active
class DeltaStub:
def __init__(self, y=0.0, is_null=False):
def __init__(self, x=0.0, y=0.0, is_null=False):
self._x = float(x)
self._y = float(y)
self._is_null = bool(is_null)
def x(self):
return self._x
def y(self):
return self._y
@@ -602,13 +606,13 @@ class TimelineHelperTests(unittest.TestCase):
self.accepted = True
class WheelEventStub:
def __init__(self, delta, modifiers=Qt.ControlModifier, pixel_delta=None):
def __init__(self, delta, modifiers=Qt.ControlModifier, pixel_delta=None, x_delta=0.0):
self._modifiers = modifiers
self._angle_delta = DeltaStub(delta, is_null=False)
self._angle_delta = DeltaStub(x=x_delta, y=delta, is_null=False)
if pixel_delta is None:
self._pixel_delta = DeltaStub(0.0, is_null=True)
self._pixel_delta = DeltaStub(is_null=True)
else:
self._pixel_delta = DeltaStub(pixel_delta, is_null=False)
self._pixel_delta = DeltaStub(y=pixel_delta, is_null=False)
self.accepted = False
self.ignored = False
@@ -2895,6 +2899,28 @@ class TimelineHelperTests(unittest.TestCase):
self.assertAlmostEqual(helper.timeline_scrolled[0][1], 0.64)
self.assertEqual(helper.timeline_scrolled[0][2:], [400.0, 100.0])
def test_qwidget_tilt_wheel_scrolls_horizontally_without_shift(self):
helper, _event_cls, wheel_event_cls = self.make_qwidget_ctrl_zoom_helper()
event = wheel_event_cls(0.0, modifiers=Qt.NoModifier, x_delta=-120.0)
app = types.SimpleNamespace(
window=types.SimpleNamespace(
TimelineScrolled=types.SimpleNamespace(
emit=lambda positions: helper.timeline_scrolled.append(list(positions))
)
)
)
with patch.object(self.qwidget_base_module, "get_app", return_value=app):
self.qwidget_base_module.TimelineWidgetBase.wheelEvent(helper, event)
helper._hscroll_timer.active = False
self.qwidget_base_module.TimelineWidgetBase._flush_pending_horizontal_scroll(helper)
self.assertTrue(event.accepted)
self.assertFalse(event.ignored)
self.assertEqual(helper._hscroll_timer.started, 1)
self.assertAlmostEqual(helper.scrollbar_position[0], 0.24)
self.assertAlmostEqual(helper.scrollbar_position[1], 0.64)
def test_qwidget_set_zoom_factor_keeps_playhead_at_existing_viewport_ratio(self):
helper = types.SimpleNamespace()
helper.zoom_factor = 10.0
@@ -2033,9 +2033,26 @@ class TimelineWidgetBase(QWidget):
event.accept()
return
horizontal_delta = 0.0
pixel_delta = event.pixelDelta()
angle_delta = event.angleDelta()
if not pixel_delta.isNull():
horizontal_delta = pixel_delta.x()
if not horizontal_delta:
horizontal_delta = angle_delta.x()
if horizontal_delta and self.scrollbar_position[3] > 0 and self.scrollbar_position[2] > self.scrollbar_position[3]:
delta = -horizontal_delta / 120.0
self._pending_hscroll_delta += delta
if not self._hscroll_timer.isActive():
# Process accumulated wheel events once the event queue is flushed
self._hscroll_timer.start(0)
event.accept()
return
if event.modifiers() & Qt.ShiftModifier:
if self.scrollbar_position[3] > 0 and self.scrollbar_position[2] > self.scrollbar_position[3]:
delta = -event.angleDelta().y() / 120.0
delta = -angle_delta.y() / 120.0
if delta:
self._pending_hscroll_delta += delta
if not self._hscroll_timer.isActive():