Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add autoscroll feature #1571

Merged
merged 3 commits into from
Nov 4, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 39 additions & 3 deletions novelwriter/gui/projtree.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@
from time import time
from typing import TYPE_CHECKING

from PyQt5.QtGui import QDropEvent, QMouseEvent, QPalette
from PyQt5.QtCore import QPoint, Qt, QSize, pyqtSignal, pyqtSlot
from PyQt5.QtGui import QDragMoveEvent, QDropEvent, QMouseEvent, QPalette
from PyQt5.QtCore import QPoint, QTimer, Qt, QSize, pyqtSignal, pyqtSlot
from PyQt5.QtWidgets import (
QAbstractItemView, QDialog, QFrame, QHBoxLayout, QHeaderView, QLabel,
QMenu, QShortcut, QSizePolicy, QToolButton, QTreeWidget, QTreeWidgetItem,
Expand Down Expand Up @@ -509,9 +509,13 @@ def __init__(self, projView: GuiProjectView) -> None:
self.setDragDropMode(QAbstractItemView.InternalMove)
self.setDropIndicatorShown(True)

# Disable built-in autoscroll as it isn't working in some Qt
# releases (see #1561) and instead use our own implementation
self.setAutoScroll(False)

# But don't allow drop on root level
# Due to a bug, this stops working somewhere between Qt 5.15.3
# and 5.15.8, so this is also blocked in dropEvent
# and 5.15.8, so this is also blocked in dropEvent (see #1569)
trRoot = self.invisibleRootItem()
trRoot.setFlags(trRoot.flags() ^ Qt.ItemIsDropEnabled)

Expand All @@ -527,6 +531,13 @@ def __init__(self, projView: GuiProjectView) -> None:
self.itemDoubleClicked.connect(self._treeDoubleClick)
self.itemSelectionChanged.connect(self._treeSelectionChange)

# Autoscroll
self._scrollMargin = SHARED.theme.baseIconSize
self._scrollDirection = 0
self._scrollTimer = QTimer()
self._scrollTimer.timeout.connect(self._doAutoScroll)
self._scrollTimer.setInterval(250)

# Set custom settings
self.initSettings()

Expand Down Expand Up @@ -1346,6 +1357,17 @@ def _openContextMenu(self, clickPos: QPoint) -> bool:

return True

@pyqtSlot()
def _doAutoScroll(self) -> None:
"""Scroll one item up or down based on direction value."""
if self._scrollDirection == -1:
self.scrollToItem(self.itemAbove(self.itemAt(1, 1)))
elif self._scrollDirection == 1:
self.scrollToItem(self.itemBelow(self.itemAt(1, self.height() - 1)))
self._scrollDirection = 0
self._scrollTimer.stop()
return

##
# Events
##
Expand Down Expand Up @@ -1377,6 +1399,20 @@ def mousePressEvent(self, event: QMouseEvent) -> None:

return

def dragMoveEvent(self, event: QDragMoveEvent) -> None:
"""Capture the drag move event to enable edge autoscroll."""
y = event.pos().y()
if y < self._scrollMargin:
if not self._scrollTimer.isActive():
self._scrollDirection = -1
self._scrollTimer.start()
elif y > self.height() - self._scrollMargin:
if not self._scrollTimer.isActive():
self._scrollDirection = 1
self._scrollTimer.start()
super().dragMoveEvent(event)
return

def dropEvent(self, event: QDropEvent) -> None:
"""Overload the drop item event to ensure relevant data has been
updated.
Expand Down