From 4d7ef63e8370624fc55ca1087bbf0b410a492646 Mon Sep 17 00:00:00 2001 From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com> Date: Tue, 14 Nov 2023 22:41:39 +0100 Subject: [PATCH] Connect the new viewer panel and add icon for it --- .../assets/icons/typicons_dark/icons.conf | 2 +- .../assets/icons/typicons_dark/nw_panel.svg | 4 + .../assets/icons/typicons_dark/typ_at.svg | 4 - .../assets/icons/typicons_light/icons.conf | 2 +- .../assets/icons/typicons_light/nw_panel.svg | 4 + .../assets/icons/typicons_light/typ_at.svg | 4 - novelwriter/config.py | 8 +- novelwriter/constants.py | 17 +- novelwriter/gui/docviewer.py | 284 ++++-------------- novelwriter/gui/docviewerpanel.py | 72 ++++- novelwriter/gui/theme.py | 4 +- novelwriter/guimain.py | 54 ++-- 12 files changed, 184 insertions(+), 275 deletions(-) create mode 100644 novelwriter/assets/icons/typicons_dark/nw_panel.svg delete mode 100644 novelwriter/assets/icons/typicons_dark/typ_at.svg create mode 100644 novelwriter/assets/icons/typicons_light/nw_panel.svg delete mode 100644 novelwriter/assets/icons/typicons_light/typ_at.svg diff --git a/novelwriter/assets/icons/typicons_dark/icons.conf b/novelwriter/assets/icons/typicons_dark/icons.conf index 94b4c633..c51b2457 100644 --- a/novelwriter/assets/icons/typicons_dark/icons.conf +++ b/novelwriter/assets/icons/typicons_dark/icons.conf @@ -59,6 +59,7 @@ maximise = typ_arrow-maximise.svg menu = typ_th-dot-menu.svg minimise = typ_arrow-minimise.svg noncheckable = mixed_input-none.svg +panel = nw_panel.svg proj_chapter = mixed_document-chapter.svg proj_details = typ_th-list-grey.svg proj_document = typ_document-text.svg @@ -68,7 +69,6 @@ proj_scene = mixed_document-scene.svg proj_section = mixed_document-section.svg proj_stats = typ_chart-bar-grey.svg proj_title = mixed_document-title.svg -reference = typ_at.svg refresh = typ_refresh.svg remove = typ_minus.svg revert = typ_refresh-flipped.svg diff --git a/novelwriter/assets/icons/typicons_dark/nw_panel.svg b/novelwriter/assets/icons/typicons_dark/nw_panel.svg new file mode 100644 index 00000000..2863918f --- /dev/null +++ b/novelwriter/assets/icons/typicons_dark/nw_panel.svg @@ -0,0 +1,4 @@ + + + + diff --git a/novelwriter/assets/icons/typicons_dark/typ_at.svg b/novelwriter/assets/icons/typicons_dark/typ_at.svg deleted file mode 100644 index 9966ede0..00000000 --- a/novelwriter/assets/icons/typicons_dark/typ_at.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/novelwriter/assets/icons/typicons_light/icons.conf b/novelwriter/assets/icons/typicons_light/icons.conf index 62314511..5f300ad2 100644 --- a/novelwriter/assets/icons/typicons_light/icons.conf +++ b/novelwriter/assets/icons/typicons_light/icons.conf @@ -59,6 +59,7 @@ maximise = typ_arrow-maximise.svg menu = typ_th-dot-menu.svg minimise = typ_arrow-minimise.svg noncheckable = mixed_input-none.svg +panel = nw_panel.svg proj_chapter = mixed_document-chapter.svg proj_details = typ_th-list-grey.svg proj_document = typ_document-text.svg @@ -68,7 +69,6 @@ proj_scene = mixed_document-scene.svg proj_section = mixed_document-section.svg proj_stats = typ_chart-bar-grey.svg proj_title = mixed_document-title.svg -reference = typ_at.svg refresh = typ_refresh.svg remove = typ_minus.svg revert = typ_refresh-flipped.svg diff --git a/novelwriter/assets/icons/typicons_light/nw_panel.svg b/novelwriter/assets/icons/typicons_light/nw_panel.svg new file mode 100644 index 00000000..c78ab50b --- /dev/null +++ b/novelwriter/assets/icons/typicons_light/nw_panel.svg @@ -0,0 +1,4 @@ + + + + diff --git a/novelwriter/assets/icons/typicons_light/typ_at.svg b/novelwriter/assets/icons/typicons_light/typ_at.svg deleted file mode 100644 index 0578267f..00000000 --- a/novelwriter/assets/icons/typicons_light/typ_at.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/novelwriter/config.py b/novelwriter/config.py index bc8af368..08230fba 100644 --- a/novelwriter/config.py +++ b/novelwriter/config.py @@ -179,9 +179,9 @@ class Config: self.spellLanguage = "en" # State - self.showRefPanel = True # The reference panel for the viewer is visible + self.showViewerPanel = True # The panel for the viewer is visible self.showEditToolBar = False # The document editor toolbar visibility - self.useShortcodes = False # Use shorcodes for basic formatting + self.useShortcodes = False # Use shortcodes for basic formatting self.viewComments = True # Comments are shown in the viewer self.viewSynopsis = True # Synopsis is shown in the viewer @@ -602,7 +602,7 @@ class Config: # State sec = "State" - self.showRefPanel = conf.rdBool(sec, "showrefpanel", self.showRefPanel) + self.showViewerPanel = conf.rdBool(sec, "showviewerpanel", self.showViewerPanel) self.showEditToolBar = conf.rdBool(sec, "showedittoolbar", self.showEditToolBar) self.useShortcodes = conf.rdBool(sec, "useshortcodes", self.useShortcodes) self.viewComments = conf.rdBool(sec, "viewcomments", self.viewComments) @@ -727,7 +727,7 @@ class Config: } conf["State"] = { - "showrefpanel": str(self.showRefPanel), + "showviewerpanel": str(self.showViewerPanel), "showedittoolbar": str(self.showEditToolBar), "useshortcodes": str(self.useShortcodes), "viewcomments": str(self.viewComments), diff --git a/novelwriter/constants.py b/novelwriter/constants.py index 514ea9f2..d8ce3562 100644 --- a/novelwriter/constants.py +++ b/novelwriter/constants.py @@ -153,6 +153,21 @@ class nwKeyWords: # END Class nwKeyWords +class nwLists: + + USER_CLASSES = [ + nwItemClass.CHARACTER, + nwItemClass.PLOT, + nwItemClass.WORLD, + nwItemClass.TIMELINE, + nwItemClass.OBJECT, + nwItemClass.ENTITY, + nwItemClass.CUSTOM, + ] + +# END Class nwLists + + class nwLabels: CLASS_NAME = { @@ -221,8 +236,8 @@ class nwLabels: nwOutline.FOCUS: QT_TRANSLATE_NOOP("Constant", "Focus"), nwOutline.CHAR: KEY_NAME[nwKeyWords.CHAR_KEY], nwOutline.PLOT: KEY_NAME[nwKeyWords.PLOT_KEY], - nwOutline.TIME: KEY_NAME[nwKeyWords.TIME_KEY], nwOutline.WORLD: KEY_NAME[nwKeyWords.WORLD_KEY], + nwOutline.TIME: KEY_NAME[nwKeyWords.TIME_KEY], nwOutline.OBJECT: KEY_NAME[nwKeyWords.OBJECT_KEY], nwOutline.ENTITY: KEY_NAME[nwKeyWords.ENTITY_KEY], nwOutline.CUSTOM: KEY_NAME[nwKeyWords.CUSTOM_KEY], diff --git a/novelwriter/gui/docviewer.py b/novelwriter/gui/docviewer.py index ff548fb6..5376a872 100644 --- a/novelwriter/gui/docviewer.py +++ b/novelwriter/gui/docviewer.py @@ -4,7 +4,6 @@ novelWriter – GUI Document Viewer File History: Created: 2019-05-10 [0.0.1] GuiDocViewer -Created: 2019-10-31 [0.3.2] GuiDocViewDetails Created: 2020-04-25 [0.4.5] GuiDocViewHeader Created: 2020-06-09 [0.8] GuiDocViewFooter Created: 2020-09-08 [1.0b1] GuiDocViewHistory @@ -38,8 +37,8 @@ from PyQt5.QtGui import ( QTextOption ) from PyQt5.QtWidgets import ( - QAction, qApp, QFrame, QHBoxLayout, QLabel, QMenu, QScrollArea, - QTextBrowser, QToolButton, QWidget + QAction, qApp, QFrame, QHBoxLayout, QLabel, QMenu, QTextBrowser, + QToolButton, QWidget ) from novelwriter import CONFIG, SHARED @@ -58,6 +57,7 @@ logger = logging.getLogger(__name__) class GuiDocViewer(QTextBrowser): loadDocumentTagRequest = pyqtSignal(str, Enum) + togglePanelVisibility = pyqtSignal() def __init__(self, mainGui: GuiMain) -> None: super().__init__(parent=mainGui) @@ -242,7 +242,7 @@ class GuiDocViewer(QTextBrowser): self.updateDocMargins() # Make sure the main GUI knows we changed the content - self.mainGui.viewMeta.refreshReferences(tHandle) + # self.mainGui.viewMeta.refreshReferences(tHandle) # Since we change the content while it may still be rendering, we mark # the document dirty again to make sure it's re-rendered properly. @@ -342,7 +342,7 @@ class GuiDocViewer(QTextBrowser): @pyqtSlot(str) def updateDocInfo(self, tHandle: str) -> None: - """Update the header titlebar if needed.""" + """Update the header title bar if needed.""" if tHandle == self._docHandle: self.docHeader.setTitleFromHandle(self._docHandle) self.updateDocMargins() @@ -530,20 +530,16 @@ class GuiDocViewer(QTextBrowser): class GuiDocViewHistory: - def __init__(self, docViewer): - + def __init__(self, docViewer: GuiDocViewer) -> None: self.docViewer = docViewer - self._navHistory = [] self._posHistory = [] self._currPos = -1 self._prevPos = -1 - return - def clear(self): - """Clear the view history. - """ + def clear(self) -> None: + """Clear the view history.""" logger.debug("View history cleared") self._navHistory = [] self._posHistory = [] @@ -551,7 +547,7 @@ class GuiDocViewHistory: self._prevPos = -1 return - def append(self, tHandle): + def append(self, tHandle: str) -> bool: """Append a document handle and its scroll bar position to the history, but only if the document is different than the current active entry. Any further entries are truncated. @@ -577,74 +573,61 @@ class GuiDocViewHistory: return True - def forward(self): - """Navigate to the next entry in the view history. - """ + def forward(self) -> None: + """Navigate to the next entry in the view history.""" newPos = self._currPos + 1 if newPos < len(self._navHistory): logger.debug("Move forward in view history") self._prevPos = self._currPos self._updateScrollBar() - self.docViewer.loadText(self._navHistory[newPos], updateHistory=False) self.docViewer.setScrollPosition(self._posHistory[newPos]) self._currPos = newPos self._updateNavButtons() - self._dumpHistory() - return - def backward(self): - """Navigate to the previous entry in the view history. - """ + def backward(self) -> None: + """Navigate to the previous entry in the view history.""" newPos = self._currPos - 1 if newPos >= 0: logger.debug("Move backward in view history") self._prevPos = self._currPos self._updateScrollBar() - self.docViewer.loadText(self._navHistory[newPos], updateHistory=False) self.docViewer.setScrollPosition(self._posHistory[newPos]) self._currPos = newPos self._updateNavButtons() - self._dumpHistory() - return ## # Internal Functions ## - def _updateScrollBar(self): - """Update the scrollbar position of the previous entry. - """ + def _updateScrollBar(self) -> None: + """Update the scrollbar position of the previous entry.""" if self._prevPos >= 0 and self._prevPos < len(self._posHistory): self._posHistory[self._prevPos] = self.docViewer.scrollPosition return - def _updateNavButtons(self): - """Update the navigation buttons in the document header. - """ + def _updateNavButtons(self) -> None: + """Update the navigation buttons in the document header.""" self.docViewer.docHeader.updateNavButtons(0, len(self._navHistory) - 1, self._currPos) return - def _truncateHistory(self, atPos): + def _truncateHistory(self, atPos: int) -> None: """Truncate the navigation history to the given position. Also enforces a maximum length of the navigation history to 20. """ nSkip = 1 if atPos > 19 else 0 - self._navHistory = self._navHistory[nSkip:atPos + 1] self._posHistory = self._posHistory[nSkip:atPos + 1] - self._currPos -= nSkip self._prevPos -= nSkip - return - def _dumpHistory(self): + def _dumpHistory(self) -> None: """Debug function to dump history to the logger. Since it is a for loop, it is skipped entirely if log level isn't DEBUG. """ @@ -667,7 +650,7 @@ class GuiDocViewHistory: class GuiDocViewHeader(QWidget): - def __init__(self, docViewer): + def __init__(self, docViewer: GuiDocViewer) -> None: super().__init__(parent=docViewer) logger.debug("Create: GuiDocViewHeader") @@ -763,9 +746,8 @@ class GuiDocViewHeader(QWidget): # Methods ## - def updateTheme(self): - """Update theme elements. - """ + def updateTheme(self) -> None: + """Update theme elements.""" self.backButton.setIcon(SHARED.theme.getIcon("backward")) self.forwardButton.setIcon(SHARED.theme.getIcon("forward")) self.refreshButton.setIcon(SHARED.theme.getIcon("refresh")) @@ -785,7 +767,7 @@ class GuiDocViewHeader(QWidget): return - def matchColours(self): + def matchColours(self) -> None: """Update the colours of the widget to match those of the syntax theme rather than the main GUI. """ @@ -793,13 +775,11 @@ class GuiDocViewHeader(QWidget): thePalette.setColor(QPalette.Window, QColor(*SHARED.theme.colBack)) thePalette.setColor(QPalette.WindowText, QColor(*SHARED.theme.colText)) thePalette.setColor(QPalette.Text, QColor(*SHARED.theme.colText)) - self.setPalette(thePalette) self.theTitle.setPalette(thePalette) - return - def setTitleFromHandle(self, tHandle): + def setTitleFromHandle(self, tHandle: str | None) -> bool: """Sets the document title from the handle, or alternatively, set the whole document path. """ @@ -835,28 +815,25 @@ class GuiDocViewHeader(QWidget): return True - def updateNavButtons(self, firstIdx, lastIdx, currIdx): - """Enable and disable nav buttons based on index in history. - """ + def updateNavButtons(self, firstIdx: int, lastIdx: int, currIdx: int) -> None: + """Enable and disable nav buttons based on index in history.""" self.backButton.setEnabled(currIdx > firstIdx) self.forwardButton.setEnabled(currIdx < lastIdx) return ## - # Slots + # Private Slots ## @pyqtSlot() - def _closeDocument(self): - """Trigger the close editor/viewer on the main window. - """ + def _closeDocument(self) -> None: + """Trigger the close editor/viewer on the main window.""" self.mainGui.closeDocViewer() return @pyqtSlot() - def _refreshDocument(self): - """Reload the content of the document. - """ + def _refreshDocument(self) -> None: + """Reload the content of the document.""" if self.docViewer.docHandle == self.mainGui.docEditor.docHandle: self.mainGui.saveDocument() self.docViewer.reloadText() @@ -866,7 +843,7 @@ class GuiDocViewHeader(QWidget): # Events ## - def mousePressEvent(self, theEvent): + def mousePressEvent(self, event: QMouseEvent) -> None: """Capture a click on the title and ensure that the item is selected in the project tree. """ @@ -883,14 +860,13 @@ class GuiDocViewHeader(QWidget): class GuiDocViewFooter(QWidget): - def __init__(self, docViewer): + def __init__(self, docViewer: GuiDocViewer) -> None: super().__init__(parent=docViewer) logger.debug("Create: GuiDocViewFooter") self.docViewer = docViewer self.mainGui = docViewer.mainGui - self.viewMeta = docViewer.mainGui.viewMeta # Internal Variables self._docHandle = None @@ -908,19 +884,8 @@ class GuiDocViewFooter(QWidget): self.showHide.setToolButtonStyle(Qt.ToolButtonIconOnly) self.showHide.setIconSize(QSize(fPx, fPx)) self.showHide.setFixedSize(QSize(fPx, fPx)) - self.showHide.clicked.connect(self._doShowHide) - self.showHide.setToolTip(self.tr("Show/hide the references panel")) - - # Sticky Button - self.stickyRefs = QToolButton(self) - self.stickyRefs.setCheckable(True) - self.stickyRefs.setToolButtonStyle(Qt.ToolButtonIconOnly) - self.stickyRefs.setIconSize(QSize(fPx, fPx)) - self.stickyRefs.setFixedSize(QSize(fPx, fPx)) - self.stickyRefs.toggled.connect(self._doToggleSticky) - self.stickyRefs.setToolTip(self.tr( - "Activate to freeze the content of the references panel when changing document" - )) + self.showHide.clicked.connect(lambda: self.docViewer.togglePanelVisibility.emit()) + self.showHide.setToolTip(self.tr("Show/Hide Viewer Panel")) # Show Comments self.showComments = QToolButton(self) @@ -930,7 +895,7 @@ class GuiDocViewFooter(QWidget): self.showComments.setIconSize(QSize(fPx, fPx)) self.showComments.setFixedSize(QSize(fPx, fPx)) self.showComments.toggled.connect(self._doToggleComments) - self.showComments.setToolTip(self.tr("Show comments")) + self.showComments.setToolTip(self.tr("Show Comments")) # Show Synopsis self.showSynopsis = QToolButton(self) @@ -940,27 +905,9 @@ class GuiDocViewFooter(QWidget): self.showSynopsis.setIconSize(QSize(fPx, fPx)) self.showSynopsis.setFixedSize(QSize(fPx, fPx)) self.showSynopsis.toggled.connect(self._doToggleSynopsis) - self.showSynopsis.setToolTip(self.tr("Show synopsis comments")) + self.showSynopsis.setToolTip(self.tr("Show Synopsis Comments")) # Labels - self.lblRefs = QLabel(self.tr("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.lblSticky = QLabel(self.tr("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.lblComments = QLabel(self.tr("Comments")) self.lblComments.setBuddy(self.showComments) self.lblComments.setIndent(0) @@ -981,8 +928,6 @@ class GuiDocViewFooter(QWidget): lblFont = self.font() lblFont.setPointSizeF(0.9*SHARED.theme.fontPointSize) - self.lblRefs.setFont(lblFont) - self.lblSticky.setFont(lblFont) self.lblComments.setFont(lblFont) self.lblSynopsis.setFont(lblFont) @@ -990,10 +935,6 @@ class GuiDocViewFooter(QWidget): self.outerBox = QHBoxLayout() self.outerBox.setSpacing(bSp) self.outerBox.addWidget(self.showHide, 0) - self.outerBox.addWidget(self.lblRefs, 0) - self.outerBox.addSpacing(hSp) - self.outerBox.addWidget(self.stickyRefs, 0) - self.outerBox.addWidget(self.lblSticky, 0) self.outerBox.addStretch(1) self.outerBox.addWidget(self.showComments, 0) self.outerBox.addWidget(self.lblComments, 0) @@ -1024,23 +965,19 @@ class GuiDocViewFooter(QWidget): """Update theme elements.""" # Icons fPx = int(0.9*SHARED.theme.fontPixelSize) - stickyIcon = SHARED.theme.getToggleIcon("sticky", (fPx, fPx)) bulletIcon = SHARED.theme.getToggleIcon("bullet", (fPx, fPx)) - self.showHide.setIcon(SHARED.theme.getIcon("reference")) - self.stickyRefs.setIcon(stickyIcon) + self.showHide.setIcon(SHARED.theme.getIcon("panel")) self.showComments.setIcon(bulletIcon) self.showSynopsis.setIcon(bulletIcon) # StyleSheets - buttonStyle = ( "QToolButton {{border: none; background: transparent;}} " "QToolButton:hover {{border: none; background: rgba({0},{1},{2},0.2);}}" ).format(*SHARED.theme.colText) self.showHide.setStyleSheet(buttonStyle) - self.stickyRefs.setStyleSheet(buttonStyle) self.showComments.setStyleSheet(buttonStyle) self.showSynopsis.setStyleSheet(buttonStyle) @@ -1048,138 +985,35 @@ class GuiDocViewFooter(QWidget): return - def matchColours(self): + def matchColours(self) -> None: """Update the colours of the widget to match those of the syntax theme rather than the main GUI. """ - thePalette = QPalette() - thePalette.setColor(QPalette.Window, QColor(*SHARED.theme.colBack)) - thePalette.setColor(QPalette.WindowText, QColor(*SHARED.theme.colText)) - thePalette.setColor(QPalette.Text, QColor(*SHARED.theme.colText)) - - self.setPalette(thePalette) - self.lblRefs.setPalette(thePalette) - self.lblSticky.setPalette(thePalette) - self.lblComments.setPalette(thePalette) - self.lblSynopsis.setPalette(thePalette) - - return - - ## - # Slots - ## - - @pyqtSlot() - def _doShowHide(self): - """Toggle the expand/collapse of the panel. - """ - isVisible = self.viewMeta.isVisible() - self.viewMeta.setVisible(not isVisible) - return - - @pyqtSlot(bool) - def _doToggleSticky(self, theState): - """Toggle the sticky flag for the reference panel. - """ - logger.debug("Reference sticky is %s", str(theState)) - self.docViewer.stickyRef = theState - if not theState and self.docViewer.docHandle is not None: - self.viewMeta.refreshReferences(self.docViewer.docHandle) - return - - @pyqtSlot(bool) - def _doToggleComments(self, theState): - """Toggle the view comment button and reload the document. - """ - CONFIG.viewComments = theState - self.docViewer.reloadText() - return - - @pyqtSlot(bool) - def _doToggleSynopsis(self, theState): - """Toggle the view synopsis button and reload the document. - """ - CONFIG.viewSynopsis = theState - self.docViewer.reloadText() - return - -# END Class GuiDocViewFooter - - -# =============================================================================================== # -# The Document Back-Reference Panel -# Placed in a separate QSplitter position in the main GUI window -# =============================================================================================== # - -class GuiDocViewDetails(QScrollArea): - - def __init__(self, mainGui): - super().__init__(parent=mainGui) - - logger.debug("Create: GuiDocViewDetails") - - self.mainGui = mainGui - - self.refList = QLabel("") - self.refList.setWordWrap(True) - self.refList.setAlignment(Qt.AlignTop) - self.refList.setScaledContents(True) - self.refList.linkActivated.connect(self._linkClicked) - - self.linkStyle = "style='color: rgb({0},{1},{2})'".format(*SHARED.theme.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(CONFIG.pxInt(50)) - self.setFrameStyle(QFrame.NoFrame) - - logger.debug("Ready: GuiDocViewDetails") - - return - - def refreshReferences(self, tHandle): - """Update the current list of document references from the - project index. - """ - if self.mainGui.docViewer.stickyRef: - return - - theRefs = SHARED.project.index.getBackReferenceList(tHandle) - theList = [] - for tHandle in theRefs: - tItem = SHARED.project.tree[tHandle] - if tItem is not None: - theList.append("%s" % ( - tHandle, theRefs[tHandle], self.linkStyle, tItem.itemName - )) - - self.refList.setText(", ".join(theList)) - + palette = QPalette() + palette.setColor(QPalette.Window, QColor(*SHARED.theme.colBack)) + palette.setColor(QPalette.WindowText, QColor(*SHARED.theme.colText)) + palette.setColor(QPalette.Text, QColor(*SHARED.theme.colText)) + self.setPalette(palette) + self.lblComments.setPalette(palette) + self.lblSynopsis.setPalette(palette) return ## # Private Slots ## - @pyqtSlot(str) - def _linkClicked(self, theLink): - """Capture the link-click and forward it to the document viewer - class for handling. - """ - logger.debug("Clicked link: '%s'", theLink) - if len(theLink) >= 13: - tHandle = theLink[:13] - tAnchor = theLink[13:] or None - self.mainGui.viewDocument(tHandle, tAnchor) + @pyqtSlot(bool) + def _doToggleComments(self, state: bool) -> None: + """Toggle the view comment button and reload the document.""" + CONFIG.viewComments = state + self.docViewer.reloadText() return -# END Class GuiDocViewDetails + @pyqtSlot(bool) + def _doToggleSynopsis(self, state: bool) -> None: + """Toggle the view synopsis button and reload the document.""" + CONFIG.viewSynopsis = state + self.docViewer.reloadText() + return + +# END Class GuiDocViewFooter diff --git a/novelwriter/gui/docviewerpanel.py b/novelwriter/gui/docviewerpanel.py index 9316fe2f..36290b8c 100644 --- a/novelwriter/gui/docviewerpanel.py +++ b/novelwriter/gui/docviewerpanel.py @@ -3,7 +3,7 @@ novelWriter – GUI Document Viewer Panel ======================================= File History: -Created: 2023-11-09 [2.2a1] GuiDocViewerPanel +Created: 2023-11-14 [2.2rc1] GuiDocViewerPanel This file is a part of novelWriter Copyright 2018–2023, Veronica Berglyd Olsen @@ -25,40 +25,90 @@ from __future__ import annotations import logging -from PyQt5.QtWidgets import QVBoxLayout, QWidget +from PyQt5.QtWidgets import QTabWidget, QVBoxLayout, QWidget -from novelwriter.gui.docviewer import GuiDocViewer +from novelwriter import CONFIG +from novelwriter.constants import nwLabels, nwLists, trConst logger = logging.getLogger(__name__) class GuiDocViewerPanel(QWidget): - def __init__(self, docViewer: GuiDocViewer) -> None: - super().__init__(parent=docViewer) + def __init__(self, parent: QWidget) -> None: + super().__init__(parent=parent) logger.debug("Create: GuiDocViewerPanel") - self.panelHeader = GuiDocViewerPanelHeader(self) + self.tabBackRefs = _ViewPanelBackRefs(self) + + self.mainTabs = QTabWidget(self) + self.mainTabs.addTab(self.tabBackRefs, self.tr("Back References")) + + self.kwTabs = {} + for itemClass in nwLists.USER_CLASSES: + self.kwTabs[itemClass] = _ViewPanelKeyWords(self) + self.mainTabs.addTab(self.kwTabs[itemClass], trConst(nwLabels.CLASS_NAME[itemClass])) # Assemble self.outerBox = QVBoxLayout() - self.outerBox.addWidget(self.panelHeader) + self.outerBox.addWidget(self.mainTabs) self.outerBox.setContentsMargins(0, 0, 0, 0) self.setLayout(self.outerBox) + self.updateTheme() logger.debug("Ready: GuiDocViewerPanel") return + def updateTheme(self) -> None: + """Update theme elements.""" + vPx = CONFIG.pxInt(4) + lPx = CONFIG.pxInt(2) + rPx = CONFIG.pxInt(14) + hCol = self.palette().highlight().color() + + styleSheet = ( + "QTabWidget QTabBar::tab {" + f"border: 0; padding: {vPx}px {rPx}px {vPx}px {lPx}px;" + "} " + "QTabWidget QTabBar::tab:selected {" + f"color: rgb({hCol.red()}, {hCol.green()}, {hCol.blue()});" + "} " + ) + self.mainTabs.setStyleSheet(styleSheet) + + return + # END Class GuiDocViewerPanel -class GuiDocViewerPanelHeader(QWidget): +class _ViewPanelBackRefs(QWidget): - def __init__(self, docViewerPanel: GuiDocViewerPanel) -> None: - super().__init__(parent=docViewerPanel) + def __init__(self, parent: QWidget) -> None: + super().__init__(parent=parent) return -# END Class GuiDocViewerPanelHeader + def refreshContent(self): + """""" + # theRefs = SHARED.project.index.getBackReferenceList(tHandle) + # theList = [] + # for tHandle in theRefs: + # tItem = SHARED.project.tree[tHandle] + # if tItem is not None: + # theList.append("%s" % ( + # tHandle, theRefs[tHandle], self.linkStyle, tItem.itemName + # )) + return + +# END Class _ViewPanelBackRefs + + +class _ViewPanelKeyWords(QWidget): + + def __init__(self, parent: QWidget) -> None: + super().__init__(parent=parent) + return + +# END Class _ViewPanelRefs diff --git a/novelwriter/gui/theme.py b/novelwriter/gui/theme.py index 6c4d7e76..a169e6f8 100644 --- a/novelwriter/gui/theme.py +++ b/novelwriter/gui/theme.py @@ -464,8 +464,8 @@ class GuiIcons: # General Button Icons "add", "backward", "bookmark", "browse", "checked", "close", "cross", "down", "edit", - "export", "forward", "maximise", "menu", "minimise", "noncheckable", "reference", - "refresh", "remove", "revert", "search_replace", "search", "settings", "unchecked", "up", + "export", "forward", "maximise", "menu", "minimise", "noncheckable", "panel", "refresh", + "remove", "revert", "search_replace", "search", "settings", "unchecked", "up", # Switches "sticky-on", "sticky-off", diff --git a/novelwriter/guimain.py b/novelwriter/guimain.py index c672a1f2..b8e4b8ed 100644 --- a/novelwriter/guimain.py +++ b/novelwriter/guimain.py @@ -44,10 +44,11 @@ from novelwriter.gui.outline import GuiOutlineView from novelwriter.gui.mainmenu import GuiMainMenu from novelwriter.gui.projtree import GuiProjectView from novelwriter.gui.doceditor import GuiDocEditor -from novelwriter.gui.docviewer import GuiDocViewDetails, GuiDocViewer +from novelwriter.gui.docviewer import GuiDocViewer from novelwriter.gui.noveltree import GuiNovelView from novelwriter.gui.statusbar import GuiMainStatus from novelwriter.gui.itemdetails import GuiItemDetails +from novelwriter.gui.docviewerpanel import GuiDocViewerPanel from novelwriter.dialogs.about import GuiAbout from novelwriter.dialogs.updates import GuiUpdates from novelwriter.dialogs.projload import GuiProjectLoad @@ -133,16 +134,16 @@ class GuiMain(QMainWindow): hWd = CONFIG.pxInt(4) # Main GUI Elements - self.mainStatus = GuiMainStatus(self) - self.projView = GuiProjectView(self) - self.novelView = GuiNovelView(self) - self.docEditor = GuiDocEditor(self) - self.viewMeta = GuiDocViewDetails(self) - self.docViewer = GuiDocViewer(self) - self.itemDetails = GuiItemDetails(self) - self.outlineView = GuiOutlineView(self) - self.mainMenu = GuiMainMenu(self) - self.sideBar = GuiSideBar(self) + self.mainStatus = GuiMainStatus(self) + self.projView = GuiProjectView(self) + self.novelView = GuiNovelView(self) + self.docEditor = GuiDocEditor(self) + self.docViewer = GuiDocViewer(self) + self.docViewerPanel = GuiDocViewerPanel(self) + self.itemDetails = GuiItemDetails(self) + self.outlineView = GuiOutlineView(self) + self.mainMenu = GuiMainMenu(self) + self.sideBar = GuiSideBar(self) # Project Tree Stack self.projStack = QStackedWidget(self) @@ -162,7 +163,7 @@ class GuiMain(QMainWindow): # Splitter : Document Viewer / Document Meta self.splitView = QSplitter(Qt.Vertical, self) self.splitView.addWidget(self.docViewer) - self.splitView.addWidget(self.viewMeta) + self.splitView.addWidget(self.docViewerPanel) self.splitView.setHandleWidth(hWd) self.splitView.setOpaqueResize(False) self.splitView.setSizes(CONFIG.viewPanePos) @@ -190,12 +191,12 @@ class GuiMain(QMainWindow): self.mainStack.currentChanged.connect(self._mainStackChanged) # Indices of Splitter Widgets - self.idxTree = self.splitMain.indexOf(self.treePane) - 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) + self.idxTree = self.splitMain.indexOf(self.treePane) + 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.idxViewDocPanel = self.splitView.indexOf(self.docViewerPanel) # Indices of Stack Widgets self.idxEditorView = self.mainStack.indexOf(self.splitMain) @@ -209,7 +210,7 @@ class GuiMain(QMainWindow): self.splitDocs.setCollapsible(self.idxEditor, False) self.splitDocs.setCollapsible(self.idxViewer, False) self.splitView.setCollapsible(self.idxViewDoc, False) - self.splitView.setCollapsible(self.idxViewMeta, False) + self.splitView.setCollapsible(self.idxViewDocPanel, False) self.splitMain.setStretchFactor(self.idxTree, 0) self.splitMain.setStretchFactor(self.idxMain, 1) @@ -277,6 +278,7 @@ class GuiMain(QMainWindow): self.docEditor.toggleFocusModeRequest.connect(self.toggleFocusMode) self.docViewer.loadDocumentTagRequest.connect(self._followTag) + self.docViewer.togglePanelVisibility.connect(self._toggleViewerPanelVisibility) self.outlineView.loadDocumentTagRequest.connect(self._followTag) self.outlineView.openDocumentRequest.connect(self._openDocument) @@ -681,7 +683,7 @@ class GuiMain(QMainWindow): vPos[0] = int(bPos[1]/2) vPos[1] = bPos[1] - vPos[0] self.splitDocs.setSizes(vPos) - self.viewMeta.setVisible(CONFIG.showRefPanel) + self.docViewerPanel.setVisible(CONFIG.showViewerPanel) if sTitle: self.docViewer.navigateTo(f"#{sTitle}") @@ -877,6 +879,7 @@ class GuiMain(QMainWindow): SHARED.theme.loadTheme() self.docEditor.updateTheme() self.docViewer.updateTheme() + self.docViewerPanel.updateTheme() self.sideBar.updateTheme() self.projView.updateTheme() self.novelView.updateTheme() @@ -1076,10 +1079,10 @@ class GuiMain(QMainWindow): if not self.isFocusMode: CONFIG.setMainPanePos(self.splitMain.sizes()) CONFIG.setOutlinePanePos(self.outlineView.splitSizes()) - if self.viewMeta.isVisible(): + if self.docViewerPanel.isVisible(): CONFIG.setViewPanePos(self.splitView.sizes()) - CONFIG.showRefPanel = self.viewMeta.isVisible() + CONFIG.showViewerPanel = self.docViewerPanel.isVisible() if self.windowState() & Qt.WindowFullScreen != Qt.WindowFullScreen: # Ignore window size if in full screen mode CONFIG.setMainWinSize(self.width(), self.height()) @@ -1267,6 +1270,13 @@ class GuiMain(QMainWindow): self.docEditor.insertText(content) return + @pyqtSlot() + def _toggleViewerPanelVisibility(self): + """Toggle the visibility of the document viewer panel.""" + CONFIG.showViewerPanel = not CONFIG.showViewerPanel + self.docViewerPanel.setVisible(CONFIG.showViewerPanel) + return + @pyqtSlot() def _timeTick(self) -> None: """Process time tick of the main timer."""