Tweak project toolbar look, and fix shortcuts

This commit is contained in:
Veronica Berglyd Olsen
2022-06-07 22:38:02 +02:00
parent 5a6ef5efd3
commit ef270bc069
2 changed files with 79 additions and 95 deletions
+79 -86
View File
@@ -33,11 +33,11 @@ from enum import Enum
from time import time from time import time
from PyQt5.QtCore import Qt, QSize, pyqtSignal, pyqtSlot from PyQt5.QtCore import Qt, QSize, pyqtSignal, pyqtSlot
from PyQt5.QtGui import QIcon from PyQt5.QtGui import QIcon, QPalette
from PyQt5.QtWidgets import ( from PyQt5.QtWidgets import (
qApp, QTreeWidget, QTreeWidgetItem, QAbstractItemView, QMenu, QAction, qApp, QTreeWidget, QTreeWidgetItem, QAbstractItemView, QMenu, QAction,
QFrame, QDialog, QHeaderView, QWidget, QVBoxLayout, QToolBar, QLabel, QFrame, QDialog, QHeaderView, QWidget, QVBoxLayout, QLabel, QToolButton,
QToolButton, QSizePolicy, QInputDialog QSizePolicy, QInputDialog, QHBoxLayout, QShortcut
) )
from novelwriter.core import NWDoc from novelwriter.core import NWDoc
@@ -75,13 +75,24 @@ class GuiProjectView(QWidget):
# Assemble # Assemble
self.outerBox = QVBoxLayout() self.outerBox = QVBoxLayout()
self.outerBox.addWidget(self.projBar) self.outerBox.addWidget(self.projBar, 0)
self.outerBox.addWidget(self.projTree) self.outerBox.addWidget(self.projTree, 1)
self.outerBox.setContentsMargins(0, 0, 0, 0) self.outerBox.setContentsMargins(0, 0, 0, 0)
self.outerBox.setSpacing(0) self.outerBox.setSpacing(0)
self.setLayout(self.outerBox) self.setLayout(self.outerBox)
# Keyboard Shortcuts
self.keyCtrlUp = QShortcut(self.projTree)
self.keyCtrlUp.setKey("Ctrl+Up")
self.keyCtrlUp.setContext(Qt.WidgetShortcut)
self.keyCtrlUp.activated.connect(lambda: self.projTree.moveTreeItem(-1))
self.keyCtrlDown = QShortcut(self.projTree)
self.keyCtrlDown.setKey("Ctrl+Down")
self.keyCtrlDown.setContext(Qt.WidgetShortcut)
self.keyCtrlDown.activated.connect(lambda: self.projTree.moveTreeItem(1))
# Connect Signals # Connect Signals
# Function Mappings # Function Mappings
@@ -155,7 +166,7 @@ class GuiProjectView(QWidget):
# END Class GuiProjectView # END Class GuiProjectView
class GuiProjectToolBar(QToolBar): class GuiProjectToolBar(QWidget):
ADD_PLAIN = 0 ADD_PLAIN = 0
ADD_CHAP = 1 ADD_CHAP = 1
@@ -163,42 +174,52 @@ class GuiProjectToolBar(QToolBar):
ADD_NOTE = 3 ADD_NOTE = 3
ADD_FOLDER = 4 ADD_FOLDER = 4
def __init__(self, theWidget): def __init__(self, projView):
QTreeWidget.__init__(self, theWidget) QTreeWidget.__init__(self, projView)
logger.debug("Initialising GuiProjectToolBar ...") logger.debug("Initialising GuiProjectToolBar ...")
self.mainConf = novelwriter.CONFIG self.mainConf = novelwriter.CONFIG
self.theWidget = theWidget self.projView = projView
self.theParent = theWidget.theParent self.theParent = projView.theParent
self.theProject = theWidget.theParent.theProject self.theProject = projView.theParent.theProject
self.theTheme = theWidget.theParent.theTheme self.theTheme = projView.theParent.theTheme
iPx = self.theTheme.baseIconSize iPx = self.theTheme.baseIconSize
mPx = self.mainConf.pxInt(12) mPx = self.mainConf.pxInt(4)
self.setMovable(False)
self.setIconSize(QSize(iPx, iPx))
self.setContentsMargins(0, 0, 0, 0) self.setContentsMargins(0, 0, 0, 0)
self.setStyleSheet("QToolBar {border: 0px;}") self.setAutoFillBackground(True)
qPalette = self.palette()
qPalette.setBrush(QPalette.Window, qPalette.base())
self.setPalette(qPalette)
fadeCol = qPalette.text().color()
buttonStyle = (
"QToolButton {{border: none; background: transparent;}} "
"QToolButton:hover {{border: none; background: rgba({0},{1},{2},0.2);}}"
).format(fadeCol.red(), fadeCol.green(), fadeCol.blue())
# Tree Label # Tree Label
self.projLabel = QLabel("<b>%s</b>" % self.tr("Project Content")) self.projLabel = QLabel("<b>%s</b>" % self.tr("Project Content"))
self.projLabel.setContentsMargins(0, 0, mPx, 0) self.projLabel.setContentsMargins(0, 0, 0, 0)
self.projLabel.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.projLabel.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
# Move Buttons # Move Buttons
self.tbMoveU = QToolButton(self) self.tbMoveU = QToolButton(self)
self.tbMoveU.setToolTip("%s [Ctrl+Up]" % self.tr("Move Up")) self.tbMoveU.setToolTip("%s [Ctrl+Up]" % self.tr("Move Up"))
self.tbMoveU.setShortcut("Ctrl+Up")
self.tbMoveU.setIcon(self.theTheme.getIcon("up")) self.tbMoveU.setIcon(self.theTheme.getIcon("up"))
self.tbMoveU.clicked.connect(lambda: self._forwardMoveItem(-1)) self.tbMoveU.setIconSize(QSize(iPx, iPx))
self.tbMoveU.setStyleSheet(buttonStyle)
self.tbMoveU.clicked.connect(lambda: self.projView.projTree.moveTreeItem(-1))
self.tbMoveD = QToolButton(self) self.tbMoveD = QToolButton(self)
self.tbMoveD.setToolTip("%s [Ctrl+Down]" % self.tr("Move Down")) self.tbMoveD.setToolTip("%s [Ctrl+Down]" % self.tr("Move Down"))
self.tbMoveD.setShortcut("Ctrl+Down")
self.tbMoveD.setIcon(self.theTheme.getIcon("down")) self.tbMoveD.setIcon(self.theTheme.getIcon("down"))
self.tbMoveD.clicked.connect(lambda: self._forwardMoveItem(1)) self.tbMoveD.setIconSize(QSize(iPx, iPx))
self.tbMoveD.setStyleSheet(buttonStyle)
self.tbMoveD.clicked.connect(lambda: self.projView.projTree.moveTreeItem(1))
# Items Menu # Items Menu
self.mItems = QMenu() self.mItems = QMenu()
@@ -239,21 +260,29 @@ class GuiProjectToolBar(QToolBar):
self.tbItems.setToolTip("%s [Ctrl+N]" % self.tr("Add Item")) self.tbItems.setToolTip("%s [Ctrl+N]" % self.tr("Add Item"))
self.tbItems.setShortcut("Ctrl+N") self.tbItems.setShortcut("Ctrl+N")
self.tbItems.setIcon(self.theTheme.getIcon("add")) self.tbItems.setIcon(self.theTheme.getIcon("add"))
self.tbItems.setIconSize(QSize(iPx, iPx))
self.tbItems.setStyleSheet(buttonStyle)
self.tbItems.setMenu(self.mItems) self.tbItems.setMenu(self.mItems)
self.tbItems.setPopupMode(QToolButton.InstantPopup) self.tbItems.setPopupMode(QToolButton.InstantPopup)
# Settings Menu # Settings Menu
self.tbSettings = QToolButton(self) self.tbSettings = QToolButton(self)
self.tbSettings.setIcon(self.theTheme.getIcon("menu")) self.tbSettings.setIcon(self.theTheme.getIcon("menu"))
self.tbSettings.setIconSize(QSize(iPx, iPx))
self.tbSettings.setStyleSheet(buttonStyle)
self.tbSettings.setPopupMode(QToolButton.InstantPopup) self.tbSettings.setPopupMode(QToolButton.InstantPopup)
# Assemble # Assemble
self.addWidget(self.projLabel) self.outerBox = QHBoxLayout()
self.addSeparator() self.outerBox.addWidget(self.projLabel)
self.addWidget(self.tbMoveU) self.outerBox.addWidget(self.tbMoveU)
self.addWidget(self.tbMoveD) self.outerBox.addWidget(self.tbMoveD)
self.addWidget(self.tbItems) self.outerBox.addWidget(self.tbItems)
self.addWidget(self.tbSettings) self.outerBox.addWidget(self.tbSettings)
self.outerBox.setContentsMargins(mPx, mPx, 0, mPx)
self.outerBox.setSpacing(mPx)
self.setLayout(self.outerBox)
logger.debug("GuiProjectToolBar initialisation complete") logger.debug("GuiProjectToolBar initialisation complete")
@@ -267,7 +296,7 @@ class GuiProjectToolBar(QToolBar):
def _forwardNewRootFolder(self, itemClass): def _forwardNewRootFolder(self, itemClass):
"""Forward the request for a new root folder to the tree. """Forward the request for a new root folder to the tree.
""" """
self.theWidget.projTree.newTreeItem(nwItemType.ROOT, itemClass) self.projView.projTree.newTreeItem(nwItemType.ROOT, itemClass)
return return
@pyqtSlot(int) @pyqtSlot(int)
@@ -275,22 +304,15 @@ class GuiProjectToolBar(QToolBar):
"""Forward the request for a new item of a given type. """Forward the request for a new item of a given type.
""" """
if type == self.ADD_PLAIN: if type == self.ADD_PLAIN:
self.theWidget.projTree.newTreeItem(nwItemType.FILE, hLevel=0, isNote=False) self.projView.projTree.newTreeItem(nwItemType.FILE, hLevel=0, isNote=False)
elif type == self.ADD_CHAP: elif type == self.ADD_CHAP:
self.theWidget.projTree.newTreeItem(nwItemType.FILE, hLevel=2, isNote=False) self.projView.projTree.newTreeItem(nwItemType.FILE, hLevel=2, isNote=False)
elif type == self.ADD_SCENE: elif type == self.ADD_SCENE:
self.theWidget.projTree.newTreeItem(nwItemType.FILE, hLevel=3, isNote=False) self.projView.projTree.newTreeItem(nwItemType.FILE, hLevel=3, isNote=False)
elif type == self.ADD_NOTE: elif type == self.ADD_NOTE:
self.theWidget.projTree.newTreeItem(nwItemType.FILE, hLevel=1, isNote=True) self.projView.projTree.newTreeItem(nwItemType.FILE, hLevel=1, isNote=True)
elif type == self.ADD_FOLDER: elif type == self.ADD_FOLDER:
self.theWidget.projTree.newTreeItem(nwItemType.FOLDER) self.projView.projTree.newTreeItem(nwItemType.FOLDER)
return
@pyqtSlot(int)
def _forwardMoveItem(self, steps):
"""Forward the request to move an item up or down.
"""
self.theWidget.projTree.moveTreeItem(steps)
return return
## ##
@@ -315,16 +337,16 @@ class GuiProjectTree(QTreeWidget):
C_EXPORT = 2 C_EXPORT = 2
C_STATUS = 3 C_STATUS = 3
def __init__(self, theWidget): def __init__(self, projView):
QTreeWidget.__init__(self, theWidget) QTreeWidget.__init__(self, projView)
logger.debug("Initialising GuiProjectTree ...") logger.debug("Initialising GuiProjectTree ...")
self.mainConf = novelwriter.CONFIG self.mainConf = novelwriter.CONFIG
self.theWidget = theWidget self.projView = projView
self.theParent = theWidget.theParent self.theParent = projView.theParent
self.theTheme = theWidget.theParent.theTheme self.theTheme = projView.theParent.theTheme
self.theProject = theWidget.theParent.theProject self.theProject = projView.theParent.theProject
# Internal Variables # Internal Variables
self._treeMap = {} self._treeMap = {}
@@ -496,7 +518,7 @@ class GuiProjectTree(QTreeWidget):
# If successful, update word count # If successful, update word count
wC = self.theProject.index.getCounts(tHandle)[1] wC = self.theProject.index.getCounts(tHandle)[1]
self.propagateCount(tHandle, wC) self.propagateCount(tHandle, wC)
self.theWidget.wordCountsChanged.emit() self.projView.wordCountsChanged.emit()
# Add the new item to the project tree # Add the new item to the project tree
self.revealNewTreeItem(tHandle, nHandle) self.revealNewTreeItem(tHandle, nHandle)
@@ -525,19 +547,12 @@ class GuiProjectTree(QTreeWidget):
return True return True
def moveTreeItem(self, nStep): def moveTreeItem(self, nStep):
"""Move an item up or down in the tree, but only if the project """Move an item up or down in the tree.
tree has focus. This also applies when the menu is used.
""" """
if not self.theParent.hasProject:
logger.error("No project open")
return False
if not self.theWidget.anyFocus():
return False
tHandle = self.getSelectedHandle() tHandle = self.getSelectedHandle()
tItem = self._getTreeItem(tHandle) tItem = self._getTreeItem(tHandle)
if tItem is None: if tItem is None:
logger.verbose("No item selected")
return False return False
pItem = tItem.parent() pItem = tItem.parent()
@@ -745,7 +760,7 @@ class GuiProjectTree(QTreeWidget):
self._deleteTreeItem(dHandle) self._deleteTreeItem(dHandle)
self._alertTreeChange(tHandle=tHandle, flush=autoFlush) self._alertTreeChange(tHandle=tHandle, flush=autoFlush)
self.theWidget.wordCountsChanged.emit() self.projView.wordCountsChanged.emit()
else: else:
# The item is not already in the trash folder, so we # The item is not already in the trash folder, so we
@@ -871,7 +886,7 @@ class GuiProjectTree(QTreeWidget):
dstItem = self._lastMove.get("parent", None) dstItem = self._lastMove.get("parent", None)
dstIndex = self._lastMove.get("index", None) dstIndex = self._lastMove.get("index", None)
if not self.theWidget.anyFocus(): if not self.projView.anyFocus():
return False return False
if srcItem is None or dstItem is None or dstIndex is None: if srcItem is None or dstItem is None or dstIndex is None:
@@ -951,7 +966,7 @@ class GuiProjectTree(QTreeWidget):
""" """
tHandle = self.getSelectedHandle() tHandle = self.getSelectedHandle()
if tHandle is not None: if tHandle is not None:
self.theWidget.selectedItemChanged.emit(tHandle) self.projView.selectedItemChanged.emit(tHandle)
return return
@pyqtSlot("QTreeWidgetItem*", int) @pyqtSlot("QTreeWidgetItem*", int)
@@ -968,7 +983,7 @@ class GuiProjectTree(QTreeWidget):
return return
if tItem.itemType == nwItemType.FILE: if tItem.itemType == nwItemType.FILE:
self.theWidget.openDocumentRequest.emit(tHandle, nwDocMode.EDIT) self.projView.openDocumentRequest.emit(tHandle, nwDocMode.EDIT)
else: else:
trItem = self._getTreeItem(tHandle) trItem = self._getTreeItem(tHandle)
if trItem is not None: if trItem is not None:
@@ -1020,7 +1035,7 @@ class GuiProjectTree(QTreeWidget):
return return
if tItem.itemType == nwItemType.FILE: if tItem.itemType == nwItemType.FILE:
self.theWidget.openDocumentRequest.emit(tHandle, nwDocMode.VIEW) self.projView.openDocumentRequest.emit(tHandle, nwDocMode.VIEW)
return return
@@ -1227,11 +1242,11 @@ class GuiProjectTree(QTreeWidget):
itemType = tItem.itemType itemType = tItem.itemType
if itemType == nwItemType.ROOT: if itemType == nwItemType.ROOT:
self.theWidget.rootFolderChanged.emit(tHandle) self.projView.rootFolderChanged.emit(tHandle)
elif itemType == nwItemType.FILE and tItem.isNovelLike(): elif itemType == nwItemType.FILE and tItem.isNovelLike():
self.theWidget.novelItemChanged.emit(tHandle) self.projView.novelItemChanged.emit(tHandle)
self.theWidget.treeItemChanged.emit(tHandle) self.projView.treeItemChanged.emit(tHandle)
return return
@@ -1283,14 +1298,6 @@ class GuiProjectTreeMenu(QMenu):
self.emptyTrash.triggered.connect(self._doEmptyTrash) self.emptyTrash.triggered.connect(self._doEmptyTrash)
self.addAction(self.emptyTrash) self.addAction(self.emptyTrash)
self.moveUp = QAction(self.tr("Move Item Up"), self)
self.moveUp.triggered.connect(self._doMoveUp)
self.addAction(self.moveUp)
self.moveDown = QAction(self.tr("Move Item Down"), self)
self.moveDown.triggered.connect(self._doMoveDown)
self.addAction(self.moveDown)
return return
def filterActions(self, theItem): def filterActions(self, theItem):
@@ -1369,18 +1376,4 @@ class GuiProjectTreeMenu(QMenu):
self.theTree.emptyTrash() self.theTree.emptyTrash()
return return
@pyqtSlot()
def _doMoveUp(self):
"""Forward the move item call to the project tree.
"""
self.theTree.moveTreeItem(-1)
return
@pyqtSlot()
def _doMoveDown(self):
"""Forward the move item call to the project tree.
"""
self.theTree.moveTreeItem(1)
return
# END Class GuiProjectTreeMenu # END Class GuiProjectTreeMenu
-9
View File
@@ -187,15 +187,6 @@ def testGuiProjTree_MoveItems(qtbot, monkeypatch, nwGUI, fncDir, mockRnd):
"0000000000010", "0000000000011", "0000000000012", "0000000000010", "0000000000011", "0000000000012",
] ]
# Move item without focus
with monkeypatch.context() as mp:
mp.setattr(GuiProjectView, "anyFocus", lambda *a: False)
assert nwTree.projTree.moveTreeItem(1) is False
assert nwTree.getTreeFromHandle("000000000000d") == [
"000000000000d", "000000000000e", "000000000000f",
"0000000000010", "0000000000011", "0000000000012",
]
# Move with no selections # Move with no selections
nwTree.projTree.clearSelection() nwTree.projTree.clearSelection()
assert nwTree.projTree.moveTreeItem(1) is False assert nwTree.projTree.moveTreeItem(1) is False