From 94329b334acd14cf0839113c88676157bcec7982 Mon Sep 17 00:00:00 2001 From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com> Date: Thu, 31 Aug 2023 11:40:52 +0200 Subject: [PATCH] Forward all scroll events in editor/viewer areas to their text area widgets (#1425) --- novelwriter/extensions/wheeleventfilter.py | 65 ++++++++++++++++++++++ novelwriter/gui/doceditor.py | 5 ++ novelwriter/gui/docviewer.py | 5 ++ 3 files changed, 75 insertions(+) create mode 100644 novelwriter/extensions/wheeleventfilter.py diff --git a/novelwriter/extensions/wheeleventfilter.py b/novelwriter/extensions/wheeleventfilter.py new file mode 100644 index 00000000..75340cfa --- /dev/null +++ b/novelwriter/extensions/wheeleventfilter.py @@ -0,0 +1,65 @@ +""" +novelWriter – Custom Object: Wheel Event Filter +=============================================== + +File History: +Created: 2023-08-31 [2.1b2] + +This file is a part of novelWriter +Copyright 2018–2023, Veronica Berglyd Olsen + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +""" +from __future__ import annotations + +from PyQt5.QtGui import QWheelEvent +from PyQt5.QtCore import QEvent, QObject +from PyQt5.QtWidgets import QWidget + + +class WheelEventFilter(QObject): + """Extensions: Wheel Event Filter + + An event filter that filters mouse wheel events for a widget and + forward them to the root widget. This solves the lack of mouse wheel + scrolling response in margins of widgets like the editor and viewer. + + Solves: https://github.com/vkbo/novelWriter/issues/1425 + Reference: https://stackoverflow.com/a/17739995/5825851 + """ + + __slots__ = ("_parent", "_locked") + + def __init__(self, parent: QWidget) -> None: + super().__init__(parent=parent) + self._parent = parent + self._locked = False + return + + def eventFilter(self, object: QObject, event: QEvent) -> bool: + """Filter events of type QWheelEvent and forward them to the + parent widget's wheelEvent handler. + """ + if self._locked: + return False + if isinstance(event, QWheelEvent): + # Recursion protection may be redundant, but a comment on + # StackOverflow points to Qt 5.12 as the change, and we + # still support Qt 5.10 + self._locked = True + self._parent.wheelEvent(event) + self._locked = False + return False + +# END Class WheelEventFilter diff --git a/novelwriter/gui/doceditor.py b/novelwriter/gui/doceditor.py index 5d971ca6..c10765aa 100644 --- a/novelwriter/gui/doceditor.py +++ b/novelwriter/gui/doceditor.py @@ -55,6 +55,7 @@ from novelwriter.common import minmax, transferCase from novelwriter.constants import nwConst, nwKeyWords, nwUnicode from novelwriter.core.index import countWords from novelwriter.gui.dochighlight import GuiDocHighlighter +from novelwriter.extensions.wheeleventfilter import WheelEventFilter if TYPE_CHECKING: # pragma: no cover from novelwriter.guimain import GuiMain @@ -178,6 +179,10 @@ class GuiDocEditor(QTextEdit): self.wCounterSel.setAutoDelete(False) self.wCounterSel.signals.countsReady.connect(self._updateSelCounts) + # Install Event Filter for Mouse Wheel + self.wheelEventForwarder = WheelEventFilter(self) + self.installEventFilter(self.wheelEventForwarder) + # Finalise self.updateSyntaxColours() self.initEditor() diff --git a/novelwriter/gui/docviewer.py b/novelwriter/gui/docviewer.py index bbfb4c64..91992c00 100644 --- a/novelwriter/gui/docviewer.py +++ b/novelwriter/gui/docviewer.py @@ -47,6 +47,7 @@ from novelwriter.enum import nwItemType, nwDocAction, nwDocMode from novelwriter.error import logException from novelwriter.constants import nwUnicode from novelwriter.core.tohtml import ToHtml +from novelwriter.extensions.wheeleventfilter import WheelEventFilter if TYPE_CHECKING: # pragma: no cover from novelwriter.guimain import GuiMain @@ -85,6 +86,10 @@ class GuiDocViewer(QTextBrowser): # Signals self.anchorClicked.connect(self._linkClicked) + # Install Event Filter for Mouse Wheel + self.wheelEventForwarder = WheelEventFilter(self) + self.installEventFilter(self.wheelEventForwarder) + # Context Menu self.setContextMenuPolicy(Qt.CustomContextMenu) self.customContextMenuRequested.connect(self._openContextMenu)