diff --git a/novelwriter/extensions/modified.py b/novelwriter/extensions/modified.py index 39416b23..15b61db0 100644 --- a/novelwriter/extensions/modified.py +++ b/novelwriter/extensions/modified.py @@ -25,9 +25,9 @@ along with this program. If not, see . """ from __future__ import annotations -from PyQt5.QtCore import Qt +from PyQt5.QtCore import QSize, Qt from PyQt5.QtGui import QWheelEvent -from PyQt5.QtWidgets import QComboBox, QDoubleSpinBox, QSpinBox, QWidget +from PyQt5.QtWidgets import QComboBox, QDoubleSpinBox, QSpinBox, QToolButton, QWidget class NComboBox(QComboBox): @@ -85,3 +85,15 @@ class NDoubleSpinBox(QDoubleSpinBox): return # END Class NDoubleSpinBox + + +class NIconToolButton(QToolButton): + + def __init__(self, parent: QWidget, iconSize: int) -> None: + super().__init__(parent=parent) + self.setToolButtonStyle(Qt.ToolButtonStyle.ToolButtonIconOnly) + self.setIconSize(QSize(iconSize, iconSize)) + self.setPopupMode(QToolButton.ToolButtonPopupMode.InstantPopup) + return + +# END Class NIconToolButton diff --git a/novelwriter/gui/doceditor.py b/novelwriter/gui/doceditor.py index a3051647..8cd72429 100644 --- a/novelwriter/gui/doceditor.py +++ b/novelwriter/gui/doceditor.py @@ -53,15 +53,17 @@ from PyQt5.QtWidgets import ( ) from novelwriter import CONFIG, SHARED -from novelwriter.enum import nwDocAction, nwDocInsert, nwDocMode, nwItemClass, nwTrinary from novelwriter.common import minmax, transferCase from novelwriter.constants import nwKeyWords, nwShortcode, nwUnicode -from novelwriter.tools.lipsum import GuiLipsum from novelwriter.core.document import NWDocument -from novelwriter.text.counting import standardCounter +from novelwriter.enum import nwDocAction, nwDocInsert, nwDocMode, nwItemClass, nwTrinary +from novelwriter.extensions.eventfilters import WheelEventFilter +from novelwriter.extensions.modified import NIconToolButton from novelwriter.gui.dochighlight import BLOCK_META, BLOCK_TITLE from novelwriter.gui.editordocument import GuiTextDocument -from novelwriter.extensions.eventfilters import WheelEventFilter +from novelwriter.gui.theme import STYLES_MIN_TOOLBUTTON +from novelwriter.text.counting import standardCounter +from novelwriter.tools.lipsum import GuiLipsum if TYPE_CHECKING: # pragma: no cover from novelwriter.guimain import GuiMain @@ -2805,10 +2807,8 @@ class GuiDocEditHeader(QWidget): self._docHandle = None self._docOutline: dict[int, str] = {} - fPx = int(0.9*SHARED.theme.fontPixelSize) - mPx = CONFIG.pxInt(8) - hSp = CONFIG.pxInt(6) - iconSize = QSize(fPx, fPx) + iPx = SHARED.theme.baseIconSize + mPx = CONFIG.pxInt(4) # Main Widget Settings self.setAutoFillBackground(True) @@ -2820,7 +2820,7 @@ class GuiDocEditHeader(QWidget): self.itemTitle.setContentsMargins(0, 0, 0, 0) self.itemTitle.setAutoFillBackground(True) self.itemTitle.setAlignment(Qt.AlignmentFlag.AlignHCenter | Qt.AlignmentFlag.AlignTop) - self.itemTitle.setFixedHeight(fPx) + self.itemTitle.setFixedHeight(iPx) lblFont = self.itemTitle.font() lblFont.setPointSizeF(0.9*SHARED.theme.fontPointSize) @@ -2830,63 +2830,44 @@ class GuiDocEditHeader(QWidget): self.outlineMenu = QMenu(self) # Buttons - self.tbButton = QToolButton(self) - self.tbButton.setContentsMargins(0, 0, 0, 0) - self.tbButton.setIconSize(iconSize) - self.tbButton.setFixedSize(fPx, fPx) - self.tbButton.setToolButtonStyle(Qt.ToolButtonStyle.ToolButtonIconOnly) + self.tbButton = NIconToolButton(self, iPx) self.tbButton.setVisible(False) self.tbButton.setToolTip(self.tr("Toggle Tool Bar")) self.tbButton.clicked.connect(lambda: self.toggleToolBarRequest.emit()) - self.outlineButton = QToolButton(self) - self.outlineButton.setContentsMargins(0, 0, 0, 0) - self.outlineButton.setIconSize(iconSize) - self.outlineButton.setFixedSize(fPx, fPx) - self.outlineButton.setToolButtonStyle(Qt.ToolButtonStyle.ToolButtonIconOnly) + self.outlineButton = NIconToolButton(self, iPx) self.outlineButton.setVisible(False) self.outlineButton.setToolTip(self.tr("Outline")) self.outlineButton.setMenu(self.outlineMenu) - self.outlineButton.setPopupMode(QToolButton.ToolButtonPopupMode.InstantPopup) - self.searchButton = QToolButton(self) - self.searchButton.setContentsMargins(0, 0, 0, 0) - self.searchButton.setIconSize(iconSize) - self.searchButton.setFixedSize(fPx, fPx) - self.searchButton.setToolButtonStyle(Qt.ToolButtonStyle.ToolButtonIconOnly) + self.searchButton = NIconToolButton(self, iPx) self.searchButton.setVisible(False) self.searchButton.setToolTip(self.tr("Search")) self.searchButton.clicked.connect(self.docEditor.toggleSearch) - self.minmaxButton = QToolButton(self) - self.minmaxButton.setContentsMargins(0, 0, 0, 0) - self.minmaxButton.setIconSize(iconSize) - self.minmaxButton.setFixedSize(fPx, fPx) - self.minmaxButton.setToolButtonStyle(Qt.ToolButtonStyle.ToolButtonIconOnly) + self.minmaxButton = NIconToolButton(self, iPx) self.minmaxButton.setVisible(False) self.minmaxButton.setToolTip(self.tr("Toggle Focus Mode")) self.minmaxButton.clicked.connect(lambda: self.docEditor.toggleFocusModeRequest.emit()) - self.closeButton = QToolButton(self) - self.closeButton.setContentsMargins(0, 0, 0, 0) - self.closeButton.setIconSize(iconSize) - self.closeButton.setFixedSize(fPx, fPx) - self.closeButton.setToolButtonStyle(Qt.ToolButtonStyle.ToolButtonIconOnly) + self.closeButton = NIconToolButton(self, iPx) self.closeButton.setVisible(False) self.closeButton.setToolTip(self.tr("Close")) self.closeButton.clicked.connect(self._closeDocument) # Assemble Layout self.outerBox = QHBoxLayout() - self.outerBox.setSpacing(hSp) self.outerBox.addWidget(self.tbButton, 0) self.outerBox.addWidget(self.outlineButton, 0) self.outerBox.addWidget(self.searchButton, 0) + self.outerBox.addSpacing(mPx) self.outerBox.addWidget(self.itemTitle, 1) - self.outerBox.addSpacing(fPx + hSp) + self.outerBox.addSpacing(mPx) + self.outerBox.addSpacing(iPx) self.outerBox.addWidget(self.minmaxButton, 0) self.outerBox.addWidget(self.closeButton, 0) self.outerBox.setContentsMargins(mPx, mPx, mPx, mPx) + self.outerBox.setSpacing(0) self.setLayout(self.outerBox) @@ -2896,7 +2877,7 @@ class GuiDocEditHeader(QWidget): # Fix Margins and Size # This is needed for high DPI systems. See issue #499. self.setContentsMargins(0, 0, 0, 0) - self.setMinimumHeight(fPx + 2*mPx) + self.setMinimumHeight(iPx + 2*mPx) self.updateTheme() @@ -2944,15 +2925,9 @@ class GuiDocEditHeader(QWidget): self.minmaxButton.setIcon(SHARED.theme.getIcon("maximise")) self.closeButton.setIcon(SHARED.theme.getIcon("close")) - colText = SHARED.theme.colText - buttonStyle = ( - "QToolButton {{border: none; background: transparent;}} " - "QToolButton:hover {{border: none; background: rgba({0}, {1}, {2}, 0.2);}}" - ).format(colText.red(), colText.green(), colText.blue()) - buttonStyleMenu = f"{buttonStyle} QToolButton::menu-indicator {{image: none;}}" - + buttonStyle = SHARED.theme.getStyleSheet(STYLES_MIN_TOOLBUTTON) self.tbButton.setStyleSheet(buttonStyle) - self.outlineButton.setStyleSheet(buttonStyleMenu) + self.outlineButton.setStyleSheet(buttonStyle) self.searchButton.setStyleSheet(buttonStyle) self.minmaxButton.setStyleSheet(buttonStyle) self.closeButton.setStyleSheet(buttonStyle) diff --git a/novelwriter/gui/docviewer.py b/novelwriter/gui/docviewer.py index d3352720..891af3e6 100644 --- a/novelwriter/gui/docviewer.py +++ b/novelwriter/gui/docviewer.py @@ -44,6 +44,8 @@ from novelwriter import CONFIG, SHARED from novelwriter.enum import nwItemType, nwDocAction, nwDocMode from novelwriter.error import logException from novelwriter.constants import nwHeaders, nwUnicode +from novelwriter.extensions.modified import NIconToolButton +from novelwriter.gui.theme import STYLES_MIN_TOOLBUTTON from novelwriter.core.tohtml import ToHtml from novelwriter.extensions.eventfilters import WheelEventFilter @@ -630,10 +632,8 @@ class GuiDocViewHeader(QWidget): self._docHandle = None self._docOutline: dict[int, tuple[str, int]] = {} - fPx = int(0.9*SHARED.theme.fontPixelSize) - hSp = CONFIG.pxInt(6) - mPx = CONFIG.pxInt(8) - iconSize = QSize(fPx, fPx) + iPx = SHARED.theme.baseIconSize + mPx = CONFIG.pxInt(4) # Main Widget Settings self.setAutoFillBackground(True) @@ -646,7 +646,7 @@ class GuiDocViewHeader(QWidget): self.itemTitle.setContentsMargins(0, 0, 0, 0) self.itemTitle.setAutoFillBackground(True) self.itemTitle.setAlignment(Qt.AlignmentFlag.AlignHCenter | Qt.AlignmentFlag.AlignTop) - self.itemTitle.setFixedHeight(fPx) + self.itemTitle.setFixedHeight(iPx) lblFont = self.itemTitle.font() lblFont.setPointSizeF(0.9*SHARED.theme.fontPointSize) @@ -656,62 +656,43 @@ class GuiDocViewHeader(QWidget): self.outlineMenu = QMenu(self) # Buttons - self.outlineButton = QToolButton(self) - self.outlineButton.setContentsMargins(0, 0, 0, 0) - self.outlineButton.setIconSize(iconSize) - self.outlineButton.setFixedSize(fPx, fPx) - self.outlineButton.setToolButtonStyle(Qt.ToolButtonStyle.ToolButtonIconOnly) + self.outlineButton = NIconToolButton(self, iPx) self.outlineButton.setVisible(False) self.outlineButton.setToolTip(self.tr("Outline")) self.outlineButton.setMenu(self.outlineMenu) - self.outlineButton.setPopupMode(QToolButton.ToolButtonPopupMode.InstantPopup) - self.backButton = QToolButton(self) - self.backButton.setContentsMargins(0, 0, 0, 0) - self.backButton.setIconSize(iconSize) - self.backButton.setFixedSize(fPx, fPx) - self.backButton.setToolButtonStyle(Qt.ToolButtonStyle.ToolButtonIconOnly) + self.backButton = NIconToolButton(self, iPx) self.backButton.setVisible(False) self.backButton.setToolTip(self.tr("Go Backward")) self.backButton.clicked.connect(self.docViewer.navBackward) - self.forwardButton = QToolButton(self) - self.forwardButton.setContentsMargins(0, 0, 0, 0) - self.forwardButton.setIconSize(iconSize) - self.forwardButton.setFixedSize(fPx, fPx) - self.forwardButton.setToolButtonStyle(Qt.ToolButtonStyle.ToolButtonIconOnly) + self.forwardButton = NIconToolButton(self, iPx) self.forwardButton.setVisible(False) self.forwardButton.setToolTip(self.tr("Go Forward")) self.forwardButton.clicked.connect(self.docViewer.navForward) - self.refreshButton = QToolButton(self) - self.refreshButton.setContentsMargins(0, 0, 0, 0) - self.refreshButton.setIconSize(iconSize) - self.refreshButton.setFixedSize(fPx, fPx) - self.refreshButton.setToolButtonStyle(Qt.ToolButtonStyle.ToolButtonIconOnly) + self.refreshButton = NIconToolButton(self, iPx) self.refreshButton.setVisible(False) self.refreshButton.setToolTip(self.tr("Reload")) self.refreshButton.clicked.connect(self._refreshDocument) - self.closeButton = QToolButton(self) - self.closeButton.setContentsMargins(0, 0, 0, 0) - self.closeButton.setIconSize(iconSize) - self.closeButton.setFixedSize(fPx, fPx) - self.closeButton.setToolButtonStyle(Qt.ToolButtonStyle.ToolButtonIconOnly) + self.closeButton = NIconToolButton(self, iPx) self.closeButton.setVisible(False) self.closeButton.setToolTip(self.tr("Close")) self.closeButton.clicked.connect(self._closeDocument) # Assemble Layout self.outerBox = QHBoxLayout() - self.outerBox.setSpacing(hSp) self.outerBox.addWidget(self.outlineButton, 0) self.outerBox.addWidget(self.backButton, 0) self.outerBox.addWidget(self.forwardButton, 0) + self.outerBox.addSpacing(mPx) self.outerBox.addWidget(self.itemTitle, 1) - self.outerBox.addSpacing(fPx + hSp) + self.outerBox.addSpacing(mPx) + self.outerBox.addSpacing(iPx) self.outerBox.addWidget(self.refreshButton, 0) self.outerBox.addWidget(self.closeButton, 0) + self.outerBox.setSpacing(0) self.setLayout(self.outerBox) @@ -719,7 +700,7 @@ class GuiDocViewHeader(QWidget): # This is needed for high DPI systems. See issue #499. self.setContentsMargins(0, 0, 0, 0) self.outerBox.setContentsMargins(mPx, mPx, mPx, mPx) - self.setMinimumHeight(fPx + 2*mPx) + self.setMinimumHeight(iPx + 2*mPx) # Fix the Colours self.updateTheme() @@ -773,14 +754,8 @@ class GuiDocViewHeader(QWidget): self.refreshButton.setIcon(SHARED.theme.getIcon("refresh")) self.closeButton.setIcon(SHARED.theme.getIcon("close")) - colText = SHARED.theme.colText - buttonStyle = ( - "QToolButton {{border: none; background: transparent;}} " - "QToolButton:hover {{border: none; background: rgba({0}, {1}, {2}, 0.2);}}" - ).format(colText.red(), colText.green(), colText.blue()) - buttonStyleMenu = f"{buttonStyle} QToolButton::menu-indicator {{image: none;}}" - - self.outlineButton.setStyleSheet(buttonStyleMenu) + buttonStyle = SHARED.theme.getStyleSheet(STYLES_MIN_TOOLBUTTON) + self.outlineButton.setStyleSheet(buttonStyle) self.backButton.setStyleSheet(buttonStyle) self.forwardButton.setStyleSheet(buttonStyle) self.refreshButton.setStyleSheet(buttonStyle) @@ -878,17 +853,16 @@ class GuiDocViewFooter(QWidget): # Internal Variables self._docHandle = None - fPx = int(0.9*SHARED.theme.fontPixelSize) + iPx = SHARED.theme.baseIconSize hSp = CONFIG.pxInt(4) + mPx = CONFIG.pxInt(4) # Main Widget Settings self.setContentsMargins(0, 0, 0, 0) self.setAutoFillBackground(True) # Show/Hide Details - self.showHide = QToolButton(self) - self.showHide.setToolButtonStyle(Qt.ToolButtonStyle.ToolButtonIconOnly) - self.showHide.setIconSize(QSize(fPx, fPx)) + self.showHide = NIconToolButton(self, iPx) self.showHide.clicked.connect(lambda: self.docViewer.togglePanelVisibility.emit()) self.showHide.setToolTip(self.tr("Show/Hide Viewer Panel")) @@ -898,7 +872,7 @@ class GuiDocViewFooter(QWidget): self.showComments.setCheckable(True) self.showComments.setChecked(CONFIG.viewComments) self.showComments.setToolButtonStyle(Qt.ToolButtonStyle.ToolButtonTextBesideIcon) - self.showComments.setIconSize(QSize(fPx, fPx)) + self.showComments.setIconSize(QSize(iPx, iPx)) self.showComments.toggled.connect(self._doToggleComments) self.showComments.setToolTip(self.tr("Show Comments")) @@ -908,7 +882,7 @@ class GuiDocViewFooter(QWidget): self.showSynopsis.setCheckable(True) self.showSynopsis.setChecked(CONFIG.viewSynopsis) self.showSynopsis.setToolButtonStyle(Qt.ToolButtonStyle.ToolButtonTextBesideIcon) - self.showSynopsis.setIconSize(QSize(fPx, fPx)) + self.showSynopsis.setIconSize(QSize(iPx, iPx)) self.showSynopsis.toggled.connect(self._doToggleSynopsis) self.showSynopsis.setToolTip(self.tr("Show Synopsis Comments")) @@ -928,10 +902,9 @@ class GuiDocViewFooter(QWidget): # Fix Margins and Size # This is needed for high DPI systems. See issue #499. - cM = CONFIG.pxInt(8) self.setContentsMargins(0, 0, 0, 0) - self.outerBox.setContentsMargins(cM, cM, cM, cM) - self.setMinimumHeight(fPx + 2*cM) + self.outerBox.setContentsMargins(mPx, mPx, mPx, mPx) + self.setMinimumHeight(iPx + 2*mPx) # Fix the Colours self.updateTheme() @@ -954,12 +927,7 @@ class GuiDocViewFooter(QWidget): self.showComments.setIcon(bulletIcon) self.showSynopsis.setIcon(bulletIcon) - colText = SHARED.theme.colText - buttonStyle = ( - "QToolButton {{border: none; background: transparent;}} " - "QToolButton:hover {{border: none; background: rgba({0}, {1}, {2}, 0.2);}}" - ).format(colText.red(), colText.green(), colText.blue()) - + buttonStyle = SHARED.theme.getStyleSheet(STYLES_MIN_TOOLBUTTON) self.showHide.setStyleSheet(buttonStyle) self.showComments.setStyleSheet(buttonStyle) self.showSynopsis.setStyleSheet(buttonStyle) diff --git a/novelwriter/gui/docviewerpanel.py b/novelwriter/gui/docviewerpanel.py index a5a5695e..a58d7f02 100644 --- a/novelwriter/gui/docviewerpanel.py +++ b/novelwriter/gui/docviewerpanel.py @@ -34,10 +34,11 @@ from PyQt5.QtWidgets import ( ) from novelwriter import CONFIG, SHARED -from novelwriter.enum import nwDocMode, nwItemClass from novelwriter.common import checkInt from novelwriter.constants import nwHeaders, nwLabels, nwLists, trConst from novelwriter.core.index import IndexHeading, IndexItem +from novelwriter.enum import nwDocMode, nwItemClass +from novelwriter.gui.theme import STYLES_FLAT_TABS, STYLES_MIN_TOOLBUTTON logger = logging.getLogger(__name__) @@ -99,35 +100,14 @@ class GuiDocViewerPanel(QWidget): def updateTheme(self, updateTabs: bool = True) -> None: """Update theme elements.""" - qPalette = self.palette() - mPx = CONFIG.pxInt(2) - vPx = CONFIG.pxInt(4) - hPx = CONFIG.pxInt(8) - hCol = qPalette.highlight().color() - fCol = qPalette.text().color() - - buttonStyle = ( - "QToolButton {{padding: {0}px; margin: 0 0 {1}px 0; border: none; " - "background: transparent;}} " - "QToolButton:hover {{border: none; background: rgba({2}, {3}, {4}, 0.2);}} " - "QToolButton::menu-indicator {{image: none;}} " - ).format(mPx, mPx, fCol.red(), fCol.green(), fCol.blue()) self.optsButton.setIcon(SHARED.theme.getIcon("menu")) - self.optsButton.setStyleSheet(buttonStyle) - - styleSheet = ( - "QTabWidget::pane {{border: 0;}} " - "QTabWidget QTabBar::tab {{border: 0; padding: {0}px {1}px;}} " - "QTabWidget QTabBar::tab:selected {{color: rgb({2}, {3}, {4});}} " - ).format(vPx, hPx, hCol.red(), hCol.green(), hCol.blue()) - self.mainTabs.setStyleSheet(styleSheet) + self.optsButton.setStyleSheet(SHARED.theme.getStyleSheet(STYLES_MIN_TOOLBUTTON)) + self.mainTabs.setStyleSheet(SHARED.theme.getStyleSheet(STYLES_FLAT_TABS)) self.updateHandle(self._lastHandle) - if updateTabs: self.tabBackRefs.updateTheme() for tab in self.kwTabs.values(): tab.updateTheme() - return def openProjectTasks(self) -> None: diff --git a/novelwriter/gui/noveltree.py b/novelwriter/gui/noveltree.py index f2c62ddb..95a6e25f 100644 --- a/novelwriter/gui/noveltree.py +++ b/novelwriter/gui/noveltree.py @@ -35,16 +35,18 @@ from PyQt5.QtGui import QFocusEvent, QFont, QMouseEvent, QPalette, QResizeEvent from PyQt5.QtCore import QModelIndex, QPoint, Qt, QSize, pyqtSlot, pyqtSignal from PyQt5.QtWidgets import ( QAbstractItemView, QActionGroup, QFrame, QHBoxLayout, QHeaderView, - QInputDialog, QMenu, QSizePolicy, QToolButton, QToolTip, QTreeWidget, - QTreeWidgetItem, QVBoxLayout, QWidget + QInputDialog, QMenu, QSizePolicy, QToolTip, QTreeWidget, QTreeWidgetItem, + QVBoxLayout, QWidget ) from novelwriter import CONFIG, SHARED -from novelwriter.enum import nwDocMode, nwItemClass, nwOutline from novelwriter.common import minmax from novelwriter.constants import nwHeaders, nwKeyWords, nwLabels, trConst from novelwriter.core.index import IndexHeading +from novelwriter.enum import nwDocMode, nwItemClass, nwOutline +from novelwriter.extensions.modified import NIconToolButton from novelwriter.extensions.novelselector import NovelSelector +from novelwriter.gui.theme import STYLES_MIN_TOOLBUTTON if TYPE_CHECKING: # pragma: no cover from novelwriter.guimain import GuiMain @@ -215,15 +217,13 @@ class GuiNovelToolBar(QWidget): self.novelValue.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding) self.novelValue.novelSelectionChanged.connect(self.setCurrentRoot) - self.tbNovel = QToolButton(self) + self.tbNovel = NIconToolButton(self, iPx) self.tbNovel.setToolTip(self.tr("Novel Root")) - self.tbNovel.setIconSize(QSize(iPx, iPx)) self.tbNovel.clicked.connect(self.novelValue.showPopup) # Refresh Button - self.tbRefresh = QToolButton(self) + self.tbRefresh = NIconToolButton(self, iPx) self.tbRefresh.setToolTip(self.tr("Refresh")) - self.tbRefresh.setIconSize(QSize(iPx, iPx)) self.tbRefresh.clicked.connect(self._refreshNovelTree) # More Options Menu @@ -241,11 +241,9 @@ class GuiNovelToolBar(QWidget): self.aLastColSize = self.mLastCol.addAction(self.tr("Column Size")) self.aLastColSize.triggered.connect(self._selectLastColumnSize) - self.tbMore = QToolButton(self) + self.tbMore = NIconToolButton(self, iPx) self.tbMore.setToolTip(self.tr("More Options")) - self.tbMore.setIconSize(QSize(iPx, iPx)) self.tbMore.setMenu(self.mMore) - self.tbMore.setPopupMode(QToolButton.ToolButtonPopupMode.InstantPopup) # Assemble self.outerBox = QHBoxLayout() @@ -280,16 +278,10 @@ class GuiNovelToolBar(QWidget): self.setPalette(qPalette) # StyleSheets - fadeCol = qPalette.text().color() - buttonStyle = ( - "QToolButton {{padding: {0}px; border: none; background: transparent;}} " - "QToolButton:hover {{border: none; background: rgba({1},{2},{3},0.2);}}" - ).format(CONFIG.pxInt(2), fadeCol.red(), fadeCol.green(), fadeCol.blue()) - buttonStyleMenu = f"{buttonStyle} QToolButton::menu-indicator {{image: none;}}" - + buttonStyle = SHARED.theme.getStyleSheet(STYLES_MIN_TOOLBUTTON) self.tbNovel.setStyleSheet(buttonStyle) self.tbRefresh.setStyleSheet(buttonStyle) - self.tbMore.setStyleSheet(buttonStyleMenu) + self.tbMore.setStyleSheet(buttonStyle) self.novelValue.setStyleSheet( "QComboBox {border-style: none; padding-left: 0;} " diff --git a/novelwriter/gui/projtree.py b/novelwriter/gui/projtree.py index 674f9da2..7299aff0 100644 --- a/novelwriter/gui/projtree.py +++ b/novelwriter/gui/projtree.py @@ -38,20 +38,22 @@ from PyQt5.QtGui import ( from PyQt5.QtCore import QPoint, QTimer, Qt, QSize, pyqtSignal, pyqtSlot from PyQt5.QtWidgets import ( QAbstractItemView, QAction, QDialog, QFrame, QHBoxLayout, QHeaderView, - QLabel, QMenu, QShortcut, QSizePolicy, QToolButton, QTreeWidget, - QTreeWidgetItem, QVBoxLayout, QWidget + QLabel, QMenu, QShortcut, QSizePolicy, QTreeWidget, QTreeWidgetItem, + QVBoxLayout, QWidget ) from novelwriter import CONFIG, SHARED -from novelwriter.enum import nwDocMode, nwItemType, nwItemClass, nwItemLayout from novelwriter.common import minmax from novelwriter.constants import nwHeaders, nwUnicode, trConst, nwLabels -from novelwriter.core.item import NWItem from novelwriter.core.coretools import DocDuplicator, DocMerger, DocSplitter +from novelwriter.core.item import NWItem from novelwriter.dialogs.docmerge import GuiDocMerge from novelwriter.dialogs.docsplit import GuiDocSplit from novelwriter.dialogs.editlabel import GuiEditLabel from novelwriter.dialogs.projectsettings import GuiProjectSettings +from novelwriter.enum import nwDocMode, nwItemType, nwItemClass, nwItemLayout +from novelwriter.extensions.modified import NIconToolButton +from novelwriter.gui.theme import STYLES_MIN_TOOLBUTTON if TYPE_CHECKING: # pragma: no cover from novelwriter.guimain import GuiMain @@ -275,22 +277,18 @@ class GuiProjectToolBar(QWidget): # Quick Links self.mQuick = QMenu(self) - self.tbQuick = QToolButton(self) + self.tbQuick = NIconToolButton(self, iPx) self.tbQuick.setToolTip("%s [Ctrl+L]" % self.tr("Quick Links")) self.tbQuick.setShortcut("Ctrl+L") - self.tbQuick.setIconSize(QSize(iPx, iPx)) self.tbQuick.setMenu(self.mQuick) - self.tbQuick.setPopupMode(QToolButton.ToolButtonPopupMode.InstantPopup) # Move Buttons - self.tbMoveU = QToolButton(self) + self.tbMoveU = NIconToolButton(self, iPx) self.tbMoveU.setToolTip("%s [Ctrl+Up]" % self.tr("Move Up")) - self.tbMoveU.setIconSize(QSize(iPx, iPx)) self.tbMoveU.clicked.connect(lambda: self.projTree.moveTreeItem(-1)) - self.tbMoveD = QToolButton(self) + self.tbMoveD = NIconToolButton(self, iPx) self.tbMoveD.setToolTip("%s [Ctrl+Down]" % self.tr("Move Down")) - self.tbMoveD.setIconSize(QSize(iPx, iPx)) self.tbMoveD.clicked.connect(lambda: self.projTree.moveTreeItem(1)) # Add Item Menu @@ -329,12 +327,10 @@ class GuiProjectToolBar(QWidget): self.mAddRoot = self.mAdd.addMenu(trConst(nwLabels.ITEM_DESCRIPTION["root"])) self._buildRootMenu() - self.tbAdd = QToolButton(self) + self.tbAdd = NIconToolButton(self, iPx) self.tbAdd.setToolTip("%s [Ctrl+N]" % self.tr("Add Item")) self.tbAdd.setShortcut("Ctrl+N") - self.tbAdd.setIconSize(QSize(iPx, iPx)) self.tbAdd.setMenu(self.mAdd) - self.tbAdd.setPopupMode(QToolButton.ToolButtonPopupMode.InstantPopup) # More Options Menu self.mMore = QMenu(self) @@ -348,11 +344,9 @@ class GuiProjectToolBar(QWidget): self.aEmptyTrash = self.mMore.addAction(self.tr("Empty Trash")) self.aEmptyTrash.triggered.connect(lambda: self.projTree.emptyTrash()) - self.tbMore = QToolButton(self) + self.tbMore = NIconToolButton(self, iPx) self.tbMore.setToolTip(self.tr("More Options")) - self.tbMore.setIconSize(QSize(iPx, iPx)) self.tbMore.setMenu(self.mMore) - self.tbMore.setPopupMode(QToolButton.ToolButtonPopupMode.InstantPopup) # Assemble self.outerBox = QHBoxLayout() @@ -382,18 +376,12 @@ class GuiProjectToolBar(QWidget): qPalette.setBrush(QPalette.ColorRole.Window, qPalette.base()) self.setPalette(qPalette) - fadeCol = qPalette.text().color() - buttonStyle = ( - "QToolButton {{padding: {0}px; border: none; background: transparent;}} " - "QToolButton:hover {{border: none; background: rgba({1},{2},{3},0.2);}}" - ).format(CONFIG.pxInt(2), fadeCol.red(), fadeCol.green(), fadeCol.blue()) - buttonStyleMenu = f"{buttonStyle} QToolButton::menu-indicator {{image: none;}}" - - self.tbQuick.setStyleSheet(buttonStyleMenu) + buttonStyle = SHARED.theme.getStyleSheet(STYLES_MIN_TOOLBUTTON) + self.tbQuick.setStyleSheet(buttonStyle) self.tbMoveU.setStyleSheet(buttonStyle) self.tbMoveD.setStyleSheet(buttonStyle) - self.tbAdd.setStyleSheet(buttonStyleMenu) - self.tbMore.setStyleSheet(buttonStyleMenu) + self.tbAdd.setStyleSheet(buttonStyle) + self.tbMore.setStyleSheet(buttonStyle) self.tbQuick.setIcon(SHARED.theme.getIcon("bookmark")) self.tbMoveU.setIcon(SHARED.theme.getIcon("up")) diff --git a/novelwriter/gui/sidebar.py b/novelwriter/gui/sidebar.py index d425ccf8..9497444d 100644 --- a/novelwriter/gui/sidebar.py +++ b/novelwriter/gui/sidebar.py @@ -28,12 +28,14 @@ import logging from typing import TYPE_CHECKING from PyQt5.QtGui import QPalette -from PyQt5.QtCore import QEvent, QPoint, Qt, QSize, pyqtSignal -from PyQt5.QtWidgets import QMenu, QToolButton, QVBoxLayout, QWidget +from PyQt5.QtCore import QEvent, QPoint, pyqtSignal +from PyQt5.QtWidgets import QMenu, QVBoxLayout, QWidget from novelwriter import CONFIG, SHARED from novelwriter.enum import nwView from novelwriter.extensions.eventfilters import StatusTipFilter +from novelwriter.extensions.modified import NIconToolButton +from novelwriter.gui.theme import STYLES_BIG_TOOLBUTTON if TYPE_CHECKING: # pragma: no cover from novelwriter.guimain import GuiMain @@ -53,46 +55,37 @@ class GuiSideBar(QWidget): self.mainGui = mainGui iPx = CONFIG.pxInt(24) - iconSize = QSize(iPx, iPx) self.setContentsMargins(0, 0, 0, 0) self.installEventFilter(StatusTipFilter(mainGui)) # Buttons - self.tbProject = QToolButton(self) + self.tbProject = NIconToolButton(self, iPx) self.tbProject.setToolTip("{0} [Ctrl+T]".format(self.tr("Project Tree View"))) - self.tbProject.setIconSize(iconSize) self.tbProject.clicked.connect(lambda: self.viewChangeRequested.emit(nwView.PROJECT)) - self.tbNovel = QToolButton(self) + self.tbNovel = NIconToolButton(self, iPx) self.tbNovel.setToolTip("{0} [Ctrl+T]".format(self.tr("Novel Tree View"))) - self.tbNovel.setIconSize(iconSize) self.tbNovel.clicked.connect(lambda: self.viewChangeRequested.emit(nwView.NOVEL)) - self.tbOutline = QToolButton(self) + self.tbOutline = NIconToolButton(self, iPx) self.tbOutline.setToolTip("{0} [Ctrl+Shift+T]".format(self.tr("Novel Outline View"))) - self.tbOutline.setIconSize(iconSize) self.tbOutline.clicked.connect(lambda: self.viewChangeRequested.emit(nwView.OUTLINE)) - self.tbBuild = QToolButton(self) + self.tbBuild = NIconToolButton(self, iPx) self.tbBuild.setToolTip("{0} [F5]".format(self.tr("Build Manuscript"))) - self.tbBuild.setIconSize(iconSize) self.tbBuild.clicked.connect(self.mainGui.showBuildManuscriptDialog) - self.tbDetails = QToolButton(self) + self.tbDetails = NIconToolButton(self, iPx) self.tbDetails.setToolTip("{0} [Shift+F6]".format(self.tr("Novel Details"))) - self.tbDetails.setIconSize(iconSize) self.tbDetails.clicked.connect(self.mainGui.showNovelDetailsDialog) - self.tbStats = QToolButton(self) + self.tbStats = NIconToolButton(self, iPx) self.tbStats.setToolTip("{0} [F6]".format(self.tr("Writing Statistics"))) - self.tbStats.setIconSize(iconSize) self.tbStats.clicked.connect(self.mainGui.showWritingStatsDialog) # Settings Menu - self.tbSettings = QToolButton(self) + self.tbSettings = NIconToolButton(self, iPx) self.tbSettings.setToolTip(self.tr("Settings")) - self.tbSettings.setIconSize(iconSize) - self.tbSettings.setToolButtonStyle(Qt.ToolButtonStyle.ToolButtonIconOnly) self.mSettings = _PopRightMenu(self.tbSettings) self.mSettings.addAction(self.mainGui.mainMenu.aEditWordList) @@ -101,7 +94,6 @@ class GuiSideBar(QWidget): self.mSettings.addAction(self.mainGui.mainMenu.aPreferences) self.tbSettings.setMenu(self.mSettings) - self.tbSettings.setPopupMode(QToolButton.InstantPopup) # Assemble self.outerBox = QVBoxLayout() @@ -129,12 +121,7 @@ class GuiSideBar(QWidget): qPalette.setBrush(QPalette.Window, qPalette.base()) self.setPalette(qPalette) - fadeCol = qPalette.text().color() - buttonStyle = ( - "QToolButton {{padding: {0}px; border: none; background: transparent;}} " - "QToolButton:hover {{border: none; background: rgba({1},{2},{3},0.2);}}" - ).format(CONFIG.pxInt(6), fadeCol.red(), fadeCol.green(), fadeCol.blue()) - buttonStyleMenu = f"{buttonStyle} QToolButton::menu-indicator {{image: none;}}" + buttonStyle = SHARED.theme.getStyleSheet(STYLES_BIG_TOOLBUTTON) self.tbProject.setIcon(SHARED.theme.getIcon("view_editor")) self.tbProject.setStyleSheet(buttonStyle) @@ -155,7 +142,7 @@ class GuiSideBar(QWidget): self.tbStats.setStyleSheet(buttonStyle) self.tbSettings.setIcon(SHARED.theme.getIcon("settings")) - self.tbSettings.setStyleSheet(buttonStyleMenu) + self.tbSettings.setStyleSheet(buttonStyle) return diff --git a/novelwriter/gui/theme.py b/novelwriter/gui/theme.py index 548ed327..8ffe396e 100644 --- a/novelwriter/gui/theme.py +++ b/novelwriter/gui/theme.py @@ -43,6 +43,10 @@ from novelwriter.constants import nwLabels logger = logging.getLogger(__name__) +STYLES_FLAT_TABS = "flatTabWidget" +STYLES_MIN_TOOLBUTTON = "minimalToolButton" +STYLES_BIG_TOOLBUTTON = "bigToolButton" + # =============================================================================================== # # Gui Theme Class @@ -120,6 +124,7 @@ class GuiTheme: self._syntaxList: list[tuple[str, str]] = [] self._availThemes: dict[str, Path] = {} self._availSyntax: dict[str, Path] = {} + self._styleSheets: dict[str, str] = {} self._listConf(self._availSyntax, CONFIG.assetPath("syntax")) self._listConf(self._availThemes, CONFIG.assetPath("themes")) @@ -272,6 +277,9 @@ class GuiTheme: # Apply Styles qApp.setPalette(self._guiPalette) + # Reset stylesheets so that they are regenerated + self._buildStyleSheets(self._guiPalette) + return True def loadSyntax(self) -> bool: @@ -366,6 +374,10 @@ class GuiTheme: return self._syntaxList + def getStyleSheet(self, name: str) -> str: + """Load a standard style sheet.""" + return self._styleSheets.get(name, "") + ## # Internal Functions ## @@ -412,6 +424,41 @@ class GuiTheme: self._guiPalette.setColor(value, self._parseColour(parser, section, name)) return + def _buildStyleSheets(self, palette: QPalette) -> None: + """Build default style sheets.""" + self._styleSheets = {} + + aPx = CONFIG.pxInt(2) + bPx = CONFIG.pxInt(4) + cPx = CONFIG.pxInt(6) + dPx = CONFIG.pxInt(8) + + tCol = palette.text().color() + hCol = palette.highlight().color() + + # Flat Tab Widget and Tab Bar: + self._styleSheets[STYLES_FLAT_TABS] = ( + "QTabWidget::pane {{border: 0;}} " + "QTabWidget QTabBar::tab {{border: 0; padding: {0}px {1}px;}} " + "QTabWidget QTabBar::tab:selected {{color: rgb({2}, {3}, {4});}} " + ).format(bPx, dPx, hCol.red(), hCol.green(), hCol.blue()) + + # Minimal Tool Button + self._styleSheets[STYLES_MIN_TOOLBUTTON] = ( + "QToolButton {{padding: {0}px; margin: 0; border: none; background: transparent;}} " + "QToolButton:hover {{border: none; background: rgba({1}, {2}, {3}, 0.2);}} " + "QToolButton::menu-indicator {{image: none;}} " + ).format(aPx, tCol.red(), tCol.green(), tCol.blue()) + + # Big Tool Button + self._styleSheets[STYLES_BIG_TOOLBUTTON] = ( + "QToolButton {{padding: {0}px; margin: 0; border: none; background: transparent;}} " + "QToolButton:hover {{border: none; background: rgba({1}, {2}, {3}, 0.2);}} " + "QToolButton::menu-indicator {{image: none;}} " + ).format(cPx, tCol.red(), tCol.green(), tCol.blue()) + + return + # End Class GuiTheme diff --git a/novelwriter/tools/manuscript.py b/novelwriter/tools/manuscript.py index 0e89b3c6..316c2541 100644 --- a/novelwriter/tools/manuscript.py +++ b/novelwriter/tools/manuscript.py @@ -35,21 +35,23 @@ from PyQt5.QtCore import QSize, QTimer, Qt, pyqtSlot from PyQt5.QtWidgets import ( QAbstractItemView, QDialog, QFormLayout, QGridLayout, QHBoxLayout, QLabel, QListWidget, QListWidgetItem, QPushButton, QSizePolicy, QSplitter, - QStackedWidget, QTextBrowser, QToolButton, QTreeWidget, QTreeWidgetItem, + QStackedWidget, QTabWidget, QTextBrowser, QTreeWidget, QTreeWidgetItem, QVBoxLayout, QWidget, qApp ) from PyQt5.QtPrintSupport import QPrintPreviewDialog, QPrinter from novelwriter import CONFIG, SHARED -from novelwriter.error import logException from novelwriter.common import checkInt, fuzzyTime -from novelwriter.core.tohtml import ToHtml -from novelwriter.core.docbuild import NWBuildDocument -from novelwriter.core.tokenizer import HeadingFormatter from novelwriter.core.buildsettings import BuildCollection, BuildSettings +from novelwriter.core.docbuild import NWBuildDocument +from novelwriter.core.tohtml import ToHtml +from novelwriter.core.tokenizer import HeadingFormatter +from novelwriter.error import logException +from novelwriter.extensions.circularprogress import NProgressCircle +from novelwriter.extensions.modified import NIconToolButton +from novelwriter.gui.theme import STYLES_FLAT_TABS, STYLES_MIN_TOOLBUTTON from novelwriter.tools.manusbuild import GuiManuscriptBuild from novelwriter.tools.manussettings import GuiBuildSettings -from novelwriter.extensions.circularprogress import NProgressCircle if TYPE_CHECKING: # pragma: no cover from novelwriter.guimain import GuiMain @@ -101,29 +103,22 @@ class GuiManuscript(QDialog): qPalette.setBrush(QPalette.Window, qPalette.base()) self.setPalette(qPalette) - fadeCol = qPalette.text().color() - buttonStyle = ( - "QToolButton {{padding: {0}px; border: none; background: transparent;}} " - "QToolButton:hover {{border: none; background: rgba({1},{2},{3},0.2);}}" - ).format(CONFIG.pxInt(2), fadeCol.red(), fadeCol.green(), fadeCol.blue()) + buttonStyle = SHARED.theme.getStyleSheet(STYLES_MIN_TOOLBUTTON) - self.tbAdd = QToolButton(self) + self.tbAdd = NIconToolButton(self, iPx) self.tbAdd.setIcon(SHARED.theme.getIcon("add")) - self.tbAdd.setIconSize(QSize(iPx, iPx)) self.tbAdd.setToolTip(self.tr("Add New Build")) self.tbAdd.setStyleSheet(buttonStyle) self.tbAdd.clicked.connect(self._createNewBuild) - self.tbDel = QToolButton(self) + self.tbDel = NIconToolButton(self, iPx) self.tbDel.setIcon(SHARED.theme.getIcon("remove")) - self.tbDel.setIconSize(QSize(iPx, iPx)) self.tbDel.setToolTip(self.tr("Delete Selected Build")) self.tbDel.setStyleSheet(buttonStyle) self.tbDel.clicked.connect(self._deleteSelectedBuild) - self.tbEdit = QToolButton(self) + self.tbEdit = NIconToolButton(self, iPx) self.tbEdit.setIcon(SHARED.theme.getIcon("edit")) - self.tbEdit.setIconSize(QSize(iPx, iPx)) self.tbEdit.setToolTip(self.tr("Edit Selected Build")) self.tbEdit.setStyleSheet(buttonStyle) self.tbEdit.clicked.connect(self._editSelectedBuild) @@ -141,21 +136,28 @@ class GuiManuscript(QDialog): # Builds # ====== - self.buildList = QListWidget() + self.buildList = QListWidget(self) self.buildList.setIconSize(QSize(iPx, iPx)) self.buildList.doubleClicked.connect(self._editSelectedBuild) self.buildList.currentItemChanged.connect(self._updateBuildDetails) self.buildList.setSelectionMode(QAbstractItemView.SingleSelection) self.buildList.setDragDropMode(QAbstractItemView.InternalMove) + # Details Tabs + # ============ + self.buildDetails = _DetailsWidget(self) self.buildDetails.setColumnWidth( CONFIG.pxInt(pOptions.getInt("GuiManuscript", "detailsWidth", 100)), ) + self.detailsTabs = QTabWidget(self) + self.detailsTabs.addTab(self.buildDetails, self.tr("Build")) + self.detailsTabs.setStyleSheet(SHARED.theme.getStyleSheet(STYLES_FLAT_TABS)) + self.buildSplit = QSplitter(Qt.Orientation.Vertical, self) self.buildSplit.addWidget(self.buildList) - self.buildSplit.addWidget(self.buildDetails) + self.buildSplit.addWidget(self.detailsTabs) self.buildSplit.setSizes([ CONFIG.pxInt(pOptions.getInt("GuiManuscript", "listHeight", 50)), CONFIG.pxInt(pOptions.getInt("GuiManuscript", "detailsHeight", 50)), @@ -882,19 +884,13 @@ class _StatsWidget(QWidget): self.minWidget = QWidget(self) self.maxWidget = QWidget(self) - fPx = int(0.6*SHARED.theme.fontPixelSize) - toggleIcon = SHARED.theme.getToggleIcon("unfold", (fPx, fPx)) + iPx = int(0.6*SHARED.theme.baseIconSize) + toggleIcon = SHARED.theme.getToggleIcon("unfold", (iPx, iPx)) - fadeCol = self.palette().text().color() - buttonStyle = ( - "QToolButton {{padding: 0; border: none; background: transparent;}} " - "QToolButton:hover {{border: none; background: rgba({0},{1},{2},0.2);}}" - ).format(fadeCol.red(), fadeCol.green(), fadeCol.blue()) - - self.toggleButton = QToolButton(self) + self.toggleButton = NIconToolButton(self, iPx) self.toggleButton.setCheckable(True) self.toggleButton.setIcon(toggleIcon) - self.toggleButton.setStyleSheet(buttonStyle) + self.toggleButton.setStyleSheet(SHARED.theme.getStyleSheet(STYLES_MIN_TOOLBUTTON)) self.toggleButton.toggled.connect(self._toggleView) self._buildMinimal()