Make some minor modifications to the doc toolbar, and add typings in themes

This commit is contained in:
Veronica Berglyd Olsen
2023-11-08 21:27:14 +01:00
parent 9a1947c0f5
commit 003615c3be
4 changed files with 69 additions and 86 deletions
+1 -13
View File
@@ -2188,18 +2188,6 @@ class GuiDocToolBar(QWidget):
palette.setColor(QPalette.Text, QColor(*SHARED.theme.colText)) palette.setColor(QPalette.Text, QColor(*SHARED.theme.colText))
self.setPalette(palette) self.setPalette(palette)
# qPalette = self.palette()
# 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(4), fadeCol.red(), fadeCol.green(), fadeCol.blue())
# buttonStyleMenu = f"{buttonStyle} QToolButton::menu-indicator {{image: none;}}"
# self.tbEdit.setStyleSheet(buttonStyle)
tPx = int(0.8*SHARED.theme.fontPixelSize) tPx = int(0.8*SHARED.theme.fontPixelSize)
self.tbMode.setIcon(SHARED.theme.getToggleIcon("fmt_mode", (tPx, tPx))) self.tbMode.setIcon(SHARED.theme.getToggleIcon("fmt_mode", (tPx, tPx)))
self.tbBold.setIcon(SHARED.theme.getIcon("fmt_bold")) self.tbBold.setIcon(SHARED.theme.getIcon("fmt_bold"))
@@ -2212,7 +2200,7 @@ class GuiDocToolBar(QWidget):
return return
## ##
# Internal Slots # Private Slots
## ##
@pyqtSlot(bool) @pyqtSlot(bool)
+1 -1
View File
@@ -468,7 +468,7 @@ class GuiNovelTree(QTreeWidget):
def updateTheme(self) -> None: def updateTheme(self) -> None:
"""Update theme elements.""" """Update theme elements."""
iPx = SHARED.theme.baseIconSize iPx = SHARED.theme.baseIconSize
self._pMore = SHARED.theme.loadDecoration("deco_doc_more", pxH=iPx) self._pMore = SHARED.theme.loadDecoration("deco_doc_more", h=iPx)
return return
## ##
+64 -69
View File
@@ -36,7 +36,7 @@ from PyQt5.QtGui import (
) )
from novelwriter import CONFIG from novelwriter import CONFIG
from novelwriter.enum import nwItemLayout, nwItemType from novelwriter.enum import nwItemClass, nwItemLayout, nwItemType
from novelwriter.error import logException from novelwriter.error import logException
from novelwriter.common import NWConfigParser, minmax from novelwriter.common import NWConfigParser, minmax
from novelwriter.constants import nwLabels from novelwriter.constants import nwLabels
@@ -51,7 +51,7 @@ logger = logging.getLogger(__name__)
class GuiTheme: class GuiTheme:
def __init__(self): def __init__(self) -> None:
self.iconCache = GuiIcons(self) self.iconCache = GuiIcons(self)
@@ -183,7 +183,7 @@ class GuiTheme:
# Theme Methods # Theme Methods
## ##
def loadTheme(self): def loadTheme(self) -> bool:
"""Load the currently specified GUI theme.""" """Load the currently specified GUI theme."""
guiTheme = CONFIG.guiTheme guiTheme = CONFIG.guiTheme
if guiTheme not in self._availThemes: if guiTheme not in self._availThemes:
@@ -270,7 +270,7 @@ class GuiTheme:
return True return True
def loadSyntax(self): def loadSyntax(self) -> bool:
"""Load the currently specified syntax highlighter theme.""" """Load the currently specified syntax highlighter theme."""
guiSyntax = CONFIG.guiSyntax guiSyntax = CONFIG.guiSyntax
if guiSyntax not in self._availSyntax: if guiSyntax not in self._availSyntax:
@@ -364,7 +364,7 @@ class GuiTheme:
# Internal Functions # Internal Functions
## ##
def _setGuiFont(self): def _setGuiFont(self) -> None:
"""Update the GUI's font style from settings.""" """Update the GUI's font style from settings."""
theFont = QFont() theFont = QFont()
fontDB = QFontDatabase() fontDB = QFontDatabase()
@@ -396,9 +396,7 @@ class GuiTheme:
return True return True
def _parseColour( def _parseColour(self, parser: NWConfigParser, section: str, name: str) -> list[int]:
self, parser: NWConfigParser, section: str, name: str
) -> list[int]:
"""Parse a colour value from a config string.""" """Parse a colour value from a config string."""
if parser.has_option(section, name): if parser.has_option(section, name):
values = parser.get(section, name).split(",") values = parser.get(section, name).split(",")
@@ -415,9 +413,8 @@ class GuiTheme:
result = [0, 0, 0] result = [0, 0, 0]
return result return result
def _setPalette( def _setPalette(self, parser: NWConfigParser, section: str,
self, parser: NWConfigParser, section: str, name: str, value: QPalette.ColorRole name: str, value: QPalette.ColorRole) -> None:
):
"""Set a palette colour value from a config string.""" """Set a palette colour value from a config string."""
self._guiPalette.setColor( self._guiPalette.setColor(
value, QColor(*self._parseColour(parser, section, name)) value, QColor(*self._parseColour(parser, section, name))
@@ -488,17 +485,17 @@ class GuiIcons:
"wiz-back": "wizard-back.jpg", "wiz-back": "wizard-back.jpg",
} }
def __init__(self, mainTheme): def __init__(self, mainTheme: GuiTheme) -> None:
self.mainTheme = mainTheme self.mainTheme = mainTheme
# Storage # Storage
self._qIcons = {} self._qIcons: dict[str, QIcon] = {}
self._themeMap = {} self._themeMap: dict[str, Path] = {}
self._headerDec = [] self._headerDec: list[QPixmap] = []
self._confName = "icons.conf"
# Icon Theme Path # Icon Theme Path
self._confName = "icons.conf"
self._iconPath = CONFIG.assetPath("icons") self._iconPath = CONFIG.assetPath("icons")
# Icon Theme Meta # Icon Theme Meta
@@ -516,7 +513,7 @@ class GuiIcons:
# Actions # Actions
## ##
def loadTheme(self, iconTheme): def loadTheme(self, iconTheme: str) -> bool:
"""Update the theme map. This is more of an init, since many of """Update the theme map. This is more of an init, since many of
the GUI icons cannot really be replaced without writing specific the GUI icons cannot really be replaced without writing specific
update functions for the classes where they're used. update functions for the classes where they're used.
@@ -590,60 +587,60 @@ class GuiIcons:
# Access Functions # Access Functions
## ##
def loadDecoration(self, decoKey, pxW=None, pxH=None): def loadDecoration(self, name: str, w: int | None = None, h: int | None = None) -> QPixmap:
"""Load graphical decoration element based on the decoration """Load graphical decoration element based on the decoration
map or the icon map. This function always returns a QPixmap. map or the icon map. This function always returns a QPixmap.
""" """
if decoKey in self._themeMap: if name in self._themeMap:
imgPath = self._themeMap[decoKey] imgPath = self._themeMap[name]
elif decoKey in self.IMAGE_MAP: elif name in self.IMAGE_MAP:
imgPath = CONFIG.assetPath("images") / self.IMAGE_MAP[decoKey] imgPath = CONFIG.assetPath("images") / self.IMAGE_MAP[name]
else: else:
logger.error("Decoration with name '%s' does not exist", decoKey) logger.error("Decoration with name '%s' does not exist", name)
return QPixmap() return QPixmap()
if not imgPath.is_file(): if not imgPath.is_file():
logger.error("Asset not found: %s", imgPath) logger.error("Asset not found: %s", imgPath)
return QPixmap() return QPixmap()
theDeco = QPixmap(str(imgPath)) pixmap = QPixmap(str(imgPath))
if pxW is not None and pxH is not None: if w is not None and h is not None:
return theDeco.scaled(pxW, pxH, Qt.IgnoreAspectRatio, Qt.SmoothTransformation) return pixmap.scaled(w, h, Qt.IgnoreAspectRatio, Qt.SmoothTransformation)
elif pxW is None and pxH is not None: elif w is None and h is not None:
return theDeco.scaledToHeight(pxH, Qt.SmoothTransformation) return pixmap.scaledToHeight(h, Qt.SmoothTransformation)
elif pxW is not None and pxH is None: elif w is not None and h is None:
return theDeco.scaledToWidth(pxW, Qt.SmoothTransformation) return pixmap.scaledToWidth(w, Qt.SmoothTransformation)
return theDeco return pixmap
def getIcon(self, iconKey): def getIcon(self, name: str) -> QIcon:
"""Return an icon from the icon buffer, or load it.""" """Return an icon from the icon buffer, or load it."""
if iconKey in self._qIcons: if name in self._qIcons:
return self._qIcons[iconKey] return self._qIcons[name]
else: else:
qIcon = self._loadIcon(iconKey) icon = self._loadIcon(name)
self._qIcons[iconKey] = qIcon self._qIcons[name] = icon
return qIcon return icon
def getToggleIcon(self, iconKey: str, iconSize: tuple[int, int]) -> QIcon: def getToggleIcon(self, name: str, size: tuple[int, int]) -> QIcon:
"""Return a toggle icon from the icon buffer. or load it.""" """Return a toggle icon from the icon buffer. or load it."""
if iconKey in self.TOGGLE_ICON_KEYS: if name in self.TOGGLE_ICON_KEYS:
pixOne = self.getPixmap(self.TOGGLE_ICON_KEYS[iconKey][0], iconSize) pOne = self.getPixmap(self.TOGGLE_ICON_KEYS[name][0], size)
pixTwo = self.getPixmap(self.TOGGLE_ICON_KEYS[iconKey][1], iconSize) pTwo = self.getPixmap(self.TOGGLE_ICON_KEYS[name][1], size)
qIcon = QIcon() icon = QIcon()
qIcon.addPixmap(pixOne, QIcon.Normal, QIcon.On) icon.addPixmap(pOne, QIcon.Normal, QIcon.On)
qIcon.addPixmap(pixTwo, QIcon.Normal, QIcon.Off) icon.addPixmap(pTwo, QIcon.Normal, QIcon.Off)
return qIcon return icon
return QIcon() return QIcon()
def getPixmap(self, iconKey, iconSize): def getPixmap(self, name: str, size: tuple[int, int]) -> QPixmap:
"""Return an icon from the icon buffer as a QPixmap. If it """Return an icon from the icon buffer as a QPixmap. If it
doesn't exist, return an empty QPixmap. doesn't exist, return an empty QPixmap.
""" """
qIcon = self.getIcon(iconKey) return self.getIcon(name).pixmap(size[0], size[1], QIcon.Normal)
return qIcon.pixmap(iconSize[0], iconSize[1], QIcon.Normal)
def getItemIcon(self, tType, tClass, tLayout, hLevel="H0"): def getItemIcon(self, tType: nwItemType, tClass: nwItemClass,
tLayout: nwItemLayout, hLevel: str = "H0") -> QIcon:
"""Get the correct icon for a project item based on type, class """Get the correct icon for a project item based on type, class
and header level and header level
""" """
@@ -670,17 +667,16 @@ class GuiIcons:
return self.getIcon(iconName) return self.getIcon(iconName)
def getHeaderDecoration(self, hLevel): def getHeaderDecoration(self, hLevel: int) -> QPixmap:
"""Get the decoration for a specific header level. """Get the decoration for a specific header level."""
"""
if not self._headerDec: if not self._headerDec:
iPx = self.mainTheme.baseIconSize iPx = self.mainTheme.baseIconSize
self._headerDec = [ self._headerDec = [
self.loadDecoration("deco_doc_h0", pxH=iPx), self.loadDecoration("deco_doc_h0", h=iPx),
self.loadDecoration("deco_doc_h1", pxH=iPx), self.loadDecoration("deco_doc_h1", h=iPx),
self.loadDecoration("deco_doc_h2", pxH=iPx), self.loadDecoration("deco_doc_h2", h=iPx),
self.loadDecoration("deco_doc_h3", pxH=iPx), self.loadDecoration("deco_doc_h3", h=iPx),
self.loadDecoration("deco_doc_h4", pxH=iPx), self.loadDecoration("deco_doc_h4", h=iPx),
] ]
return self._headerDec[minmax(hLevel, 0, 4)] return self._headerDec[minmax(hLevel, 0, 4)]
@@ -688,27 +684,27 @@ class GuiIcons:
# Internal Functions # Internal Functions
## ##
def _loadIcon(self, iconKey): def _loadIcon(self, name: str) -> QIcon:
"""Load an icon from the assets themes folder. Is guaranteed to """Load an icon from the assets themes folder. Is guaranteed to
return a QIcon. return a QIcon.
""" """
if iconKey not in self.ICON_KEYS: if name not in self.ICON_KEYS:
logger.error("Requested unknown icon name '%s'", iconKey) logger.error("Requested unknown icon name '%s'", name)
return QIcon() return QIcon()
# If we just want the app icons, return right away # If we just want the app icons, return right away
if iconKey == "novelwriter": if name == "novelwriter":
return QIcon(str(self._iconPath / "novelwriter.svg")) return QIcon(str(self._iconPath / "novelwriter.svg"))
elif iconKey == "proj_nwx": elif name == "proj_nwx":
return QIcon(str(self._iconPath / "x-novelwriter-project.svg")) return QIcon(str(self._iconPath / "x-novelwriter-project.svg"))
# Otherwise, we load from the theme folder # Otherwise, we load from the theme folder
if iconKey in self._themeMap: if name in self._themeMap:
logger.debug("Loading: %s", self._themeMap[iconKey].name) logger.debug("Loading: %s", self._themeMap[name].name)
return QIcon(str(self._themeMap[iconKey])) return QIcon(str(self._themeMap[name]))
# If we didn't find one, give up and return an empty icon # If we didn't find one, give up and return an empty icon
logger.warning("Did not load an icon for '%s'", iconKey) logger.warning("Did not load an icon for '%s'", name)
return QIcon() return QIcon()
@@ -719,9 +715,8 @@ class GuiIcons:
# Module Functions # Module Functions
# =============================================================================================== # # =============================================================================================== #
def _loadInternalName(confParser, confFile): def _loadInternalName(confParser: NWConfigParser, confFile: str | Path) -> str:
"""Open a conf file and read the 'name' setting. """Open a conf file and read the 'name' setting."""
"""
try: try:
with open(confFile, mode="r", encoding="utf-8") as inFile: with open(confFile, mode="r", encoding="utf-8") as inFile:
confParser.read_file(inFile) confParser.read_file(inFile)
+3 -3
View File
@@ -322,17 +322,17 @@ def testGuiTheme_Icons(qtbot, caplog, monkeypatch, nwGUI, tstPaths):
assert qPix.isNull() is True assert qPix.isNull() is True
# Test image sizes # Test image sizes
qPix = iconCache.loadDecoration("wiz-back", pxW=100, pxH=None) qPix = iconCache.loadDecoration("wiz-back", w=100, h=None)
assert qPix.isNull() is False assert qPix.isNull() is False
assert qPix.width() == 100 assert qPix.width() == 100
assert qPix.height() > 100 assert qPix.height() > 100
qPix = iconCache.loadDecoration("wiz-back", pxW=None, pxH=100) qPix = iconCache.loadDecoration("wiz-back", w=None, h=100)
assert qPix.isNull() is False assert qPix.isNull() is False
assert qPix.width() < 100 assert qPix.width() < 100
assert qPix.height() == 100 assert qPix.height() == 100
qPix = iconCache.loadDecoration("wiz-back", pxW=100, pxH=100) qPix = iconCache.loadDecoration("wiz-back", w=100, h=100)
assert qPix.isNull() is False assert qPix.isNull() is False
assert qPix.width() == 100 assert qPix.width() == 100
assert qPix.height() == 100 assert qPix.height() == 100