Add help text colour as separate setting, and annotate theme class

This commit is contained in:
Veronica Berglyd Olsen
2023-07-19 17:31:02 +02:00
parent 795782320c
commit 2c5799679c
+80 -78
View File
@@ -23,10 +23,12 @@ General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. along with this program. If not, see <https://www.gnu.org/licenses/>.
""" """
from __future__ import annotations
import logging import logging
from math import ceil from math import ceil
from pathlib import Path
from PyQt5.QtCore import Qt from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import qApp from PyQt5.QtWidgets import qApp
@@ -72,6 +74,7 @@ class GuiTheme:
self.statUnsaved = [200, 15, 39] self.statUnsaved = [200, 15, 39]
self.statSaved = [2, 133, 37] self.statSaved = [2, 133, 37]
self.helpText = [0, 0, 0] self.helpText = [0, 0, 0]
self.winBright = [0, 0, 0]
# Loaded Syntax Settings # Loaded Syntax Settings
# ====================== # ======================
@@ -111,10 +114,10 @@ class GuiTheme:
# Load Themes # Load Themes
self._guiPalette = QPalette() self._guiPalette = QPalette()
self._themeList = [] self._themeList: list[tuple[str, str]] = []
self._syntaxList = [] self._syntaxList: list[tuple[str, str]] = []
self._availThemes = {} self._availThemes: dict[str, Path] = {}
self._availSyntax = {} self._availSyntax: dict[str, Path] = {}
self._listConf(self._availSyntax, CONFIG.assetPath("syntax")) self._listConf(self._availSyntax, CONFIG.assetPath("syntax"))
self._listConf(self._availThemes, CONFIG.assetPath("themes")) self._listConf(self._availThemes, CONFIG.assetPath("themes"))
@@ -166,22 +169,22 @@ class GuiTheme:
# Methods # Methods
## ##
def getTextWidth(self, theText, theFont=None): def getTextWidth(self, text: str, font: QFont | None = None) -> int:
"""Returns the width needed to contain a given piece of text. """Returns the width needed to contain a given piece of text in
pixels.
""" """
if isinstance(theFont, QFont): if isinstance(font, QFont):
qMetrics = QFontMetrics(theFont) qMetrics = QFontMetrics(font)
else: else:
qMetrics = QFontMetrics(self.guiFont) qMetrics = QFontMetrics(self.guiFont)
return int(ceil(qMetrics.boundingRect(theText).width())) return int(ceil(qMetrics.boundingRect(text).width()))
## ##
# Theme Methods # Theme Methods
## ##
def loadTheme(self): def loadTheme(self):
"""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:
logger.error("Could not find GUI theme '%s'", guiTheme) logger.error("Could not find GUI theme '%s'", guiTheme)
@@ -195,70 +198,72 @@ class GuiTheme:
# Config File # Config File
logger.info("Loading GUI theme '%s'", guiTheme) logger.info("Loading GUI theme '%s'", guiTheme)
confParser = NWConfigParser() parser = NWConfigParser()
try: try:
with open(themeFile, mode="r", encoding="utf-8") as inFile: with open(themeFile, mode="r", encoding="utf-8") as inFile:
confParser.read_file(inFile) parser.read_file(inFile)
except Exception: except Exception:
logger.error("Could not load theme settings from: %s", themeFile) logger.error("Could not load theme settings from: %s", themeFile)
logException() logException()
return False return False
# Main # Main
cnfSec = "Main" sec = "Main"
if confParser.has_section(cnfSec): if parser.has_section(sec):
self.themeName = confParser.rdStr(cnfSec, "name", "") self.themeName = parser.rdStr(sec, "name", "")
self.themeDescription = confParser.rdStr(cnfSec, "description", "N/A") self.themeDescription = parser.rdStr(sec, "description", "N/A")
self.themeAuthor = confParser.rdStr(cnfSec, "author", "N/A") self.themeAuthor = parser.rdStr(sec, "author", "N/A")
self.themeCredit = confParser.rdStr(cnfSec, "credit", "N/A") self.themeCredit = parser.rdStr(sec, "credit", "N/A")
self.themeUrl = confParser.rdStr(cnfSec, "url", "") self.themeUrl = parser.rdStr(sec, "url", "")
self.themeLicense = confParser.rdStr(cnfSec, "license", "N/A") self.themeLicense = parser.rdStr(sec, "license", "N/A")
self.themeLicenseUrl = confParser.rdStr(cnfSec, "licenseurl", "") self.themeLicenseUrl = parser.rdStr(sec, "licenseurl", "")
self.themeIcons = confParser.rdStr(cnfSec, "icontheme", "") self.themeIcons = parser.rdStr(sec, "icontheme", "")
# Palette # Palette
cnfSec = "Palette" sec = "Palette"
if confParser.has_section(cnfSec): if parser.has_section(sec):
self._setPalette(confParser, cnfSec, "window", QPalette.Window) self._setPalette(parser, sec, "window", QPalette.ColorRole.Window)
self._setPalette(confParser, cnfSec, "windowtext", QPalette.WindowText) self._setPalette(parser, sec, "windowtext", QPalette.ColorRole.WindowText)
self._setPalette(confParser, cnfSec, "base", QPalette.Base) self._setPalette(parser, sec, "base", QPalette.ColorRole.Base)
self._setPalette(confParser, cnfSec, "alternatebase", QPalette.AlternateBase) self._setPalette(parser, sec, "alternatebase", QPalette.ColorRole.AlternateBase)
self._setPalette(confParser, cnfSec, "text", QPalette.Text) self._setPalette(parser, sec, "text", QPalette.ColorRole.Text)
self._setPalette(confParser, cnfSec, "tooltipbase", QPalette.ToolTipBase) self._setPalette(parser, sec, "tooltipbase", QPalette.ColorRole.ToolTipBase)
self._setPalette(confParser, cnfSec, "tooltiptext", QPalette.ToolTipText) self._setPalette(parser, sec, "tooltiptext", QPalette.ColorRole.ToolTipText)
self._setPalette(confParser, cnfSec, "button", QPalette.Button) self._setPalette(parser, sec, "button", QPalette.ColorRole.Button)
self._setPalette(confParser, cnfSec, "buttontext", QPalette.ButtonText) self._setPalette(parser, sec, "buttontext", QPalette.ColorRole.ButtonText)
self._setPalette(confParser, cnfSec, "brighttext", QPalette.BrightText) self._setPalette(parser, sec, "brighttext", QPalette.ColorRole.BrightText)
self._setPalette(confParser, cnfSec, "highlight", QPalette.Highlight) self._setPalette(parser, sec, "highlight", QPalette.ColorRole.Highlight)
self._setPalette(confParser, cnfSec, "highlightedtext", QPalette.HighlightedText) self._setPalette(parser, sec, "highlightedtext", QPalette.ColorRole.HighlightedText)
self._setPalette(confParser, cnfSec, "link", QPalette.Link) self._setPalette(parser, sec, "link", QPalette.ColorRole.Link)
self._setPalette(confParser, cnfSec, "linkvisited", QPalette.LinkVisited) self._setPalette(parser, sec, "linkvisited", QPalette.ColorRole.LinkVisited)
else: else:
self._guiPalette = qApp.style().standardPalette() self._guiPalette = qApp.style().standardPalette()
# GUI # GUI
cnfSec = "GUI" sec = "GUI"
if confParser.has_section(cnfSec): if parser.has_section(sec):
self.statNone = self._parseColour(confParser, cnfSec, "statusnone") self.helpText = self._parseColour(parser, sec, "helptext")
self.statUnsaved = self._parseColour(confParser, cnfSec, "statusunsaved") self.statNone = self._parseColour(parser, sec, "statusnone")
self.statSaved = self._parseColour(confParser, cnfSec, "statussaved") self.statUnsaved = self._parseColour(parser, sec, "statusunsaved")
self.statSaved = self._parseColour(parser, sec, "statussaved")
# Icons
self.iconCache.loadTheme(self.themeIcons or "typicons_light")
# Update Dependant Colours # Update Dependant Colours
backCol = self._guiPalette.window().color() backCol = self._guiPalette.window().color()
textCol = self._guiPalette.windowText().color() textCol = self._guiPalette.windowText().color()
backLCol = backCol.lightnessF() backLNess = backCol.lightnessF()
textLCol = textCol.lightnessF() textLNess = textCol.lightnessF()
if backLCol > textLCol: if self.helpText == [0, 0, 0]:
helpLCol = textLCol + 0.65*(backLCol - textLCol) if backLNess > textLNess:
else: helpLCol = textLNess + 0.35*(backLNess - textLNess)
helpLCol = backLCol + 0.65*(textLCol - backLCol) else:
helpLCol = backLNess + 0.65*(textLNess - backLNess)
self.helpText = [int(255*helpLCol)]*3
self.helpText = [int(255*helpLCol)]*3 # Icons
defaultIcons = "typicons_light" if backLNess >= 0.5 else "typicons_dark"
self.iconCache.loadTheme(self.themeIcons or defaultIcons)
# Apply Styles # Apply Styles
qApp.setPalette(self._guiPalette) qApp.setPalette(self._guiPalette)
@@ -266,8 +271,7 @@ class GuiTheme:
return True return True
def loadSyntax(self): def loadSyntax(self):
"""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:
logger.error("Could not find syntax theme '%s'", guiSyntax) logger.error("Could not find syntax theme '%s'", guiSyntax)
@@ -323,9 +327,8 @@ class GuiTheme:
return True return True
def listThemes(self): def listThemes(self) -> list[tuple[str, str]]:
"""Scan the GUI themes folder and list all themes. """Scan the GUI themes folder and list all themes."""
"""
if self._themeList: if self._themeList:
return self._themeList return self._themeList
@@ -340,9 +343,8 @@ class GuiTheme:
return self._themeList return self._themeList
def listSyntax(self): def listSyntax(self) -> list[tuple[str, str]]:
"""Scan the syntax themes folder and list all themes. """Scan the syntax themes folder and list all themes."""
"""
if self._syntaxList: if self._syntaxList:
return self._syntaxList return self._syntaxList
@@ -362,8 +364,7 @@ class GuiTheme:
## ##
def _setGuiFont(self): def _setGuiFont(self):
"""Update the GUI's font style from settings. """Update the GUI's font style from settings."""
"""
theFont = QFont() theFont = QFont()
fontDB = QFontDatabase() fontDB = QFontDatabase()
if CONFIG.guiFont not in fontDB.families(): if CONFIG.guiFont not in fontDB.families():
@@ -383,9 +384,8 @@ class GuiTheme:
return return
def _listConf(self, targetDict, checkDir): def _listConf(self, targetDict: dict, checkDir: Path) -> bool:
"""Scan for theme config files and populate the dictionary. """Scan for theme config files and populate the dictionary."""
"""
if not checkDir.is_dir(): if not checkDir.is_dir():
return False return False
@@ -395,29 +395,31 @@ class GuiTheme:
return True return True
def _parseColour(self, confParser, cnfSec, cnfName): def _parseColour(
"""Parse a colour value from a config string. self, parser: NWConfigParser, section: str, name: str
""" ) -> list[int]:
if confParser.has_option(cnfSec, cnfName): """Parse a colour value from a config string."""
values = confParser.get(cnfSec, cnfName).split(",") if parser.has_option(section, name):
values = parser.get(section, name).split(",")
result = [] result = []
try: try:
result.append(minmax(int(values[0]), 0, 255)) result.append(minmax(int(values[0]), 0, 255))
result.append(minmax(int(values[1]), 0, 255)) result.append(minmax(int(values[1]), 0, 255))
result.append(minmax(int(values[2]), 0, 255)) result.append(minmax(int(values[2]), 0, 255))
except Exception: except Exception:
logger.error("Could not load theme colours for '%s' from config file", cnfName) logger.error("Could not load theme colours for '%s' from config file", name)
result = [0, 0, 0] result = [0, 0, 0]
else: else:
logger.warning("Could not find theme colours for '%s' in config file", cnfName) logger.warning("Could not find theme colours for '%s' in config file", name)
result = [0, 0, 0] result = [0, 0, 0]
return result return result
def _setPalette(self, confParser, cnfSec, cnfName, paletteVal): def _setPalette(
"""Set a palette colour value from a config string. self, parser: NWConfigParser, section: str, name: str, value: QPalette.ColorRole
""" ):
"""Set a palette colour value from a config string."""
self._guiPalette.setColor( self._guiPalette.setColor(
paletteVal, QColor(*self._parseColour(confParser, cnfSec, cnfName)) value, QColor(*self._parseColour(parser, section, name))
) )
return return