diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index e31373e..bb00972 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -10,6 +10,9 @@ Added
clipboard in hex format (Images -> Sample Color)
* Added notification when attempting to paste from an empty or
unusable clipboard
+* Panning via scrollwheel:
+ * Scroll wheel without modifiers: pan vertically
+ * Scroll wheel + Shift: pan horizontally
Fixed
@@ -23,6 +26,13 @@ Fixed
would scale with the image and get potentially very thick.
+Changed
+-------
+
+* Using the scroll wheel will now only zoom when Ctrl is pressed,
+ instead of zooming all the time regardless of modifiers.
+
+
0.3.2 - 2024-01-21
==================
diff --git a/beeref/documentation/controls.html b/beeref/documentation/controls.html
index 0740be6..31e1f09 100644
--- a/beeref/documentation/controls.html
+++ b/beeref/documentation/controls.html
@@ -2,13 +2,15 @@
Middle Click + Drag
- Alt + Left Click + Drag
+ Alt + Left Click + Drag
+ Mouse Wheel (pan vertically)
+ Shift + Mouse wheel (pan horizontally)
Zoom Canvas
- Mouse wheel up/down
+ Ctrl + Mouse Wheel
Ctrl + Middle Click + Drag
diff --git a/beeref/view.py b/beeref/view.py
index e1d1d85..3dbdedc 100644
--- a/beeref/view.py
+++ b/beeref/view.py
@@ -748,8 +748,18 @@ class BeeGraphicsView(MainControlsMixin,
self.reset_previous_transform()
def wheelEvent(self, event):
- self.zoom(event.angleDelta().y(), event.position())
- event.accept()
+ if event.modifiers() == Qt.KeyboardModifier.ControlModifier:
+ self.zoom(event.angleDelta().y(), event.position())
+ event.accept()
+ return
+ if event.modifiers() == Qt.KeyboardModifier.NoModifier:
+ self.pan(QtCore.QPointF(0, 0.5 * event.angleDelta().y()))
+ event.accept()
+ return
+ if event.modifiers() == Qt.KeyboardModifier.ShiftModifier:
+ self.pan(QtCore.QPointF(0.5 * event.angleDelta().y(), 0))
+ event.accept()
+ return
def mousePressEvent(self, event):
if self.mousePressEventMainControls(event):
diff --git a/tests/test_view.py b/tests/test_view.py
index edb4c51..490809b 100644
--- a/tests/test_view.py
+++ b/tests/test_view.py
@@ -930,15 +930,38 @@ def test_delta_zero(pan_mock, reset_mock, view, item):
@patch('beeref.view.BeeGraphicsView.zoom')
-def test_wheel_event(zoom_mock, view):
+def test_wheel_event_zoom(zoom_mock, view):
event = MagicMock()
event.angleDelta.return_value = QtCore.QPointF(0.0, 40.0)
event.position.return_value = QtCore.QPointF(10.0, 20.0)
+ event.modifiers.return_value = Qt.KeyboardModifier.ControlModifier
view.wheelEvent(event)
zoom_mock.assert_called_once_with(40, QtCore.QPointF(10.0, 20.0))
event.accept.assert_called_once_with()
+@patch('beeref.view.BeeGraphicsView.pan')
+def test_wheel_event_pan_vertically(pan_mock, view):
+ event = MagicMock()
+ event.angleDelta.return_value = QtCore.QPointF(0.0, 40.0)
+ event.position.return_value = QtCore.QPointF(10.0, 20.0)
+ event.modifiers.return_value = Qt.KeyboardModifier.NoModifier
+ view.wheelEvent(event)
+ pan_mock.assert_called_once_with(QtCore.QPointF(0, 20))
+ event.accept.assert_called_once_with()
+
+
+@patch('beeref.view.BeeGraphicsView.pan')
+def test_wheel_event_pan_horizontally(pan_mock, view):
+ event = MagicMock()
+ event.angleDelta.return_value = QtCore.QPointF(0.0, 40.0)
+ event.position.return_value = QtCore.QPointF(10.0, 20.0)
+ event.modifiers.return_value = Qt.KeyboardModifier.ShiftModifier
+ view.wheelEvent(event)
+ pan_mock.assert_called_once_with(QtCore.QPointF(20, 0))
+ event.accept.assert_called_once_with()
+
+
@patch('PyQt6.QtWidgets.QGraphicsView.mousePressEvent')
def test_mouse_press_zoom(mouse_event_mock, view):
event = MagicMock()