diff --git a/docs/source/usage_shortcuts.rst b/docs/source/usage_shortcuts.rst index 4e931351..db9382cb 100644 --- a/docs/source/usage_shortcuts.rst +++ b/docs/source/usage_shortcuts.rst @@ -25,19 +25,19 @@ Main Window Shortcuts ":kbd:`F8`", "Toggle :guilabel:`Focus Mode`" ":kbd:`F9`", "Re-build the project index" ":kbd:`F11`", "Toggle full screen mode" - ":kbd:`Alt+1`", "Switch focus to the project tree (Windows :kbd:`Ctrl+Alt+1`)" - ":kbd:`Alt+2`", "Switch focus to document editor (Windows :kbd:`Ctrl+Alt+2`)" - ":kbd:`Alt+3`", "Switch focus to document viewer (Windows :kbd:`Ctrl+Alt+3`)" - ":kbd:`Alt+4`", "Switch focus to outline view (Windows :kbd:`Ctrl+Alt+4`)" ":kbd:`Ctrl+,`", "Open the :guilabel:`Preferences` dialog" + ":kbd:`Ctrl+E`", "Switch focus to the document editor" + ":kbd:`Ctrl+T`", "Switch focus to the project/novel tree" ":kbd:`Ctrl+Q`", "Exit novelWriter" ":kbd:`Ctrl+Shift+,`", "Open the :guilabel:`Project Settings` dialog" ":kbd:`Ctrl+Shift+O`", "Open a project" ":kbd:`Ctrl+Shift+S`", "Save the current project" + ":kbd:`Ctrl+Shift+T`", "Switch focus to the outline view" ":kbd:`Ctrl+Shift+W`", "Close the current project" ":kbd:`Shift+F1`", "Open the local user manual (PDF) if it is available" ":kbd:`Shift+F6`", "Open the :guilabel:`Project Details` dialog" + .. _a_kb_tree: Project Tree Shortcuts @@ -46,21 +46,21 @@ Project Tree Shortcuts .. csv-table:: :header: "Shortcut", "Description" - ":kbd:`F2`", "Edit the label of the selected item" - ":kbd:`Return`", "Open the selected document in the editor" - ":kbd:`Alt+Up`", "Jump or go to the previous item at same level in the tree" - ":kbd:`Alt+Down`", "Jump or go to the next item at same level in the tree" - ":kbd:`Alt+Left`", "Jump to the parent item in the tree" - ":kbd:`Alt+Right`", "Jump to the first child item in the project tree" - ":kbd:`Ctrl+.`", "Open the context menu on the selected item" - ":kbd:`Ctrl+L`", "Open the :guilabel:`Quick Links` menu" - ":kbd:`Ctrl+N`", "Open the :guilabel:`Create New Item` menu" - ":kbd:`Ctrl+O`", "Open selected document" - ":kbd:`Ctrl+R`", "Open the selected document in the viewer" - ":kbd:`Ctrl+Up`", "Move selected item one step up in the tree" - ":kbd:`Ctrl+Down`", "Move selected item one step down in the tree" - ":kbd:`Ctrl+Shift+Z`", "Undo the last move of a project item, if possible" - ":kbd:`Ctrl+Shift+Del`", "Move the selected item to Trash" + ":kbd:`F2`", "Edit the label of the selected item" + ":kbd:`Return`", "Open the selected document in the editor" + ":kbd:`Alt+Up`", "Jump or go to the previous item at same level in the tree" + ":kbd:`Alt+Down`", "Jump or go to the next item at same level in the tree" + ":kbd:`Alt+Left`", "Jump to the parent item in the tree" + ":kbd:`Alt+Right`", "Jump to the first child item in the project tree" + ":kbd:`Ctrl+.`", "Open the context menu on the selected item" + ":kbd:`Ctrl+L`", "Open the :guilabel:`Quick Links` menu" + ":kbd:`Ctrl+N`", "Open the :guilabel:`Create New Item` menu" + ":kbd:`Ctrl+O`", "Open selected document" + ":kbd:`Ctrl+R`", "Open the selected document in the viewer" + ":kbd:`Ctrl+Up`", "Move selected item one step up in the tree" + ":kbd:`Ctrl+Down`", "Move selected item one step down in the tree" + ":kbd:`Ctrl+Del`", "Move the selected item to Trash" + ":kbd:`Ctrl+Shift+Z`", "Undo the last move of a project item, if possible" .. _a_kb_editor: @@ -134,6 +134,7 @@ Other Editor Shortcuts ":kbd:`Ctrl+Shift+A`", "Select all text in the current paragraph" ":kbd:`Ctrl+Shift+I`", "Import text to the current document from a text file" + .. _a_kb_ins: Insert Shortcuts diff --git a/novelwriter/gui/mainmenu.py b/novelwriter/gui/mainmenu.py index e6453a82..a0420144 100644 --- a/novelwriter/gui/mainmenu.py +++ b/novelwriter/gui/mainmenu.py @@ -54,6 +54,7 @@ class GuiMainMenu(QMenuBar): requestDocInsert = pyqtSignal(nwDocInsert) requestDocInsertText = pyqtSignal(str) requestDocKeyWordInsert = pyqtSignal(str) + requestFocusChange = pyqtSignal(nwWidget) def __init__(self, mainGui: GuiMain) -> None: super().__init__(parent=mainGui) @@ -173,7 +174,7 @@ class GuiMainMenu(QMenuBar): # Project > Delete self.aDeleteItem = self.projMenu.addAction(self.tr("Delete Item")) - self.aDeleteItem.setShortcut("Ctrl+Shift+Del") + self.aDeleteItem.setShortcuts(["Ctrl+Del", "Ctrl+Shift+Del"]) # Latter is deprecated self.aDeleteItem.triggered.connect(lambda: self.mainGui.projView.requestDeleteItem(None)) # Project > Empty Trash @@ -246,12 +247,16 @@ class GuiMainMenu(QMenuBar): # Edit > Undo self.aEditUndo = self.editMenu.addAction(self.tr("Undo")) self.aEditUndo.setShortcut("Ctrl+Z") - self.aEditUndo.triggered.connect(lambda: self.requestDocAction.emit(nwDocAction.UNDO)) + self.aEditUndo.triggered.connect( + lambda: self.requestDocAction.emit(nwDocAction.UNDO) + ) # Edit > Redo self.aEditRedo = self.editMenu.addAction(self.tr("Redo")) self.aEditRedo.setShortcut("Ctrl+Y") - self.aEditRedo.triggered.connect(lambda: self.requestDocAction.emit(nwDocAction.REDO)) + self.aEditRedo.triggered.connect( + lambda: self.requestDocAction.emit(nwDocAction.REDO) + ) # Edit > Separator self.editMenu.addSeparator() @@ -259,17 +264,23 @@ class GuiMainMenu(QMenuBar): # Edit > Cut self.aEditCut = self.editMenu.addAction(self.tr("Cut")) self.aEditCut.setShortcut("Ctrl+X") - self.aEditCut.triggered.connect(lambda: self.requestDocAction.emit(nwDocAction.CUT)) + self.aEditCut.triggered.connect( + lambda: self.requestDocAction.emit(nwDocAction.CUT) + ) # Edit > Copy self.aEditCopy = self.editMenu.addAction(self.tr("Copy")) self.aEditCopy.setShortcut("Ctrl+C") - self.aEditCopy.triggered.connect(lambda: self.requestDocAction.emit(nwDocAction.COPY)) + self.aEditCopy.triggered.connect( + lambda: self.requestDocAction.emit(nwDocAction.COPY) + ) # Edit > Paste self.aEditPaste = self.editMenu.addAction(self.tr("Paste")) self.aEditPaste.setShortcut("Ctrl+V") - self.aEditPaste.triggered.connect(lambda: self.requestDocAction.emit(nwDocAction.PASTE)) + self.aEditPaste.triggered.connect( + lambda: self.requestDocAction.emit(nwDocAction.PASTE) + ) # Edit > Separator self.editMenu.addSeparator() @@ -277,12 +288,16 @@ class GuiMainMenu(QMenuBar): # Edit > Select All self.aSelectAll = self.editMenu.addAction(self.tr("Select All")) self.aSelectAll.setShortcut("Ctrl+A") - self.aSelectAll.triggered.connect(lambda: self.requestDocAction.emit(nwDocAction.SEL_ALL)) + self.aSelectAll.triggered.connect( + lambda: self.requestDocAction.emit(nwDocAction.SEL_ALL) + ) # Edit > Select Paragraph self.aSelectPar = self.editMenu.addAction(self.tr("Select Paragraph")) self.aSelectPar.setShortcut("Ctrl+Shift+A") - self.aSelectPar.triggered.connect(lambda: self.requestDocAction.emit(nwDocAction.SEL_PARA)) + self.aSelectPar.triggered.connect( + lambda: self.requestDocAction.emit(nwDocAction.SEL_PARA) + ) return @@ -293,23 +308,24 @@ class GuiMainMenu(QMenuBar): # View > TreeView self.aFocusTree = self.viewMenu.addAction(self.tr("Go to Project Tree")) - self.aFocusTree.setShortcut("Ctrl+Alt+1" if CONFIG.osWindows else "Alt+1") - self.aFocusTree.triggered.connect(lambda: self.mainGui.switchFocus(nwWidget.TREE)) + self.aFocusTree.setShortcut("Ctrl+T") + self.aFocusTree.triggered.connect( + lambda: self.requestFocusChange.emit(nwWidget.TREE) + ) - # View > Document Pane 1 + # View > Document Editor self.aFocusEditor = self.viewMenu.addAction(self.tr("Go to Document Editor")) - self.aFocusEditor.setShortcut("Ctrl+Alt+2" if CONFIG.osWindows else "Alt+2") - self.aFocusEditor.triggered.connect(lambda: self.mainGui.switchFocus(nwWidget.EDITOR)) - - # View > Document Pane 2 - self.aFocusView = self.viewMenu.addAction(self.tr("Go to Document Viewer")) - self.aFocusView.setShortcut("Ctrl+Alt+3" if CONFIG.osWindows else "Alt+3") - self.aFocusView.triggered.connect(lambda: self.mainGui.switchFocus(nwWidget.VIEWER)) + self.aFocusEditor.setShortcut("Ctrl+E") + self.aFocusEditor.triggered.connect( + lambda: self.requestFocusChange.emit(nwWidget.EDITOR) + ) # View > Outline self.aFocusOutline = self.viewMenu.addAction(self.tr("Go to Outline")) - self.aFocusOutline.setShortcut("Ctrl+Alt+4" if CONFIG.osWindows else "Alt+4") - self.aFocusOutline.triggered.connect(lambda: self.mainGui.switchFocus(nwWidget.OUTLINE)) + self.aFocusOutline.setShortcut("Ctrl+Shift+T") + self.aFocusOutline.triggered.connect( + lambda: self.requestFocusChange.emit(nwWidget.OUTLINE) + ) # View > Separator self.viewMenu.addSeparator() diff --git a/novelwriter/gui/projtree.py b/novelwriter/gui/projtree.py index d1c2f903..b52680d7 100644 --- a/novelwriter/gui/projtree.py +++ b/novelwriter/gui/projtree.py @@ -189,7 +189,7 @@ class GuiProjectView(QWidget): self.projTree.buildTree() return - def setFocus(self) -> None: + def setTreeFocus(self) -> None: """Forward the set focus call to the tree widget.""" self.projTree.setFocus() return diff --git a/novelwriter/gui/sidebar.py b/novelwriter/gui/sidebar.py index be719a42..6bee63a6 100644 --- a/novelwriter/gui/sidebar.py +++ b/novelwriter/gui/sidebar.py @@ -57,32 +57,32 @@ class GuiSideBar(QWidget): # Buttons self.tbProject = QToolButton(self) - self.tbProject.setToolTip(self.tr("Project Tree View")) + self.tbProject.setToolTip("{0} [Ctrl+T]".format(self.tr("Project Tree View"))) self.tbProject.setIconSize(iconSize) self.tbProject.clicked.connect(lambda: self.viewChangeRequested.emit(nwView.PROJECT)) self.tbNovel = QToolButton(self) - self.tbNovel.setToolTip(self.tr("Novel Tree View")) + self.tbNovel.setToolTip("{0} [Ctrl+T]".format(self.tr("Novel Tree View"))) self.tbNovel.setIconSize(iconSize) self.tbNovel.clicked.connect(lambda: self.viewChangeRequested.emit(nwView.NOVEL)) self.tbOutline = QToolButton(self) - self.tbOutline.setToolTip(self.tr("Novel Outline View")) + self.tbOutline.setToolTip(f"{0} [Ctrl+Shift+T]".format(self.tr("Novel Outline View"))) self.tbOutline.setIconSize(iconSize) self.tbOutline.clicked.connect(lambda: self.viewChangeRequested.emit(nwView.OUTLINE)) self.tbBuild = QToolButton(self) - self.tbBuild.setToolTip(self.tr("Build Manuscript")) + self.tbBuild.setToolTip("{0} [F5]".format(self.tr("Build Manuscript"))) self.tbBuild.setIconSize(iconSize) self.tbBuild.clicked.connect(self.mainGui.showBuildManuscriptDialog) self.tbDetails = QToolButton(self) - self.tbDetails.setToolTip(self.tr("Project Details")) + self.tbDetails.setToolTip("{0} [Shift+F6]".format(self.tr("Project Details"))) self.tbDetails.setIconSize(iconSize) self.tbDetails.clicked.connect(self.mainGui.showProjectDetailsDialog) self.tbStats = QToolButton(self) - self.tbStats.setToolTip(self.tr("Writing Statistics")) + self.tbStats.setToolTip("{0} [F6]".format(self.tr("Writing Statistics"))) self.tbStats.setIconSize(iconSize) self.tbStats.clicked.connect(self.mainGui.showWritingStatsDialog) diff --git a/novelwriter/guimain.py b/novelwriter/guimain.py index 519a40cf..c672a1f2 100644 --- a/novelwriter/guimain.py +++ b/novelwriter/guimain.py @@ -31,7 +31,7 @@ from pathlib import Path from datetime import datetime from PyQt5.QtCore import Qt, QTimer, pyqtSlot -from PyQt5.QtGui import QCloseEvent, QCursor, QIcon, QKeySequence +from PyQt5.QtGui import QCloseEvent, QCursor, QIcon from PyQt5.QtWidgets import ( QDialog, QFileDialog, QHBoxLayout, QMainWindow, QMessageBox, QShortcut, QSplitter, QStackedWidget, QVBoxLayout, QWidget, qApp @@ -247,6 +247,7 @@ class GuiMain(QMainWindow): self.mainMenu.requestDocInsert.connect(self._passDocumentInsert) self.mainMenu.requestDocInsertText.connect(self._passDocumentInsert) self.mainMenu.requestDocKeyWordInsert.connect(self.docEditor.insertKeyWord) + self.mainMenu.requestFocusChange.connect(self.switchFocus) self.sideBar.viewChangeRequested.connect(self._changeView) @@ -300,17 +301,17 @@ class GuiMain(QMainWindow): # Shortcuts and Actions self._connectMenuActions() - keyReturn = QShortcut(self) - keyReturn.setKey(QKeySequence(Qt.Key_Return)) - keyReturn.activated.connect(self._keyPressReturn) + self.keyReturn = QShortcut(self) + self.keyReturn.setKey(Qt.Key.Key_Return) + self.keyReturn.activated.connect(self._keyPressReturn) - keyEnter = QShortcut(self) - keyEnter.setKey(QKeySequence(Qt.Key_Enter)) - keyEnter.activated.connect(self._keyPressReturn) + self.keyEnter = QShortcut(self) + self.keyEnter.setKey(Qt.Key.Key_Enter) + self.keyEnter.activated.connect(self._keyPressReturn) - keyEscape = QShortcut(self) - keyEscape.setKey(QKeySequence(Qt.Key_Escape)) - keyEscape.activated.connect(self._keyPressEscape) + self.keyEscape = QShortcut(self) + self.keyEscape.setKey(Qt.Key.Key_Escape) + self.keyEscape.activated.connect(self._keyPressEscape) # Check that config loaded fine self.reportConfErr() @@ -1093,25 +1094,6 @@ class GuiMain(QMainWindow): return True - def switchFocus(self, paneNo: nwWidget) -> None: - """Switch focus between main GUI views.""" - if paneNo == nwWidget.TREE: - tabIdx = self.projStack.currentIndex() - if tabIdx == self.idxProjView: - self.projView.setFocus() - elif tabIdx == self.idxNovelView: - self.novelView.setTreeFocus() - elif paneNo == nwWidget.EDITOR: - self._changeView(nwView.EDITOR) - self.docEditor.setFocus() - elif paneNo == nwWidget.VIEWER: - self._changeView(nwView.EDITOR) - self.docViewer.setFocus() - elif paneNo == nwWidget.OUTLINE: - self._changeView(nwView.OUTLINE) - self.outlineView.setTreeFocus() - return - def closeDocViewer(self, byUser: bool = True) -> bool: """Close the document view panel.""" self.docViewer.clearViewer() @@ -1189,6 +1171,33 @@ class GuiMain(QMainWindow): return + @pyqtSlot(nwWidget) + def switchFocus(self, paneNo: nwWidget) -> None: + """Switch focus between main GUI views.""" + if paneNo == nwWidget.TREE: + if self.projStack.currentWidget() is self.projView: + if self.projView.treeHasFocus(): + self._changeView(nwView.NOVEL) + self.novelView.setTreeFocus() + else: + self.projView.setTreeFocus() + else: + if self.novelView.treeHasFocus(): + self._changeView(nwView.PROJECT) + self.projView.setTreeFocus() + else: + self.novelView.setTreeFocus() + elif paneNo == nwWidget.EDITOR: + self._changeView(nwView.EDITOR) + self.docEditor.setFocus() + elif paneNo == nwWidget.VIEWER: + self._changeView(nwView.EDITOR) + self.docViewer.setFocus() + elif paneNo == nwWidget.OUTLINE: + self._changeView(nwView.OUTLINE) + self.outlineView.setTreeFocus() + return + ## # Private Slots ## @@ -1224,18 +1233,14 @@ class GuiMain(QMainWindow): if view == nwView.EDITOR: # Only change the main stack, but not the project stack self.mainStack.setCurrentWidget(self.splitMain) - elif view == nwView.PROJECT: self.mainStack.setCurrentWidget(self.splitMain) self.projStack.setCurrentWidget(self.projView) - elif view == nwView.NOVEL: self.mainStack.setCurrentWidget(self.splitMain) self.projStack.setCurrentWidget(self.novelView) - elif view == nwView.OUTLINE: self.mainStack.setCurrentWidget(self.outlineView) - return @pyqtSlot(nwDocAction)