From ea09a534962c9cd75dbf64584cc970e83b0730a7 Mon Sep 17 00:00:00 2001
From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com>
Date: Tue, 10 May 2022 20:56:52 +0200
Subject: [PATCH 1/6] Add the GuiViewsBar class
---
novelwriter/gui/__init__.py | 2 +
novelwriter/gui/viewsbar.py | 81 +++++++++++++++++++++++++++++++++++++
novelwriter/guimain.py | 5 ++-
3 files changed, 87 insertions(+), 1 deletion(-)
create mode 100644 novelwriter/gui/viewsbar.py
diff --git a/novelwriter/gui/__init__.py b/novelwriter/gui/__init__.py
index 405549cb..8364e342 100644
--- a/novelwriter/gui/__init__.py
+++ b/novelwriter/gui/__init__.py
@@ -29,6 +29,7 @@ from novelwriter.gui.outlinedetails import GuiOutlineDetails
from novelwriter.gui.projtree import GuiProjectTree
from novelwriter.gui.statusbar import GuiMainStatus
from novelwriter.gui.theme import GuiTheme
+from novelwriter.gui.viewsbar import GuiViewsBar
__all__ = [
"GuiDocEditor",
@@ -42,4 +43,5 @@ __all__ = [
"GuiOutlineDetails",
"GuiProjectTree",
"GuiTheme",
+ "GuiViewsBar",
]
diff --git a/novelwriter/gui/viewsbar.py b/novelwriter/gui/viewsbar.py
new file mode 100644
index 00000000..e8eb97fc
--- /dev/null
+++ b/novelwriter/gui/viewsbar.py
@@ -0,0 +1,81 @@
+"""
+novelWriter – GUI Main Window Views ToolBar
+===========================================
+GUI class for the main window "Views" toolbar
+
+File History:
+Created: 2022-05-10 [1.7b1]
+
+This file is a part of novelWriter
+Copyright 2018–2022, 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 .
+"""
+
+import logging
+import novelwriter
+
+from PyQt5.QtCore import Qt, QSize
+from PyQt5.QtWidgets import QToolBar, QWidget, QSizePolicy, QAction
+
+logger = logging.getLogger(__name__)
+
+
+class GuiViewsBar(QToolBar):
+
+ def __init__(self, theParent):
+ QToolBar.__init__(self, theParent)
+
+ logger.debug("Initialising GuiViewsBar ...")
+
+ self.mainConf = novelwriter.CONFIG
+ self.theParent = theParent
+ self.theTheme = theParent.theTheme
+
+ # Style
+ iPx = self.mainConf.pxInt(22)
+
+ lblFont = self.theTheme.guiFont
+ lblFont.setPointSizeF(0.65*self.theTheme.fontPointSize)
+ self.setFont(lblFont)
+
+ self.setMovable(False)
+ self.setToolButtonStyle(Qt.ToolButtonTextUnderIcon)
+ self.setIconSize(QSize(iPx, iPx))
+ self.setContentsMargins(0, 0, 0, 0)
+
+ stretch = QWidget(self)
+ stretch.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
+
+ # Actions
+ self.aProject = QAction(self.tr("Project"))
+ self.aProject.setIcon(self.theTheme.getIcon("status_lines"))
+
+ self.aStats = QAction(self.tr("Stats"))
+ self.aStats.setIcon(self.theTheme.getIcon("status_stats"))
+
+ self.aSettings = QAction(self.tr("Settings"))
+ self.aSettings.setIcon(self.theTheme.getIcon("settings"))
+
+ # Assemble
+ self.addWidget(stretch)
+ self.addAction(self.aProject)
+ self.addAction(self.aStats)
+ self.addAction(self.aSettings)
+
+ logger.debug("GuiViewsBar initialisation complete")
+
+ return
+
+# END Class GuiViewsBar
diff --git a/novelwriter/guimain.py b/novelwriter/guimain.py
index 60fe0d23..84607fc0 100644
--- a/novelwriter/guimain.py
+++ b/novelwriter/guimain.py
@@ -40,7 +40,7 @@ from PyQt5.QtWidgets import (
from novelwriter.gui import (
GuiDocEditor, GuiDocViewDetails, GuiDocViewer, GuiItemDetails, GuiMainMenu,
GuiMainStatus, GuiNovelTree, GuiOutline, GuiOutlineDetails, GuiProjectTree,
- GuiTheme
+ GuiTheme, GuiViewsBar
)
from novelwriter.dialogs import (
GuiAbout, GuiDocMerge, GuiDocSplit, GuiItemEditor, GuiPreferences,
@@ -116,6 +116,7 @@ class GuiMain(QMainWindow):
self.projView = GuiOutline(self)
self.projMeta = GuiOutlineDetails(self)
self.mainMenu = GuiMainMenu(self)
+ self.viewsBar = GuiViewsBar(self)
# Connect Signals Between Main Elements
self.docEditor.spellDictionaryChanged.connect(self.statusBar.setLanguage)
@@ -238,6 +239,7 @@ class GuiMain(QMainWindow):
self.setMenuBar(self.mainMenu)
self.setCentralWidget(self.splitMain)
self.setStatusBar(self.statusBar)
+ self.addToolBar(Qt.LeftToolBarArea, self.viewsBar)
# Finalise Initialisation
# =======================
@@ -1299,6 +1301,7 @@ class GuiMain(QMainWindow):
self.treePane.setVisible(isVisible)
self.statusBar.setVisible(isVisible)
self.mainMenu.setVisible(isVisible)
+ self.viewsBar.setVisible(isVisible)
self.mainTabs.tabBar().setVisible(isVisible)
hideDocFooter = self.isFocusMode and self.mainConf.hideFocusFooter
From 864b06a0e716dfd5d15c3dad4ceceed1f1218950 Mon Sep 17 00:00:00 2001
From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com>
Date: Tue, 10 May 2022 22:14:35 +0200
Subject: [PATCH 2/6] Shift all view changing functionality to the new Views
bar
---
novelwriter/enum.py | 13 +++
novelwriter/gui/viewsbar.py | 28 +++++-
novelwriter/guimain.py | 127 +++++++++++++--------------
tests/test_gui/test_gui_guimain.py | 4 +-
tests/test_gui/test_gui_noveltree.py | 2 +-
tests/test_gui/test_gui_outline.py | 2 +-
6 files changed, 102 insertions(+), 74 deletions(-)
diff --git a/novelwriter/enum.py b/novelwriter/enum.py
index 56340541..2d0cc56f 100644
--- a/novelwriter/enum.py
+++ b/novelwriter/enum.py
@@ -130,6 +130,19 @@ class nwState(Enum):
# END Enum nwState
+class nwView(Enum):
+
+ PROJECT = 0
+ NOVEL = 1
+ OUTLINE = 2
+ DETAILS = 3
+ STATS = 4
+ SET_PROJ = 5
+ SET_MAIN = 6
+
+# END Enum nwView
+
+
class nwWidget(Enum):
TREE = 1
diff --git a/novelwriter/gui/viewsbar.py b/novelwriter/gui/viewsbar.py
index e8eb97fc..71974357 100644
--- a/novelwriter/gui/viewsbar.py
+++ b/novelwriter/gui/viewsbar.py
@@ -26,14 +26,18 @@ along with this program. If not, see .
import logging
import novelwriter
-from PyQt5.QtCore import Qt, QSize
+from PyQt5.QtCore import Qt, QSize, pyqtSignal
from PyQt5.QtWidgets import QToolBar, QWidget, QSizePolicy, QAction
+from novelwriter.enum import nwView
+
logger = logging.getLogger(__name__)
class GuiViewsBar(QToolBar):
+ viewChangeRequested = pyqtSignal(nwView)
+
def __init__(self, theParent):
QToolBar.__init__(self, theParent)
@@ -60,17 +64,35 @@ class GuiViewsBar(QToolBar):
# Actions
self.aProject = QAction(self.tr("Project"))
- self.aProject.setIcon(self.theTheme.getIcon("status_lines"))
+ self.aProject.setIcon(self.theTheme.getIcon("proj_folder"))
+ self.aProject.triggered.connect(lambda: self.viewChangeRequested.emit(nwView.PROJECT))
+
+ self.aNovel = QAction(self.tr("Novel"))
+ self.aNovel.setIcon(self.theTheme.getIcon("cls_novel"))
+ self.aNovel.triggered.connect(lambda: self.viewChangeRequested.emit(nwView.NOVEL))
+
+ self.aOutline = QAction(self.tr("Outline"))
+ self.aOutline.setIcon(self.theTheme.getIcon("cls_plot"))
+ self.aOutline.triggered.connect(lambda: self.viewChangeRequested.emit(nwView.OUTLINE))
+
+ self.aDetails = QAction(self.tr("Details"))
+ self.aDetails.setIcon(self.theTheme.getIcon("status_lines"))
+ self.aDetails.triggered.connect(lambda: self.viewChangeRequested.emit(nwView.DETAILS))
self.aStats = QAction(self.tr("Stats"))
self.aStats.setIcon(self.theTheme.getIcon("status_stats"))
+ self.aStats.triggered.connect(lambda: self.viewChangeRequested.emit(nwView.STATS))
self.aSettings = QAction(self.tr("Settings"))
self.aSettings.setIcon(self.theTheme.getIcon("settings"))
+ self.aSettings.triggered.connect(lambda: self.viewChangeRequested.emit(nwView.SET_PROJ))
# Assemble
- self.addWidget(stretch)
self.addAction(self.aProject)
+ self.addAction(self.aNovel)
+ self.addAction(self.aOutline)
+ self.addWidget(stretch)
+ self.addAction(self.aDetails)
self.addAction(self.aStats)
self.addAction(self.aSettings)
diff --git a/novelwriter/guimain.py b/novelwriter/guimain.py
index 84607fc0..077a22d3 100644
--- a/novelwriter/guimain.py
+++ b/novelwriter/guimain.py
@@ -30,11 +30,11 @@ import novelwriter
from time import time
from datetime import datetime
-from PyQt5.QtCore import Qt, QTimer, QSize, QThreadPool, pyqtSlot
+from PyQt5.QtCore import Qt, QTimer, QThreadPool, pyqtSlot
from PyQt5.QtGui import QIcon, QKeySequence, QCursor
from PyQt5.QtWidgets import (
qApp, QMainWindow, QVBoxLayout, QWidget, QSplitter, QFileDialog, QShortcut,
- QMessageBox, QDialog, QTabWidget, QToolBar, QAction
+ QMessageBox, QDialog, QStackedWidget
)
from novelwriter.gui import (
@@ -52,7 +52,7 @@ from novelwriter.tools import (
)
from novelwriter.core import NWProject, NWIndex
from novelwriter.enum import (
- nwItemType, nwItemClass, nwAlert, nwWidget, nwState
+ nwItemType, nwItemClass, nwAlert, nwWidget, nwState, nwView
)
from novelwriter.common import getGuiItem, hexToInt
@@ -102,8 +102,6 @@ class GuiMain(QMainWindow):
# Sizes
mPx = self.mainConf.pxInt(4)
- fPx = self.theTheme.fontPixelSize
- fPt = self.theTheme.fontPointSize
# Main GUI Elements
self.statusBar = GuiMainStatus(self)
@@ -129,48 +127,20 @@ class GuiMain(QMainWindow):
self.treeView.novelItemChanged.connect(self._treeNovelItemChanged)
self.treeView.wordCountsChanged.connect(self._updateStatusWordCount)
- # Project Tree Tabs
- self.projTabs = QTabWidget()
- self.projTabs.setTabPosition(QTabWidget.South)
- self.projTabs.setStyleSheet("QTabWidget::pane {border: 0;};")
- self.projTabs.addTab(self.treeView, self.tr("Project"))
- self.projTabs.addTab(self.novelView, self.tr("Novel"))
- self.projTabs.currentChanged.connect(self._projTabsChanged)
+ self.viewsBar.viewChangeRequested.connect(self._changeView)
- tabFont = self.projTabs.tabBar().font()
- tabFont.setPointSizeF(0.9*fPt)
- self.projTabs.tabBar().setFont(tabFont)
-
- # Project Tree Action Buttons
- btnSize = int(round(0.7*fPx))
- self.treeButtons = QToolBar()
- self.treeButtons.setToolButtonStyle(Qt.ToolButtonIconOnly)
- self.treeButtons.setIconSize(QSize(btnSize, btnSize))
- self.treeButtons.setContentsMargins(0, 0, 0, 0)
- self.treeButtons.setStyleSheet("QToolBar {padding: 0;}")
- self.projTabs.setCornerWidget(self.treeButtons, Qt.BottomRightCorner)
-
- self.projDetailsBtn = QAction(self.tr("Project Details"))
- self.projDetailsBtn.setIcon(self.theTheme.getIcon("status_lines"))
- self.projDetailsBtn.triggered.connect(lambda: self.showProjectDetailsDialog())
- self.treeButtons.addAction(self.projDetailsBtn)
-
- self.projStatsBtn = QAction(self.tr("Writing Statistics"))
- self.projStatsBtn.setIcon(self.theTheme.getIcon("status_stats"))
- self.projStatsBtn.triggered.connect(lambda: self.showWritingStatsDialog())
- self.treeButtons.addAction(self.projStatsBtn)
-
- self.projSettingsBtn = QAction(self.tr("Project Settings"))
- self.projSettingsBtn.setIcon(self.theTheme.getIcon("settings"))
- self.projSettingsBtn.triggered.connect(lambda: self.showProjectSettingsDialog())
- self.treeButtons.addAction(self.projSettingsBtn)
+ # Project Tree Stack
+ self.projStack = QStackedWidget()
+ self.projStack.addWidget(self.treeView)
+ self.projStack.addWidget(self.novelView)
+ self.projStack.currentChanged.connect(self._projStackChanged)
# Project Tree View
self.treePane = QWidget()
self.treeBox = QVBoxLayout()
self.treeBox.setContentsMargins(0, 0, 0, 0)
self.treeBox.setSpacing(mPx)
- self.treeBox.addWidget(self.projTabs)
+ self.treeBox.addWidget(self.projStack)
self.treeBox.addWidget(self.treeMeta)
self.treePane.setLayout(self.treeBox)
@@ -192,33 +162,31 @@ class GuiMain(QMainWindow):
self.splitOutline.setSizes(self.mainConf.getOutlinePanePos())
# Main Tabs : Editor / Outline
- self.mainTabs = QTabWidget()
- self.mainTabs.setTabPosition(QTabWidget.East)
- self.mainTabs.setStyleSheet("QTabWidget::pane {border: 0;}")
- self.mainTabs.addTab(self.splitDocs, self.tr("Editor"))
- self.mainTabs.addTab(self.splitOutline, self.tr("Outline"))
- self.mainTabs.currentChanged.connect(self._mainTabChanged)
+ self.mainStack = QStackedWidget()
+ self.mainStack.addWidget(self.splitDocs)
+ self.mainStack.addWidget(self.splitOutline)
+ self.mainStack.currentChanged.connect(self._mainStackChanged)
# Splitter : Project Tree / Main Tabs
self.splitMain = QSplitter(Qt.Horizontal)
self.splitMain.setContentsMargins(mPx, mPx, mPx, mPx)
self.splitMain.addWidget(self.treePane)
- self.splitMain.addWidget(self.mainTabs)
+ self.splitMain.addWidget(self.mainStack)
self.splitMain.setSizes(self.mainConf.getMainPanePos())
# Indices of Splitter Widgets
self.idxTree = self.splitMain.indexOf(self.treePane)
- self.idxMain = self.splitMain.indexOf(self.mainTabs)
+ self.idxMain = self.splitMain.indexOf(self.mainStack)
self.idxEditor = self.splitDocs.indexOf(self.docEditor)
self.idxViewer = self.splitDocs.indexOf(self.splitView)
self.idxViewDoc = self.splitView.indexOf(self.docViewer)
self.idxViewMeta = self.splitView.indexOf(self.viewMeta)
# Indices of Tab Widgets
- self.idxTabEdit = self.mainTabs.indexOf(self.splitDocs)
- self.idxTabProj = self.mainTabs.indexOf(self.splitOutline)
- self.idxTreeView = self.projTabs.indexOf(self.treeView)
- self.idxNovelView = self.projTabs.indexOf(self.novelView)
+ self.idxTabEdit = self.mainStack.indexOf(self.splitDocs)
+ self.idxTabProj = self.mainStack.indexOf(self.splitOutline)
+ self.idxTreeView = self.projStack.indexOf(self.treeView)
+ self.idxNovelView = self.projStack.indexOf(self.novelView)
# Splitter Behaviour
self.splitMain.setCollapsible(self.idxTree, False)
@@ -450,7 +418,7 @@ class GuiMain(QMainWindow):
self.theIndex.clearIndex()
self.clearGUI()
self.hasProject = False
- self.mainTabs.setCurrentWidget(self.splitDocs)
+ self.mainStack.setCurrentWidget(self.splitDocs)
return saveOK
@@ -466,7 +434,7 @@ class GuiMain(QMainWindow):
return False
# Switch main tab to editor view
- self.mainTabs.setCurrentWidget(self.splitDocs)
+ self.mainStack.setCurrentWidget(self.splitDocs)
# Try to open the project
if not self.theProject.openProject(projFile):
@@ -605,7 +573,7 @@ class GuiMain(QMainWindow):
return False
self.closeDocument()
- self.mainTabs.setCurrentWidget(self.splitDocs)
+ self.mainStack.setCurrentWidget(self.splitDocs)
if self.docEditor.loadText(tHandle, tLine):
if changeFocus:
self.docEditor.setFocus()
@@ -688,7 +656,7 @@ class GuiMain(QMainWindow):
return False
# Make sure main tab is in Editor view
- self.mainTabs.setCurrentWidget(self.splitDocs)
+ self.mainStack.setCurrentWidget(self.splitDocs)
logger.debug("Viewing document with handle '%s'", tHandle)
if self.docViewer.loadText(tHandle):
@@ -873,7 +841,7 @@ class GuiMain(QMainWindow):
def requestNovelTreeRefresh(self):
"""Update the novel tree, but only if it is visible.
"""
- if self.projTabs.currentIndex() == self.idxNovelView and self.hasProject:
+ if self.projStack.currentIndex() == self.idxNovelView and self.hasProject:
self.novelView.refreshTree()
return True
return False
@@ -934,7 +902,7 @@ class GuiMain(QMainWindow):
return False
logger.verbose("Forcing a rebuild of the Project Outline")
- self.mainTabs.setCurrentWidget(self.splitOutline)
+ self.mainStack.setCurrentWidget(self.splitOutline)
self.projView.refreshTree(overRide=True)
return True
@@ -1247,19 +1215,19 @@ class GuiMain(QMainWindow):
"""Switch focus between main GUI views.
"""
if paneNo == nwWidget.TREE:
- tabIdx = self.projTabs.currentIndex()
+ tabIdx = self.projStack.currentIndex()
if tabIdx == self.idxTreeView:
self.treeView.setFocus()
elif tabIdx == self.idxNovelView:
self.novelView.setFocus()
elif paneNo == nwWidget.EDITOR:
- self.mainTabs.setCurrentWidget(self.splitDocs)
+ self.mainStack.setCurrentWidget(self.splitDocs)
self.docEditor.setFocus()
elif paneNo == nwWidget.VIEWER:
- self.mainTabs.setCurrentWidget(self.splitDocs)
+ self.mainStack.setCurrentWidget(self.splitDocs)
self.docViewer.setFocus()
elif paneNo == nwWidget.OUTLINE:
- self.mainTabs.setCurrentWidget(self.splitOutline)
+ self.mainStack.setCurrentWidget(self.splitOutline)
self.projView.setFocus()
return
@@ -1292,7 +1260,7 @@ class GuiMain(QMainWindow):
self.mainMenu.setFocusMode(self.isFocusMode)
if self.isFocusMode:
logger.debug("Activating Focus Mode")
- self.mainTabs.setCurrentWidget(self.splitDocs)
+ self.mainStack.setCurrentWidget(self.splitDocs)
self.switchFocus(nwWidget.EDITOR)
else:
logger.debug("Deactivating Focus Mode")
@@ -1302,7 +1270,6 @@ class GuiMain(QMainWindow):
self.statusBar.setVisible(isVisible)
self.mainMenu.setVisible(isVisible)
self.viewsBar.setVisible(isVisible)
- self.mainTabs.tabBar().setVisible(isVisible)
hideDocFooter = self.isFocusMode and self.mainConf.hideFocusFooter
self.docEditor.docFooter.setVisible(not hideDocFooter)
@@ -1516,6 +1483,32 @@ class GuiMain(QMainWindow):
# Slots
##
+ @pyqtSlot(nwView)
+ def _changeView(self, view):
+ """Handle the requested change of view from the GuiViewBar.
+ """
+ if view == nwView.PROJECT:
+ self.mainStack.setCurrentWidget(self.splitDocs)
+ self.projStack.setCurrentWidget(self.treeView)
+
+ elif view == nwView.NOVEL:
+ self.mainStack.setCurrentWidget(self.splitDocs)
+ self.projStack.setCurrentWidget(self.novelView)
+
+ elif view == nwView.OUTLINE:
+ self.mainStack.setCurrentWidget(self.splitOutline)
+
+ elif view == nwView.DETAILS:
+ self.showProjectDetailsDialog()
+
+ elif view == nwView.STATS:
+ self.showWritingStatsDialog()
+
+ elif view == nwView.SET_PROJ:
+ self.showProjectSettingsDialog()
+
+ return
+
@pyqtSlot()
def _timeTick(self):
"""Triggered on every tick of the main timer.
@@ -1589,7 +1582,7 @@ class GuiMain(QMainWindow):
"""Triggered when there is a change to a novel item in the
project tree.
"""
- if self.mainTabs.currentIndex() == self.idxTabProj:
+ if self.mainStack.currentIndex() == self.idxTabProj:
logger.verbose("Novel tree changed while Outline tab active")
if self.hasProject:
self.treeView.flushTreeOrder()
@@ -1618,7 +1611,7 @@ class GuiMain(QMainWindow):
return
@pyqtSlot(int)
- def _mainTabChanged(self, tabIndex):
+ def _mainStackChanged(self, tabIndex):
"""Activated when the main window tab is changed.
"""
if tabIndex == self.idxTabEdit:
@@ -1631,7 +1624,7 @@ class GuiMain(QMainWindow):
return
@pyqtSlot(int)
- def _projTabsChanged(self, tabIndex):
+ def _projStackChanged(self, tabIndex):
"""Activated when the project view tab is changed.
"""
sHandle = None
diff --git a/tests/test_gui/test_gui_guimain.py b/tests/test_gui/test_gui_guimain.py
index 65648862..ddb4f09b 100644
--- a/tests/test_gui/test_gui_guimain.py
+++ b/tests/test_gui/test_gui_guimain.py
@@ -85,7 +85,7 @@ def testGuiMain_ProjectTreeItems(qtbot, monkeypatch, nwGUI, fncProj, mockRnd):
# Project Tree has focus
nwGUI.switchFocus(nwWidget.TREE)
- nwGUI.projTabs.setCurrentIndex(0)
+ nwGUI.projStack.setCurrentIndex(0)
with monkeypatch.context() as mp:
mp.setattr(GuiProjectTree, "hasFocus", lambda *a: True)
assert nwGUI.docEditor.docHandle() is None
@@ -95,7 +95,7 @@ def testGuiMain_ProjectTreeItems(qtbot, monkeypatch, nwGUI, fncProj, mockRnd):
assert nwGUI.closeDocument() is True
# Novel Tree has focus
- nwGUI.projTabs.setCurrentIndex(1)
+ nwGUI.projStack.setCurrentIndex(1)
nwGUI.novelView.refreshTree(True)
with monkeypatch.context() as mp:
mp.setattr(GuiNovelTree, "hasFocus", lambda *a: True)
diff --git a/tests/test_gui/test_gui_noveltree.py b/tests/test_gui/test_gui_noveltree.py
index f2418a87..2bf2df8a 100644
--- a/tests/test_gui/test_gui_noveltree.py
+++ b/tests/test_gui/test_gui_noveltree.py
@@ -59,7 +59,7 @@ def testGuiNovelTree_TreeItems(qtbot, monkeypatch, nwGUI, nwMinimal):
# Populate Tree
##
- nwGUI.projTabs.setCurrentIndex(nwGUI.idxNovelView)
+ nwGUI.projStack.setCurrentIndex(nwGUI.idxNovelView)
nwGUI.rebuildIndex()
nwTree._populateTree()
assert nwTree.topLevelItemCount() == 1
diff --git a/tests/test_gui/test_gui_outline.py b/tests/test_gui/test_gui_outline.py
index 972e7456..901a2bd2 100644
--- a/tests/test_gui/test_gui_outline.py
+++ b/tests/test_gui/test_gui_outline.py
@@ -43,7 +43,7 @@ def testGuiOutline_Main(qtbot, monkeypatch, nwGUI, nwLipsum):
nwGUI.mainConf.lastPath = nwLipsum
nwGUI.rebuildIndex()
- nwGUI.mainTabs.setCurrentIndex(nwGUI.idxTabProj)
+ nwGUI.mainStack.setCurrentIndex(nwGUI.idxTabProj)
assert nwGUI.projView.topLevelItemCount() > 0
From e8a0a6d5f97e031ebe094b61a490caf86b39109e Mon Sep 17 00:00:00 2001
From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com>
Date: Sat, 14 May 2022 18:27:18 +0200
Subject: [PATCH 3/6] Connect the change of view methods to all relevant
actions
---
novelwriter/enum.py | 15 ++++----
novelwriter/gui/itemdetails.py | 1 +
novelwriter/gui/outlinedetails.py | 6 ++-
novelwriter/guimain.py | 64 ++++++++++++++++---------------
4 files changed, 48 insertions(+), 38 deletions(-)
diff --git a/novelwriter/enum.py b/novelwriter/enum.py
index 2d0cc56f..20332b2f 100644
--- a/novelwriter/enum.py
+++ b/novelwriter/enum.py
@@ -132,13 +132,14 @@ class nwState(Enum):
class nwView(Enum):
- PROJECT = 0
- NOVEL = 1
- OUTLINE = 2
- DETAILS = 3
- STATS = 4
- SET_PROJ = 5
- SET_MAIN = 6
+ EDITOR = 0
+ PROJECT = 1
+ NOVEL = 2
+ OUTLINE = 3
+ DETAILS = 4
+ STATS = 5
+ SET_PROJ = 6
+ SET_MAIN = 7
# END Enum nwView
diff --git a/novelwriter/gui/itemdetails.py b/novelwriter/gui/itemdetails.py
index 73082fa5..8b42b752 100644
--- a/novelwriter/gui/itemdetails.py
+++ b/novelwriter/gui/itemdetails.py
@@ -115,6 +115,7 @@ class GuiItemDetails(QWidget):
self.usageData = QLabel("")
self.usageData.setFont(fntValue)
self.usageData.setAlignment(Qt.AlignLeft)
+ self.usageData.setWordWrap(True)
# Character Count
self.cCountName = QLabel(" "+self.tr("Characters"))
diff --git a/novelwriter/gui/outlinedetails.py b/novelwriter/gui/outlinedetails.py
index b45c298f..358a6531 100644
--- a/novelwriter/gui/outlinedetails.py
+++ b/novelwriter/gui/outlinedetails.py
@@ -26,11 +26,12 @@ along with this program. If not, see .
import logging
import novelwriter
-from PyQt5.QtCore import Qt, QT_TRANSLATE_NOOP
+from PyQt5.QtCore import Qt, QT_TRANSLATE_NOOP, pyqtSignal
from PyQt5.QtWidgets import (
QScrollArea, QWidget, QGridLayout, QHBoxLayout, QGroupBox, QLabel
)
+from novelwriter.enum import nwView
from novelwriter.common import checkInt
from novelwriter.constants import trConst, nwKeyWords, nwLabels
@@ -46,6 +47,8 @@ class GuiOutlineDetails(QScrollArea):
"H4": QT_TRANSLATE_NOOP("GuiOutlineDetails", "Section"),
}
+ viewChangeRequested = pyqtSignal(nwView)
+
def __init__(self, theParent):
QScrollArea.__init__(self, theParent)
@@ -329,6 +332,7 @@ class GuiOutlineDetails(QScrollArea):
if len(theLink) > 0:
theBits = theLink.split("=")
if len(theBits) == 2:
+ self.viewChangeRequested.emit(nwView.PROJECT)
self.theParent.docViewer.loadFromTag(theBits[1])
return
diff --git a/novelwriter/guimain.py b/novelwriter/guimain.py
index 077a22d3..ad06cc59 100644
--- a/novelwriter/guimain.py
+++ b/novelwriter/guimain.py
@@ -128,6 +128,7 @@ class GuiMain(QMainWindow):
self.treeView.wordCountsChanged.connect(self._updateStatusWordCount)
self.viewsBar.viewChangeRequested.connect(self._changeView)
+ self.projMeta.viewChangeRequested.connect(self._changeView)
# Project Tree Stack
self.projStack = QStackedWidget()
@@ -161,32 +162,32 @@ class GuiMain(QMainWindow):
self.splitOutline.addWidget(self.projMeta)
self.splitOutline.setSizes(self.mainConf.getOutlinePanePos())
- # Main Tabs : Editor / Outline
+ # Splitter : Project Tree / Main Tabs
+ self.splitMain = QSplitter(Qt.Horizontal)
+ self.splitMain.setContentsMargins(0, 0, mPx, 0)
+ self.splitMain.addWidget(self.treePane)
+ self.splitMain.addWidget(self.splitDocs)
+ self.splitMain.setSizes(self.mainConf.getMainPanePos())
+
+ # Main Stack : Editor / Outline
self.mainStack = QStackedWidget()
- self.mainStack.addWidget(self.splitDocs)
+ self.mainStack.addWidget(self.splitMain)
self.mainStack.addWidget(self.splitOutline)
self.mainStack.currentChanged.connect(self._mainStackChanged)
- # Splitter : Project Tree / Main Tabs
- self.splitMain = QSplitter(Qt.Horizontal)
- self.splitMain.setContentsMargins(mPx, mPx, mPx, mPx)
- self.splitMain.addWidget(self.treePane)
- self.splitMain.addWidget(self.mainStack)
- self.splitMain.setSizes(self.mainConf.getMainPanePos())
-
# Indices of Splitter Widgets
self.idxTree = self.splitMain.indexOf(self.treePane)
- self.idxMain = self.splitMain.indexOf(self.mainStack)
+ self.idxMain = self.splitMain.indexOf(self.splitDocs)
self.idxEditor = self.splitDocs.indexOf(self.docEditor)
self.idxViewer = self.splitDocs.indexOf(self.splitView)
self.idxViewDoc = self.splitView.indexOf(self.docViewer)
self.idxViewMeta = self.splitView.indexOf(self.viewMeta)
# Indices of Tab Widgets
- self.idxTabEdit = self.mainStack.indexOf(self.splitDocs)
- self.idxTabProj = self.mainStack.indexOf(self.splitOutline)
- self.idxTreeView = self.projStack.indexOf(self.treeView)
- self.idxNovelView = self.projStack.indexOf(self.novelView)
+ self.idxEditorView = self.mainStack.indexOf(self.splitMain)
+ self.idxOutlineView = self.mainStack.indexOf(self.splitOutline)
+ self.idxTreeView = self.projStack.indexOf(self.treeView)
+ self.idxNovelView = self.projStack.indexOf(self.novelView)
# Splitter Behaviour
self.splitMain.setCollapsible(self.idxTree, False)
@@ -205,7 +206,7 @@ class GuiMain(QMainWindow):
# Set Main Window Elements
self.setMenuBar(self.mainMenu)
- self.setCentralWidget(self.splitMain)
+ self.setCentralWidget(self.mainStack)
self.setStatusBar(self.statusBar)
self.addToolBar(Qt.LeftToolBarArea, self.viewsBar)
@@ -418,7 +419,7 @@ class GuiMain(QMainWindow):
self.theIndex.clearIndex()
self.clearGUI()
self.hasProject = False
- self.mainStack.setCurrentWidget(self.splitDocs)
+ self._changeView(nwView.PROJECT)
return saveOK
@@ -434,7 +435,7 @@ class GuiMain(QMainWindow):
return False
# Switch main tab to editor view
- self.mainStack.setCurrentWidget(self.splitDocs)
+ self._changeView(nwView.PROJECT)
# Try to open the project
if not self.theProject.openProject(projFile):
@@ -573,7 +574,7 @@ class GuiMain(QMainWindow):
return False
self.closeDocument()
- self.mainStack.setCurrentWidget(self.splitDocs)
+ self._changeView(nwView.EDITOR)
if self.docEditor.loadText(tHandle, tLine):
if changeFocus:
self.docEditor.setFocus()
@@ -656,7 +657,7 @@ class GuiMain(QMainWindow):
return False
# Make sure main tab is in Editor view
- self.mainStack.setCurrentWidget(self.splitDocs)
+ self._changeView(nwView.EDITOR)
logger.debug("Viewing document with handle '%s'", tHandle)
if self.docViewer.loadText(tHandle):
@@ -902,7 +903,7 @@ class GuiMain(QMainWindow):
return False
logger.verbose("Forcing a rebuild of the Project Outline")
- self.mainStack.setCurrentWidget(self.splitOutline)
+ self._changeView(nwView.OUTLINE)
self.projView.refreshTree(overRide=True)
return True
@@ -1221,13 +1222,13 @@ class GuiMain(QMainWindow):
elif tabIdx == self.idxNovelView:
self.novelView.setFocus()
elif paneNo == nwWidget.EDITOR:
- self.mainStack.setCurrentWidget(self.splitDocs)
+ self._changeView(nwView.EDITOR)
self.docEditor.setFocus()
elif paneNo == nwWidget.VIEWER:
- self.mainStack.setCurrentWidget(self.splitDocs)
+ self._changeView(nwView.EDITOR)
self.docViewer.setFocus()
elif paneNo == nwWidget.OUTLINE:
- self.mainStack.setCurrentWidget(self.splitOutline)
+ self._changeView(nwView.OUTLINE)
self.projView.setFocus()
return
@@ -1260,7 +1261,6 @@ class GuiMain(QMainWindow):
self.mainMenu.setFocusMode(self.isFocusMode)
if self.isFocusMode:
logger.debug("Activating Focus Mode")
- self.mainStack.setCurrentWidget(self.splitDocs)
self.switchFocus(nwWidget.EDITOR)
else:
logger.debug("Deactivating Focus Mode")
@@ -1487,12 +1487,16 @@ class GuiMain(QMainWindow):
def _changeView(self, view):
"""Handle the requested change of view from the GuiViewBar.
"""
- if view == nwView.PROJECT:
- self.mainStack.setCurrentWidget(self.splitDocs)
+ 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.treeView)
elif view == nwView.NOVEL:
- self.mainStack.setCurrentWidget(self.splitDocs)
+ self.mainStack.setCurrentWidget(self.splitMain)
self.projStack.setCurrentWidget(self.novelView)
elif view == nwView.OUTLINE:
@@ -1582,7 +1586,7 @@ class GuiMain(QMainWindow):
"""Triggered when there is a change to a novel item in the
project tree.
"""
- if self.mainStack.currentIndex() == self.idxTabProj:
+ if self.mainStack.currentIndex() == self.idxOutlineView:
logger.verbose("Novel tree changed while Outline tab active")
if self.hasProject:
self.treeView.flushTreeOrder()
@@ -1614,9 +1618,9 @@ class GuiMain(QMainWindow):
def _mainStackChanged(self, tabIndex):
"""Activated when the main window tab is changed.
"""
- if tabIndex == self.idxTabEdit:
+ if tabIndex == self.idxEditorView:
logger.verbose("Editor tab activated")
- elif tabIndex == self.idxTabProj:
+ elif tabIndex == self.idxOutlineView:
logger.verbose("Project outline tab activated")
if self.hasProject:
self.projView.refreshTree()
From 88cc4bd5a4f26afe57a98558a9617ccf46e5d44a Mon Sep 17 00:00:00 2001
From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com>
Date: Sat, 14 May 2022 19:00:47 +0200
Subject: [PATCH 4/6] Add new icons for the views bar
---
.../assets/icons/typicons_dark/icons.conf | 5 +++
.../icons/typicons_dark/typ_book-grey.svg | 31 +++++++++++++++++++
.../assets/icons/typicons_dark/typ_edit.svg | 31 +++++++++++++++++++
.../typicons_dark/typ_puzzle-outline.svg | 31 +++++++++++++++++++
.../assets/icons/typicons_light/icons.conf | 5 +++
.../icons/typicons_light/typ_book-grey.svg | 31 +++++++++++++++++++
.../assets/icons/typicons_light/typ_edit.svg | 31 +++++++++++++++++++
.../typicons_light/typ_puzzle-outline.svg | 31 +++++++++++++++++++
novelwriter/gui/theme.py | 22 ++++++-------
novelwriter/gui/viewsbar.py | 10 +++---
10 files changed, 211 insertions(+), 17 deletions(-)
create mode 100644 novelwriter/assets/icons/typicons_dark/typ_book-grey.svg
create mode 100644 novelwriter/assets/icons/typicons_dark/typ_edit.svg
create mode 100644 novelwriter/assets/icons/typicons_dark/typ_puzzle-outline.svg
create mode 100644 novelwriter/assets/icons/typicons_light/typ_book-grey.svg
create mode 100644 novelwriter/assets/icons/typicons_light/typ_edit.svg
create mode 100644 novelwriter/assets/icons/typicons_light/typ_puzzle-outline.svg
diff --git a/novelwriter/assets/icons/typicons_dark/icons.conf b/novelwriter/assets/icons/typicons_dark/icons.conf
index bcaef71a..ccc55222 100644
--- a/novelwriter/assets/icons/typicons_dark/icons.conf
+++ b/novelwriter/assets/icons/typicons_dark/icons.conf
@@ -49,10 +49,12 @@ hash = typ_hash.svg
maximise = typ_arrow-maximise.svg
minimise = typ_arrow-minimise.svg
proj_chapter = mixed_document-chapter.svg
+proj_details = typ_th-list-grey.svg
proj_document = typ_document-text.svg
proj_folder = typ_folder.svg
proj_note = mixed_document-note.svg
proj_scene = mixed_document-scene.svg
+proj_stats = typ_chart-bar-grey.svg
proj_title = mixed_document-title.svg
reference = typ_at.svg
refresh = typ_refresh.svg
@@ -76,3 +78,6 @@ status_time = typ_stopwatch-grey.svg
sticky-off = typ_pin-outline.svg
sticky-on = typ_pin.svg
up = typ_chevron-up.svg
+view_editor = typ_edit.svg
+view_novel = typ_book-grey.svg
+view_outline = typ_puzzle-outline.svg
diff --git a/novelwriter/assets/icons/typicons_dark/typ_book-grey.svg b/novelwriter/assets/icons/typicons_dark/typ_book-grey.svg
new file mode 100644
index 00000000..a0f49771
--- /dev/null
+++ b/novelwriter/assets/icons/typicons_dark/typ_book-grey.svg
@@ -0,0 +1,31 @@
+
+
diff --git a/novelwriter/assets/icons/typicons_dark/typ_edit.svg b/novelwriter/assets/icons/typicons_dark/typ_edit.svg
new file mode 100644
index 00000000..652dda33
--- /dev/null
+++ b/novelwriter/assets/icons/typicons_dark/typ_edit.svg
@@ -0,0 +1,31 @@
+
+
diff --git a/novelwriter/assets/icons/typicons_dark/typ_puzzle-outline.svg b/novelwriter/assets/icons/typicons_dark/typ_puzzle-outline.svg
new file mode 100644
index 00000000..526feec8
--- /dev/null
+++ b/novelwriter/assets/icons/typicons_dark/typ_puzzle-outline.svg
@@ -0,0 +1,31 @@
+
+
diff --git a/novelwriter/assets/icons/typicons_light/icons.conf b/novelwriter/assets/icons/typicons_light/icons.conf
index 8639908f..a26d18b4 100644
--- a/novelwriter/assets/icons/typicons_light/icons.conf
+++ b/novelwriter/assets/icons/typicons_light/icons.conf
@@ -49,10 +49,12 @@ hash = typ_hash.svg
maximise = typ_arrow-maximise.svg
minimise = typ_arrow-minimise.svg
proj_chapter = mixed_document-chapter.svg
+proj_details = typ_th-list-grey.svg
proj_document = typ_document-text.svg
proj_folder = typ_folder.svg
proj_note = mixed_document-note.svg
proj_scene = mixed_document-scene.svg
+proj_stats = typ_chart-bar-grey.svg
proj_title = mixed_document-title.svg
reference = typ_at.svg
refresh = typ_refresh.svg
@@ -76,3 +78,6 @@ status_time = typ_stopwatch-grey.svg
sticky-off = typ_pin-outline.svg
sticky-on = typ_pin.svg
up = typ_chevron-up.svg
+view_editor = typ_edit.svg
+view_novel = typ_book-grey.svg
+view_outline = typ_puzzle-outline.svg
diff --git a/novelwriter/assets/icons/typicons_light/typ_book-grey.svg b/novelwriter/assets/icons/typicons_light/typ_book-grey.svg
new file mode 100644
index 00000000..06f58ae1
--- /dev/null
+++ b/novelwriter/assets/icons/typicons_light/typ_book-grey.svg
@@ -0,0 +1,31 @@
+
+
diff --git a/novelwriter/assets/icons/typicons_light/typ_edit.svg b/novelwriter/assets/icons/typicons_light/typ_edit.svg
new file mode 100644
index 00000000..512c1592
--- /dev/null
+++ b/novelwriter/assets/icons/typicons_light/typ_edit.svg
@@ -0,0 +1,31 @@
+
+
diff --git a/novelwriter/assets/icons/typicons_light/typ_puzzle-outline.svg b/novelwriter/assets/icons/typicons_light/typ_puzzle-outline.svg
new file mode 100644
index 00000000..e2792d41
--- /dev/null
+++ b/novelwriter/assets/icons/typicons_light/typ_puzzle-outline.svg
@@ -0,0 +1,31 @@
+
+
diff --git a/novelwriter/gui/theme.py b/novelwriter/gui/theme.py
index 19fe823a..e3151ea8 100644
--- a/novelwriter/gui/theme.py
+++ b/novelwriter/gui/theme.py
@@ -456,20 +456,18 @@ class GuiIcons:
ICON_KEYS = {
# Project and GUI icons
- "novelwriter", "proj_nwx",
- "cls_none", "cls_novel", "cls_plot", "cls_character", "cls_world",
- "cls_timeline", "cls_object", "cls_entity", "cls_custom", "cls_archive", "cls_trash",
- "proj_document", "proj_title", "proj_chapter", "proj_scene", "proj_note", "proj_folder",
- "status_lang", "status_time", "status_idle", "status_stats", "status_lines",
- "doc_h0", "doc_h1", "doc_h2", "doc_h3", "doc_h4",
- "search_case", "search_regex", "search_word", "search_loop", "search_project",
- "search_cancel", "search_preserve",
+ "novelwriter", "cls_archive", "cls_character", "cls_custom", "cls_entity", "cls_none",
+ "cls_novel", "cls_object", "cls_plot", "cls_timeline", "cls_trash", "cls_world", "doc_h0",
+ "doc_h1", "doc_h2", "doc_h3", "doc_h4", "proj_chapter", "proj_details", "proj_document",
+ "proj_folder", "proj_note", "proj_nwx", "proj_scene", "proj_stats", "proj_title",
+ "search_cancel", "search_case", "search_loop", "search_preserve", "search_project",
+ "search_regex", "search_word", "status_idle", "status_lang", "status_lines",
+ "status_stats", "status_time", "view_editor", "view_novel", "view_outline",
# General Button Icons
- "delete", "close", "done", "clear", "save", "add", "remove",
- "search", "search_replace", "edit", "check", "cross", "hash",
- "maximise", "minimise", "refresh", "reference", "backward",
- "forward", "settings", "up", "down",
+ "add", "backward", "check", "clear", "close", "cross", "delete", "done", "down", "edit",
+ "forward", "hash", "maximise", "minimise", "reference", "refresh", "remove", "save",
+ "search_replace", "search", "settings", "up",
# Switches
"sticky-on", "sticky-off",
diff --git a/novelwriter/gui/viewsbar.py b/novelwriter/gui/viewsbar.py
index 71974357..92244781 100644
--- a/novelwriter/gui/viewsbar.py
+++ b/novelwriter/gui/viewsbar.py
@@ -64,23 +64,23 @@ class GuiViewsBar(QToolBar):
# Actions
self.aProject = QAction(self.tr("Project"))
- self.aProject.setIcon(self.theTheme.getIcon("proj_folder"))
+ self.aProject.setIcon(self.theTheme.getIcon("view_editor"))
self.aProject.triggered.connect(lambda: self.viewChangeRequested.emit(nwView.PROJECT))
self.aNovel = QAction(self.tr("Novel"))
- self.aNovel.setIcon(self.theTheme.getIcon("cls_novel"))
+ self.aNovel.setIcon(self.theTheme.getIcon("view_novel"))
self.aNovel.triggered.connect(lambda: self.viewChangeRequested.emit(nwView.NOVEL))
self.aOutline = QAction(self.tr("Outline"))
- self.aOutline.setIcon(self.theTheme.getIcon("cls_plot"))
+ self.aOutline.setIcon(self.theTheme.getIcon("view_outline"))
self.aOutline.triggered.connect(lambda: self.viewChangeRequested.emit(nwView.OUTLINE))
self.aDetails = QAction(self.tr("Details"))
- self.aDetails.setIcon(self.theTheme.getIcon("status_lines"))
+ self.aDetails.setIcon(self.theTheme.getIcon("proj_details"))
self.aDetails.triggered.connect(lambda: self.viewChangeRequested.emit(nwView.DETAILS))
self.aStats = QAction(self.tr("Stats"))
- self.aStats.setIcon(self.theTheme.getIcon("status_stats"))
+ self.aStats.setIcon(self.theTheme.getIcon("proj_stats"))
self.aStats.triggered.connect(lambda: self.viewChangeRequested.emit(nwView.STATS))
self.aSettings = QAction(self.tr("Settings"))
From 096c2dbc835188c42b2513fc3b043d9feea1ffae Mon Sep 17 00:00:00 2001
From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com>
Date: Sat, 14 May 2022 19:03:51 +0200
Subject: [PATCH 5/6] Add Typicons link to credits
---
CREDITS.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/CREDITS.md b/CREDITS.md
index e770434f..74089153 100644
--- a/CREDITS.md
+++ b/CREDITS.md
@@ -32,7 +32,7 @@ The following libraries are dependencies of novelWriter:
Some of the assets bundled with novelWriter were adapted from the following sources:
-* Typicons icons by Stephen Hutchings (CC BY-SA 4.0)
+* [Typicons](https://github.com/stephenhutchings/typicons.font) icons by Stephen Hutchings (CC BY-SA 4.0)
* Tomorrow syntax themes by Chris Kempson (MIT License)
* Owl syntax themes by Sarah Drasner (MIT License)
* Solarized themes by Ethan Schoonover, added by @nullbasis (MIT License)
From d965320b57c99e1cd0e3e28eb022e761ace70f47 Mon Sep 17 00:00:00 2001
From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com>
Date: Sat, 14 May 2022 19:07:34 +0200
Subject: [PATCH 6/6] Fix broken test
---
tests/test_gui/test_gui_outline.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tests/test_gui/test_gui_outline.py b/tests/test_gui/test_gui_outline.py
index 901a2bd2..40c58388 100644
--- a/tests/test_gui/test_gui_outline.py
+++ b/tests/test_gui/test_gui_outline.py
@@ -43,7 +43,7 @@ def testGuiOutline_Main(qtbot, monkeypatch, nwGUI, nwLipsum):
nwGUI.mainConf.lastPath = nwLipsum
nwGUI.rebuildIndex()
- nwGUI.mainStack.setCurrentIndex(nwGUI.idxTabProj)
+ nwGUI.mainStack.setCurrentIndex(nwGUI.idxOutlineView)
assert nwGUI.projView.topLevelItemCount() > 0