diff --git a/nw/assets/icons/fallback/reference-dark.svg b/nw/assets/icons/fallback/reference-dark.svg new file mode 100644 index 00000000..e57b19b0 --- /dev/null +++ b/nw/assets/icons/fallback/reference-dark.svg @@ -0,0 +1,31 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/nw/assets/icons/fallback/reference.svg b/nw/assets/icons/fallback/reference.svg new file mode 100644 index 00000000..09202533 --- /dev/null +++ b/nw/assets/icons/fallback/reference.svg @@ -0,0 +1,31 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/nw/assets/icons/fallback/sticky-off-dark.svg b/nw/assets/icons/fallback/sticky-off-dark.svg new file mode 100644 index 00000000..f571d5c9 --- /dev/null +++ b/nw/assets/icons/fallback/sticky-off-dark.svg @@ -0,0 +1,31 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/nw/assets/icons/fallback/sticky-off.svg b/nw/assets/icons/fallback/sticky-off.svg new file mode 100644 index 00000000..57b2b498 --- /dev/null +++ b/nw/assets/icons/fallback/sticky-off.svg @@ -0,0 +1,31 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/nw/assets/icons/fallback/sticky-on-dark.svg b/nw/assets/icons/fallback/sticky-on-dark.svg new file mode 100644 index 00000000..62c6a66b --- /dev/null +++ b/nw/assets/icons/fallback/sticky-on-dark.svg @@ -0,0 +1,31 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/nw/assets/icons/fallback/sticky-on.svg b/nw/assets/icons/fallback/sticky-on.svg new file mode 100644 index 00000000..3473b82f --- /dev/null +++ b/nw/assets/icons/fallback/sticky-on.svg @@ -0,0 +1,31 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/nw/assets/icons/typicons_colour_dark/bookmark.svg b/nw/assets/icons/typicons_colour_dark/bookmark.svg new file mode 100644 index 00000000..e56ebbee --- /dev/null +++ b/nw/assets/icons/typicons_colour_dark/bookmark.svg @@ -0,0 +1,31 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/nw/assets/icons/typicons_colour_dark/icons.conf b/nw/assets/icons/typicons_colour_dark/icons.conf index f55adaa9..3f8b547f 100644 --- a/nw/assets/icons/typicons_colour_dark/icons.conf +++ b/nw/assets/icons/typicons_colour_dark/icons.conf @@ -49,3 +49,6 @@ edit = pencil.svg check = tick.svg cross = times.svg hash = hash.svg +reference = bookmark.svg +sticky-on = pin.svg +sticky-off = pin-outline.svg diff --git a/nw/assets/icons/typicons_colour_dark/pin-outline.svg b/nw/assets/icons/typicons_colour_dark/pin-outline.svg new file mode 100644 index 00000000..478ff1a6 --- /dev/null +++ b/nw/assets/icons/typicons_colour_dark/pin-outline.svg @@ -0,0 +1,31 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/nw/assets/icons/typicons_colour_dark/pin.svg b/nw/assets/icons/typicons_colour_dark/pin.svg new file mode 100644 index 00000000..ea040440 --- /dev/null +++ b/nw/assets/icons/typicons_colour_dark/pin.svg @@ -0,0 +1,31 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/nw/assets/icons/typicons_colour_light/bookmark.svg b/nw/assets/icons/typicons_colour_light/bookmark.svg new file mode 100644 index 00000000..3936ba30 --- /dev/null +++ b/nw/assets/icons/typicons_colour_light/bookmark.svg @@ -0,0 +1,31 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/nw/assets/icons/typicons_colour_light/icons.conf b/nw/assets/icons/typicons_colour_light/icons.conf index af948e10..b080af1d 100644 --- a/nw/assets/icons/typicons_colour_light/icons.conf +++ b/nw/assets/icons/typicons_colour_light/icons.conf @@ -49,3 +49,6 @@ edit = pencil.svg check = tick.svg cross = times.svg hash = hash.svg +reference = bookmark.svg +sticky-on = pin.svg +sticky-off = pin-outline.svg diff --git a/nw/assets/icons/typicons_colour_light/pin-outline.svg b/nw/assets/icons/typicons_colour_light/pin-outline.svg new file mode 100644 index 00000000..9091424e --- /dev/null +++ b/nw/assets/icons/typicons_colour_light/pin-outline.svg @@ -0,0 +1,31 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/nw/assets/icons/typicons_colour_light/pin.svg b/nw/assets/icons/typicons_colour_light/pin.svg new file mode 100644 index 00000000..372928f7 --- /dev/null +++ b/nw/assets/icons/typicons_colour_light/pin.svg @@ -0,0 +1,31 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/nw/assets/icons/typicons_grey_dark/bookmark.svg b/nw/assets/icons/typicons_grey_dark/bookmark.svg new file mode 100644 index 00000000..e57b19b0 --- /dev/null +++ b/nw/assets/icons/typicons_grey_dark/bookmark.svg @@ -0,0 +1,31 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/nw/assets/icons/typicons_grey_dark/icons.conf b/nw/assets/icons/typicons_grey_dark/icons.conf index b8b24e46..0a68c931 100644 --- a/nw/assets/icons/typicons_grey_dark/icons.conf +++ b/nw/assets/icons/typicons_grey_dark/icons.conf @@ -49,3 +49,6 @@ edit = pencil.svg check = tick.svg cross = times.svg hash = hash.svg +reference = bookmark.svg +sticky-on = pin.svg +sticky-off = pin-outline.svg diff --git a/nw/assets/icons/typicons_grey_dark/pin-outline.svg b/nw/assets/icons/typicons_grey_dark/pin-outline.svg new file mode 100644 index 00000000..f571d5c9 --- /dev/null +++ b/nw/assets/icons/typicons_grey_dark/pin-outline.svg @@ -0,0 +1,31 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/nw/assets/icons/typicons_grey_dark/pin.svg b/nw/assets/icons/typicons_grey_dark/pin.svg new file mode 100644 index 00000000..62c6a66b --- /dev/null +++ b/nw/assets/icons/typicons_grey_dark/pin.svg @@ -0,0 +1,31 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/nw/assets/icons/typicons_grey_light/bookmark.svg b/nw/assets/icons/typicons_grey_light/bookmark.svg new file mode 100644 index 00000000..42556b6b --- /dev/null +++ b/nw/assets/icons/typicons_grey_light/bookmark.svg @@ -0,0 +1,31 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/nw/assets/icons/typicons_grey_light/icons.conf b/nw/assets/icons/typicons_grey_light/icons.conf index 9d99741c..2c019496 100644 --- a/nw/assets/icons/typicons_grey_light/icons.conf +++ b/nw/assets/icons/typicons_grey_light/icons.conf @@ -49,3 +49,6 @@ edit = pencil.svg check = tick.svg cross = times.svg hash = hash.svg +reference = bookmark.svg +sticky-on = pin.svg +sticky-off = pin-outline.svg diff --git a/nw/assets/icons/typicons_grey_light/pin-outline.svg b/nw/assets/icons/typicons_grey_light/pin-outline.svg new file mode 100644 index 00000000..57b2b498 --- /dev/null +++ b/nw/assets/icons/typicons_grey_light/pin-outline.svg @@ -0,0 +1,31 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/nw/assets/icons/typicons_grey_light/pin.svg b/nw/assets/icons/typicons_grey_light/pin.svg new file mode 100644 index 00000000..3473b82f --- /dev/null +++ b/nw/assets/icons/typicons_grey_light/pin.svg @@ -0,0 +1,31 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/nw/config.py b/nw/config.py index ca9cab7b..5c734981 100644 --- a/nw/config.py +++ b/nw/config.py @@ -96,6 +96,7 @@ class Config: self.projColWidth = [140, 55, 140] self.mainPanePos = [300, 800] self.docPanePos = [400, 400] + self.viewPanePos = [500, 150] self.outlnPanePos = [500, 150] self.isFullScreen = False @@ -363,6 +364,9 @@ class Config: self.docPanePos = self._parseLine( cnfParse, cnfSec, "docpane", self.CNF_LIST, self.docPanePos ) + self.viewPanePos = self._parseLine( + cnfParse, cnfSec, "viewpane", self.CNF_LIST, self.viewPanePos + ) self.outlnPanePos = self._parseLine( cnfParse, cnfSec, "outlinepane", self.CNF_LIST, self.outlnPanePos ) @@ -513,6 +517,7 @@ class Config: cnfParse.set(cnfSec,"projcols", self._packList(self.projColWidth)) cnfParse.set(cnfSec,"mainpane", self._packList(self.mainPanePos)) cnfParse.set(cnfSec,"docpane", self._packList(self.docPanePos)) + cnfParse.set(cnfSec,"viewpane", self._packList(self.viewPanePos)) cnfParse.set(cnfSec,"outlinepane", self._packList(self.outlnPanePos)) cnfParse.set(cnfSec,"fullscreen", str(self.isFullScreen)) @@ -730,6 +735,11 @@ class Config: self.confChanged = True return True + def setViewPanePos(self, panePos): + self.viewPanePos = [int(x/self.guiScale) for x in panePos] + self.confChanged = True + return True + def setOutlinePanePos(self, panePos): self.outlnPanePos = [int(x/self.guiScale) for x in panePos] self.confChanged = True @@ -770,6 +780,9 @@ class Config: def getDocPanePos(self): return [int(x*self.guiScale) for x in self.docPanePos] + def getViewPanePos(self): + return [int(x*self.guiScale) for x in self.viewPanePos] + def getOutlinePanePos(self): return [int(x*self.guiScale) for x in self.outlnPanePos] diff --git a/nw/core/options.py b/nw/core/options.py index 12593c0c..abab6a65 100644 --- a/nw/core/options.py +++ b/nw/core/options.py @@ -77,7 +77,7 @@ class OptionState(): "headerOrder", "columnWidth", "columnHidden", - ]) + ]), } return diff --git a/nw/core/project.py b/nw/core/project.py index 45480820..caa81b09 100644 --- a/nw/core/project.py +++ b/nw/core/project.py @@ -579,6 +579,7 @@ class NWProject(): def closeProject(self): """Close the current project and clear all meta data. """ + self.optState.saveSettings() self.projTree.writeToCFiles() self._appendSessionStats() self._clearLockFile() diff --git a/nw/gui/__init__.py b/nw/gui/__init__.py index 312744d6..4073dcc6 100644 --- a/nw/gui/__init__.py +++ b/nw/gui/__init__.py @@ -2,8 +2,7 @@ from nw.gui.about import GuiAbout from nw.gui.build import GuiBuildNovel -from nw.gui.docbars import GuiDocTitleBar, GuiSearchBar -from nw.gui.docdetails import GuiDocViewDetails +from nw.gui.docbars import GuiDocTitleBar, GuiSearchBar, GuiDocViewDetails from nw.gui.doceditor import GuiDocEditor from nw.gui.docmerge import GuiDocMerge from nw.gui.docsplit import GuiDocSplit diff --git a/nw/gui/docbars.py b/nw/gui/docbars.py index f35556df..839ae024 100644 --- a/nw/gui/docbars.py +++ b/nw/gui/docbars.py @@ -7,7 +7,9 @@ File History: Created: 2019-09-29 [0.2.1] GuiSearchBar + Created: 2019-10-31 [0.3.2] GuiDocViewDetails Created: 2020-04-25 [0.4.5] GuiDocTitleBar + Created: 2020-06-09 [0.8.0] GuiDocViewFooter This file is a part of novelWriter Copyright 2020, Veronica Berglyd Olsen @@ -30,10 +32,10 @@ import logging import nw from PyQt5.QtCore import Qt, QSize -from PyQt5.QtGui import QPalette, QColor +from PyQt5.QtGui import QPalette, QColor, QIcon from PyQt5.QtWidgets import ( qApp, QWidget, QFrame, QGridLayout, QLabel, QLineEdit, QPushButton, - QHBoxLayout, QToolButton + QHBoxLayout, QToolButton, QScrollArea ) from nw.constants import nwDocAction, nwUnicode @@ -170,14 +172,14 @@ class GuiSearchBar(QWidget): class GuiDocTitleBar(QWidget): - def __init__(self, theParent, theProject, isEditor): + def __init__(self, theParent, isEditor): QWidget.__init__(self, theParent) logger.debug("Initialising GuiDocTitleBar ...") self.mainConf = nw.CONFIG self.theParent = theParent - self.theProject = theProject + self.theProject = theParent.theProject self.theTheme = theParent.theTheme self.theHandle = None self.isEditor = isEditor @@ -351,3 +353,198 @@ class GuiDocTitleBar(QWidget): return # END Class GuiDocTitleBar + +class GuiDocViewFooter(QWidget): + + def __init__(self, theParent): + QWidget.__init__(self, theParent) + + logger.debug("Initialising GuiDocViewFooter ...") + + self.mainConf = nw.CONFIG + self.theParent = theParent + self.theTheme = theParent.theTheme + self.optState = theParent.theProject.optState + self.viewMeta = theParent.theParent.viewMeta + self.theHandle = None + + # Make a QPalette that matches the Syntax Theme + self.thePalette = QPalette() + self.thePalette.setColor(QPalette.Window, QColor(*self.theTheme.colBack)) + self.thePalette.setColor(QPalette.Text, QColor(*self.theTheme.colText)) + + fPx = int(0.9*self.theTheme.fontPixelSize) + hSp = self.mainConf.pxInt(6) + + # Main Widget Settings + self.setContentsMargins(0, 0, 0, 0) + self.setAutoFillBackground(True) + self.setPalette(self.thePalette) + + buttonStyle = ( + "QToolButton {{border: none; background: transparent;}} " + "QToolButton:hover {{border: none; background: rgba({0},{1},{2},0.2);}}" + ).format(*self.theTheme.colText) + + # Show/Hide Details + self.showHide = QToolButton(self) + self.showHide.setToolButtonStyle(Qt.ToolButtonIconOnly) + self.showHide.setStyleSheet(buttonStyle) + self.showHide.setIcon(self.theTheme.getIcon("reference")) + self.showHide.setIconSize(QSize(fPx, fPx)) + self.showHide.setFixedSize(QSize(fPx, fPx)) + self.showHide.clicked.connect(self._doShowHide) + + # Sticky Button + stickyOn = self.theTheme.getPixmap("sticky-on", (fPx, fPx)) + stickyOff = self.theTheme.getPixmap("sticky-off", (fPx, fPx)) + stickyIcon = QIcon() + stickyIcon.addPixmap(stickyOn, QIcon.Normal, QIcon.On) + stickyIcon.addPixmap(stickyOff, QIcon.Normal, QIcon.Off) + self.stickyRefs = QToolButton(self) + self.stickyRefs.setCheckable(True) + self.stickyRefs.setToolButtonStyle(Qt.ToolButtonIconOnly) + self.stickyRefs.setStyleSheet(buttonStyle) + self.stickyRefs.setIcon(stickyIcon) + self.stickyRefs.setIconSize(QSize(fPx, fPx)) + self.stickyRefs.setFixedSize(QSize(fPx, fPx)) + self.stickyRefs.toggled.connect(self._doToggleSticky) + + # Labels + self.lblRefs = QLabel("References") + self.lblRefs.setBuddy(self.showHide) + self.lblRefs.setIndent(0) + self.lblRefs.setMargin(0) + self.lblRefs.setContentsMargins(0, 0, 0, 0) + self.lblRefs.setAutoFillBackground(True) + self.lblRefs.setFixedHeight(fPx) + self.lblRefs.setAlignment(Qt.AlignLeft | Qt.AlignTop) + self.lblRefs.setPalette(self.thePalette) + + self.lblSticky = QLabel("Sticky") + self.lblSticky.setBuddy(self.stickyRefs) + self.lblSticky.setIndent(0) + self.lblSticky.setMargin(0) + self.lblSticky.setContentsMargins(0, 0, 0, 0) + self.lblSticky.setAutoFillBackground(True) + self.lblSticky.setFixedHeight(fPx) + self.lblSticky.setAlignment(Qt.AlignLeft | Qt.AlignTop) + self.lblSticky.setPalette(self.thePalette) + + lblFont = self.font() + lblFont.setPointSizeF(0.9*self.theTheme.fontPointSize) + self.lblRefs.setFont(lblFont) + self.lblSticky.setFont(lblFont) + + # Assemble Layout + self.outerBox = QHBoxLayout() + self.outerBox.setSpacing(hSp) + self.outerBox.addWidget(self.showHide, 0) + self.outerBox.addWidget(self.lblRefs, 0) + self.outerBox.addWidget(self.stickyRefs, 0) + self.outerBox.addWidget(self.lblSticky, 0) + self.outerBox.addStretch(1) + self.setLayout(self.outerBox) + + logger.debug("GuiDocViewFooter initialisation complete") + + return + + ## + # Slots + ## + + def _doShowHide(self): + """Toggle the expand/collapse of the panel. + """ + isVisible = self.viewMeta.isVisible() + self.viewMeta.setVisible(not isVisible) + return + + def _doToggleSticky(self, theState): + """Toggle the sticky flag for the reference panel. + """ + logger.verbose("Reference sticky is %s" % str(theState)) + self.theParent.stickyRef = theState + if not theState and self.theParent.theHandle is not None: + self.viewMeta.refreshReferences(self.theParent.theHandle) + return + +# END Class GuiDocViewFooter + +class GuiDocViewDetails(QScrollArea): + + def __init__(self, theParent): + QScrollArea.__init__(self, theParent) + + logger.debug("Initialising DocViewDetails ...") + self.mainConf = nw.CONFIG + self.theParent = theParent + self.theProject = theParent.theProject + self.theTheme = theParent.theTheme + self.currHandle = None + + self.refList = QLabel("None") + self.refList.setWordWrap(True) + self.refList.setAlignment(Qt.AlignTop) + self.refList.setScaledContents(True) + self.refList.linkActivated.connect(self._linkClicked) + + hCol = self.palette().highlight().color() + self.linkStyle = "style='color: rgb({0},{1},{2})'".format( + *self.theTheme.colLink + ) + + # Assemble + self.outerWidget = QWidget() + self.outerBox = QHBoxLayout() + self.outerBox.addWidget(self.refList, 1) + + self.outerWidget.setLayout(self.outerBox) + self.setWidget(self.outerWidget) + + self.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded) + self.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded) + self.setWidgetResizable(True) + self.setMinimumHeight(self.mainConf.pxInt(50)) + + logger.debug("DocViewDetails initialisation complete") + + return + + def refreshReferences(self, tHandle): + """Update the current list of document references from the + project index. + """ + self.currHandle = tHandle + if self.theParent.docViewer.stickyRef: + return + + theRefs = self.theParent.theIndex.getBackReferenceList(tHandle) + theList = [] + for tHandle in theRefs: + tItem = self.theProject.projTree[tHandle] + if tItem is not None: + theList.append("%s" % ( + tHandle, theRefs[tHandle], self.linkStyle, tItem.itemName + )) + + self.refList.setText(", ".join(theList)) + + return + + ## + # Internal Functions + ## + + def _linkClicked(self, theLink): + """Capture the link-click and forward it to the document viewer + class for handling. + """ + logger.verbose("Clicked link: '%s'" % theLink) + if len(theLink) == 27: + tHandle = theLink[6:19] + self.theParent.viewDocument(tHandle, theLink) + return + +# END Class GuiDocViewDetails diff --git a/nw/gui/docdetails.py b/nw/gui/docdetails.py deleted file mode 100644 index 7c4ec8f7..00000000 --- a/nw/gui/docdetails.py +++ /dev/null @@ -1,156 +0,0 @@ -# -*- coding: utf-8 -*- -"""novelWriter GUI DocView Details - - novelWriter – GUI DocView Details -=================================== - Class holding the document view details panel - - File History: - Created: 2019-10-31 [0.3.2] - - This file is a part of novelWriter - Copyright 2020, 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 nw - -from PyQt5.QtCore import Qt, QSize -from PyQt5.QtWidgets import ( - QWidget, QLabel, QScrollArea, QFrame, QToolButton, QCheckBox, QGridLayout -) - -logger = logging.getLogger(__name__) - -class GuiDocViewDetails(QWidget): - - def __init__(self, theParent): - QWidget.__init__(self, theParent) - - logger.debug("Initialising DocViewDetails ...") - self.mainConf = nw.CONFIG - self.theParent = theParent - self.theProject = theParent.theProject - self.theTheme = theParent.theTheme - self.currHandle = None - - x4 = self.mainConf.pxInt(4) - x80 = self.mainConf.pxInt(80) - iPx = self.theTheme.textIconSize - - self.outerBox = QGridLayout(self) - self.outerBox.setContentsMargins(0, 0, 0, 0) - self.outerBox.setHorizontalSpacing(0) - self.outerBox.setVerticalSpacing(x4) - - self.refLabel = QLabel("Referenced By", self) - - self.showHide = QToolButton() - self.showHide.setStyleSheet("QToolButton { border: none; }") - self.showHide.setToolButtonStyle(Qt.ToolButtonIconOnly) - self.showHide.setArrowType(Qt.DownArrow) - self.showHide.setCheckable(True) - self.showHide.setIconSize(QSize(iPx, iPx)) - self.showHide.toggled.connect(self._doShowHide) - - self.isSticky = QCheckBox("Sticky") - self.isSticky.setChecked(False) - self.isSticky.toggled.connect(self._doSticky) - - self.refList = QLabel("None") - self.refList.setWordWrap(True) - self.refList.setAlignment(Qt.AlignTop) - self.refList.setScaledContents(True) - self.refList.linkActivated.connect(self._linkClicked) - - self.scrollBox = QScrollArea() - self.scrollBox.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) - self.scrollBox.setFrameStyle(QFrame.NoFrame) - self.scrollBox.setWidgetResizable(True) - self.scrollBox.setFixedHeight(x80) - self.scrollBox.setWidget(self.refList) - - self.outerBox.addWidget(self.showHide, 0, 0) - self.outerBox.addWidget(self.refLabel, 0, 1) - self.outerBox.addWidget(self.isSticky, 0, 2) - self.outerBox.addWidget(self.scrollBox, 1, 1, 1, 2) - self.outerBox.setColumnStretch(1, 1) - - self.setLayout(self.outerBox) - self.setContentsMargins(0, 0, 0, 0) - - self._doShowHide(self.mainConf.showRefPanel) - - logger.debug("DocViewDetails initialisation complete") - - return - - def refreshReferences(self, tHandle): - """Update the current list of document references from the - project index. - """ - self.currHandle = tHandle - - if self.isSticky.isChecked(): - return - - theRefs = self.theParent.theIndex.getBackReferenceList(tHandle) - theList = [] - for tHandle in theRefs: - tItem = self.theProject.projTree[tHandle] - if tItem is not None: - theList.append("%s" % ( - tHandle, theRefs[tHandle], tItem.itemName - )) - - self.refList.setText(", ".join(theList)) - self.refList.adjustSize() - - return - - ## - # Internal Functions - ## - - def _linkClicked(self, theLink): - """Capture the link-click and forward it to the document viewer - class for handling. - """ - logger.verbose("Clicked link: '%s'" % theLink) - if len(theLink) == 27: - tHandle = theLink[6:19] - self.theParent.viewDocument(tHandle, theLink) - return - - def _doShowHide(self, chState): - """Toggle the expand/collapse of the panel. - """ - self.scrollBox.setVisible(chState) - self.mainConf.setShowRefPanel(chState) - if chState: - self.showHide.setArrowType(Qt.DownArrow) - else: - self.showHide.setArrowType(Qt.RightArrow) - return - - def _doSticky(self, chState): - """Toggle the sticky feature of the references. - """ - if not chState and self.currHandle is not None: - self.refreshReferences(self.currHandle) - return - -# END Class GuiDocViewDetails diff --git a/nw/gui/doceditor.py b/nw/gui/doceditor.py index 81c37e04..d3b6eb93 100644 --- a/nw/gui/doceditor.py +++ b/nw/gui/doceditor.py @@ -85,7 +85,7 @@ class GuiDocEditor(QTextEdit): self.qDocument.contentsChange.connect(self._docChange) # Document Title - self.docTitle = GuiDocTitleBar(self, self.theProject, isEditor=True) + self.docTitle = GuiDocTitleBar(self, isEditor=True) self.docTitle.setGeometry(0, 0, self.docTitle.width(), self.docTitle.height()) self.setViewportMargins(0, self.docTitle.height(), 0, 0) diff --git a/nw/gui/docviewer.py b/nw/gui/docviewer.py index c43c6cc0..0648111b 100644 --- a/nw/gui/docviewer.py +++ b/nw/gui/docviewer.py @@ -34,7 +34,7 @@ from PyQt5.QtGui import QTextOption, QFont, QPalette, QColor, QTextCursor from nw.core import ToHtml from nw.constants import nwAlert, nwItemType, nwDocAction -from nw.gui.docbars import GuiDocTitleBar +from nw.gui.docbars import GuiDocTitleBar, GuiDocViewFooter logger = logging.getLogger(__name__) @@ -57,10 +57,10 @@ class GuiDocViewer(QTextBrowser): self.setOpenExternalLinks(False) self.initViewer() - # Document Title - self.docTitle = GuiDocTitleBar(self, self.theProject, isEditor=False) - self.docTitle.setGeometry(0, 0, self.docTitle.width(), self.docTitle.height()) - self.setViewportMargins(0, self.docTitle.height(), 0, 0) + # Document Title and Footer + self.docTitle = GuiDocTitleBar(self, isEditor=False) + self.docFooter = GuiDocViewFooter(self) + self.stickyRef = False theOpt = QTextOption() if self.mainConf.doJustify: @@ -233,15 +233,17 @@ class GuiDocViewer(QTextBrowser): tB = self.lineWidth() tW = self.width() - 2*tB - sW tH = self.docTitle.height() + fH = self.docFooter.height() + fY = self.height() - fH - tB tT = self.mainConf.getTextMargin() - tH + bT = self.mainConf.getTextMargin() - fH self.docTitle.setGeometry(tB, tB, tW, tH) - self.setViewportMargins(0, tH, 0, 0) + self.docFooter.setGeometry(tB, fY, tW, fH) + self.setViewportMargins(0, tH, 0, fH) docFormat = self.qDocument.rootFrame().frameFormat() - if tT > 0: - docFormat.setTopMargin(tT) - else: - docFormat.setTopMargin(0) + docFormat.setTopMargin(max(0, tT)) + docFormat.setBottomMargin(max(0, bT)) self.qDocument.blockSignals(True) self.qDocument.rootFrame().setFrameFormat(docFormat) diff --git a/nw/gui/outlinedetails.py b/nw/gui/outlinedetails.py index 739b1c37..9a010559 100644 --- a/nw/gui/outlinedetails.py +++ b/nw/gui/outlinedetails.py @@ -216,11 +216,9 @@ class GuiOutlineDetails(QScrollArea): self.outerBox = QHBoxLayout() self.outerBox.addWidget(self.mainGroup, 0) self.outerBox.addWidget(self.tagsGroup, 1) - # self.outerBox.addStretch(1) self.outerWidget.setLayout(self.outerBox) self.setWidget(self.outerWidget) - self.show() self.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded) self.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded) diff --git a/nw/gui/theme.py b/nw/gui/theme.py index 08b18691..78b2b44d 100644 --- a/nw/gui/theme.py +++ b/nw/gui/theme.py @@ -537,6 +537,9 @@ class GuiIcons: "maximise" : (None, None), "minimise" : (None, None), "refresh" : (None, None), + "reference" : (None, None), + "sticky-on" : (None, None), + "sticky-off" : (None, None), ## Other Icons "warning" : (QStyle.SP_MessageBoxWarning, "dialog-warning"), diff --git a/nw/guimain.py b/nw/guimain.py index 84dfbd21..e34ff448 100644 --- a/nw/guimain.py +++ b/nw/guimain.py @@ -92,8 +92,8 @@ class GuiMain(QMainWindow): self.statusBar = GuiMainStatus(self) self.treeView = GuiProjectTree(self) self.docEditor = GuiDocEditor(self) - self.docViewer = GuiDocViewer(self) self.viewMeta = GuiDocViewDetails(self) + self.docViewer = GuiDocViewer(self) self.searchBar = GuiSearchBar(self) self.treeMeta = GuiItemDetails(self) self.projView = GuiOutline(self) @@ -120,19 +120,15 @@ class GuiMain(QMainWindow): self.docEdit.addWidget(self.docEditor) self.editPane.setLayout(self.docEdit) - self.viewPane = QWidget() - self.docView = QVBoxLayout() - self.docView.setContentsMargins(0, 0, 0, 0) - self.docView.setSpacing(self.mainConf.pxInt(2)) - self.docView.addWidget(self.docViewer) - self.docView.addWidget(self.viewMeta) - self.docView.setStretch(0, 1) - self.viewPane.setLayout(self.docView) + self.splitView = QSplitter(Qt.Vertical) + self.splitView.addWidget(self.docViewer) + self.splitView.addWidget(self.viewMeta) + self.splitView.setSizes(self.mainConf.getViewPanePos()) - self.splitView = QSplitter(Qt.Horizontal) - self.splitView.setOpaqueResize(False) - self.splitView.addWidget(self.editPane) - self.splitView.addWidget(self.viewPane) + self.splitDocs = QSplitter(Qt.Horizontal) + self.splitDocs.setOpaqueResize(False) + self.splitDocs.addWidget(self.editPane) + self.splitDocs.addWidget(self.splitView) self.splitOutline = QSplitter(Qt.Vertical) self.splitOutline.addWidget(self.projView) @@ -142,7 +138,7 @@ class GuiMain(QMainWindow): self.tabWidget = QTabWidget() self.tabWidget.setTabPosition(QTabWidget.East) self.tabWidget.setStyleSheet("QTabWidget::pane {border: 0;}") - self.tabWidget.addTab(self.splitView, "Editor") + self.tabWidget.addTab(self.splitDocs, "Editor") self.tabWidget.addTab(self.splitOutline, "Outline") self.tabWidget.currentChanged.connect(self._mainTabChanged) @@ -156,20 +152,23 @@ class GuiMain(QMainWindow): self.setCentralWidget(self.splitMain) - self.idxTree = self.splitMain.indexOf(self.treePane) - self.idxMain = self.splitMain.indexOf(self.tabWidget) - self.idxEditor = self.splitView.indexOf(self.editPane) - self.idxViewer = self.splitView.indexOf(self.viewPane) - - self.idxTabEdit = self.tabWidget.indexOf(self.splitView) - self.idxTabProj = self.tabWidget.indexOf(self.splitOutline) + self.idxTree = self.splitMain.indexOf(self.treePane) + self.idxMain = self.splitMain.indexOf(self.tabWidget) + self.idxEditor = self.splitDocs.indexOf(self.editPane) + self.idxViewer = self.splitDocs.indexOf(self.splitView) + self.idxViewDoc = self.splitView.indexOf(self.docViewer) + self.idxViewMeta = self.splitView.indexOf(self.viewMeta) + self.idxTabEdit = self.tabWidget.indexOf(self.splitDocs) + self.idxTabProj = self.tabWidget.indexOf(self.splitOutline) self.splitMain.setCollapsible(self.idxTree, False) self.splitMain.setCollapsible(self.idxMain, False) - self.splitView.setCollapsible(self.idxEditor, False) - self.splitView.setCollapsible(self.idxViewer, True) + self.splitDocs.setCollapsible(self.idxEditor, False) + self.splitDocs.setCollapsible(self.idxViewer, True) + self.splitView.setCollapsible(self.idxViewDoc, False) + self.splitView.setCollapsible(self.idxViewMeta, False) - self.viewPane.setVisible(False) + self.splitView.setVisible(False) self.searchBar.setVisible(False) # Build the Tree View @@ -353,7 +352,7 @@ class GuiMain(QMainWindow): self.theIndex.clearIndex() self.clearGUI() self.hasProject = False - self.tabWidget.setCurrentWidget(self.splitView) + self.tabWidget.setCurrentWidget(self.splitDocs) return saveOK @@ -371,7 +370,7 @@ class GuiMain(QMainWindow): return False # Switch main tab to editor view - self.tabWidget.setCurrentWidget(self.splitView) + self.tabWidget.setCurrentWidget(self.splitDocs) # Try to open the project if not self.theProject.openProject(projFile): @@ -475,7 +474,7 @@ class GuiMain(QMainWindow): """ if self.hasProject: self.closeDocument() - self.tabWidget.setCurrentWidget(self.splitView) + self.tabWidget.setCurrentWidget(self.splitDocs) if self.docEditor.loadText(tHandle, tLine): if changeFocus: self.docEditor.setFocus() @@ -508,16 +507,17 @@ class GuiMain(QMainWindow): return False # Make sure main tab is in Editor view - self.tabWidget.setCurrentWidget(self.splitView) + self.tabWidget.setCurrentWidget(self.splitDocs) if self.docViewer.loadText(tHandle): - if not self.viewPane.isVisible(): + if not self.splitView.isVisible(): bPos = self.splitMain.sizes() - self.viewPane.setVisible(True) + self.splitView.setVisible(True) vPos = [0, 0] vPos[0] = int(bPos[1]/2) vPos[1] = bPos[1] - vPos[0] - self.splitView.setSizes(vPos) + self.splitDocs.setSizes(vPos) + self.viewMeta.setVisible(self.mainConf.showRefPanel) self.docViewer.navigateTo(navLink) return True @@ -842,16 +842,22 @@ class GuiMain(QMainWindow): return False logger.info("Exiting %s" % nw.__package__) - if self.hasProject: - self.closeProject(True) + if not self.isZenMode: + self.mainConf.setMainPanePos(self.splitMain.sizes()) + self.mainConf.setDocPanePos(self.splitDocs.sizes()) + self.mainConf.setOutlinePanePos(self.splitOutline.sizes()) + if self.viewMeta.isVisible(): + self.mainConf.setViewPanePos(self.splitView.sizes()) + + self.mainConf.setShowRefPanel(self.viewMeta.isVisible()) self.mainConf.setTreeColWidths(self.treeView.getColumnSizes()) if not self.mainConf.isFullScreen: self.mainConf.setWinSize(self.width(), self.height()) - if not self.isZenMode: - self.mainConf.setMainPanePos(self.splitMain.sizes()) - self.mainConf.setDocPanePos(self.splitView.sizes()) - self.mainConf.setOutlinePanePos(self.splitOutline.sizes()) + + if self.hasProject: + self.closeProject(True) + self.mainConf.saveConfig() self.reportConfErr() @@ -874,13 +880,15 @@ class GuiMain(QMainWindow): return def closeDocViewer(self): + """Close the document view panel. + """ self.docViewer.clearViewer() self.theProject.setLastViewed(None) bPos = self.splitMain.sizes() - self.viewPane.setVisible(False) + self.splitView.setVisible(False) vPos = [bPos[1], 0] - self.splitView.setSizes(vPos) - return not self.viewPane.isVisible() + self.splitDocs.setSizes(vPos) + return not self.splitView.isVisible() def toggleZenMode(self): """Main GUI Zen Mode hides tree, view pane and optionally also @@ -893,7 +901,7 @@ class GuiMain(QMainWindow): self.isZenMode = not self.isZenMode if self.isZenMode: logger.debug("Activating Zen mode") - self.tabWidget.setCurrentWidget(self.splitView) + self.tabWidget.setCurrentWidget(self.splitDocs) else: logger.debug("Deactivating Zen mode") @@ -903,10 +911,10 @@ class GuiMain(QMainWindow): self.mainMenu.setVisible(isVisible) self.tabWidget.tabBar().setVisible(isVisible) - if self.viewPane.isVisible(): - self.viewPane.setVisible(False) + if self.splitView.isVisible(): + self.splitView.setVisible(False) elif self.docViewer.theHandle is not None: - self.viewPane.setVisible(True) + self.splitView.setVisible(True) return True diff --git a/tests/reference/novelwriter.conf b/tests/reference/novelwriter.conf index 2ecde509..bafeaaed 100644 --- a/tests/reference/novelwriter.conf +++ b/tests/reference/novelwriter.conf @@ -1,5 +1,5 @@ [Main] -timestamp = 2020-06-03 20:42:03 +timestamp = 2020-06-09 23:05:17 theme = default syntax = default_light icons = typicons_colour_light @@ -13,6 +13,7 @@ treecols = 120, 30, 50 projcols = 140, 55, 140 mainpane = 300, 800 docpane = 400, 400 +viewpane = 500, 150 outlinepane = 500, 150 fullscreen = False