diff --git a/nw/gui/doceditor.py b/nw/gui/doceditor.py index 11acf866..43aaa621 100644 --- a/nw/gui/doceditor.py +++ b/nw/gui/doceditor.py @@ -56,7 +56,7 @@ class GuiDocEditor(QTextEdit): # Core Elements self.theDoc = self.document() self.theDict = enchant.Dict(self.mainConf.spellLanguage) - self.hLight = GuiDocHighlighter(self.theDoc) + self.hLight = GuiDocHighlighter(self.theDoc, self.theParent.theTheme) self.hLight.setDict(self.theDict) # Context Menu diff --git a/nw/gui/dochighlight.py b/nw/gui/dochighlight.py index 30787793..4db6267a 100644 --- a/nw/gui/dochighlight.py +++ b/nw/gui/dochighlight.py @@ -20,27 +20,27 @@ logger = logging.getLogger(__name__) class GuiDocHighlighter(QSyntaxHighlighter): - def __init__(self, theDoc): + def __init__(self, theDoc, theTheme): QSyntaxHighlighter.__init__(self, theDoc) logger.debug("Initialising DocHighlighter ...") self.mainConf = nw.CONFIG self.theDoc = theDoc + self.theTheme = theTheme self.theDict = None self.spellCheck = False self.hRules = [] - self.colHead = QColor( 0,155,200) - self.colHeadH = QColor( 0,105,135) - self.colEmph = QColor(200,120, 0) - self.colDialN = QColor(200, 46, 0) - self.colDialD = QColor(184,200, 0) - self.colDialS = QColor(136,200, 0) - self.colComm = QColor(150,150,150) - self.colKey = QColor(200, 46, 0) - self.colVal = QColor(184,200, 0) - - self.colSpell = QColor(200, 46, 0) + self.colHead = QColor(*self.theTheme.colHead) + self.colHeadH = QColor(*self.theTheme.colHeadH) + self.colEmph = QColor(*self.theTheme.colEmph) + self.colDialN = QColor(*self.theTheme.colDialN) + self.colDialD = QColor(*self.theTheme.colDialD) + self.colDialS = QColor(*self.theTheme.colDialS) + self.colComm = QColor(*self.theTheme.colComm) + self.colKey = QColor(*self.theTheme.colKey) + self.colVal = QColor(*self.theTheme.colVal) + self.colSpell = QColor(*self.theTheme.colSpell) self.hStyles = { "header1" : self._makeFormat(self.colHead, "bold",1.8), diff --git a/nw/gui/docviewer.py b/nw/gui/docviewer.py index 0ab7df11..f179d140 100644 --- a/nw/gui/docviewer.py +++ b/nw/gui/docviewer.py @@ -27,14 +27,16 @@ class GuiDocViewer(QTextBrowser): # Class Variables self.mainConf = nw.CONFIG self.theParent = theParent + self.theTheme = theParent.theTheme self.theDoc = self.document() - self.theDoc.setDefaultStyleSheet(""" - h1, h2, h3, h4 { - color: rgb(0,155,200); - } - """) - + self.theDoc.setDefaultStyleSheet(( + "h1, h2, h3, h4 {{" + " color: rgb({0},{1},{2});" + "}}" + ).format( + *self.theTheme.colHead + )) self.theDoc.setDocumentMargin(self.mainConf.textMargin[0]) self.setMinimumWidth(300) diff --git a/nw/gui/winmain.py b/nw/gui/winmain.py index 084546c1..6bcea030 100644 --- a/nw/gui/winmain.py +++ b/nw/gui/winmain.py @@ -18,6 +18,7 @@ from PyQt5.QtWidgets import QWidget, QMainWindow, QVBoxLayout, QFrame, QSpl from PyQt5.QtGui import QIcon, QPixmap, QColor from PyQt5.QtCore import Qt, QTimer +from nw.theme import Theme from nw.gui.doctree import GuiDocTree from nw.gui.doceditor import GuiDocEditor from nw.gui.docviewer import GuiDocViewer @@ -42,12 +43,14 @@ class GuiMain(QMainWindow): logger.debug("Initialising GUI ...") self.mainConf = nw.CONFIG + self.theTheme = Theme() self.theProject = NWProject(self) self.theDocument = NWDoc(self.theProject, self) self.resize(*self.mainConf.winGeometry) self._setWindowTitle() self.setWindowIcon(QIcon(path.join(self.mainConf.appPath,"..","novelWriter.svg"))) + self.theTheme.loadTheme() # Main GUI Elements self.docEditor = GuiDocEditor(self) @@ -107,11 +110,7 @@ class GuiMain(QMainWindow): self.statusBar.showMessage("Ready") # Load Theme StyleSheet - cssFile = path.join(self.mainConf.themePath,self.mainConf.guiTheme+".css") - if path.isfile(cssFile): - with open(cssFile,mode="r") as inFile: - theCss = inFile.read() - self.setStyleSheet(theCss) + self.setStyleSheet(self.theTheme.cssData) self.asProjTimer = QTimer() self.asProjTimer.setInterval(int(self.mainConf.autoSaveProj*1000)) diff --git a/nw/theme.py b/nw/theme.py new file mode 100644 index 00000000..cab4c302 --- /dev/null +++ b/nw/theme.py @@ -0,0 +1,120 @@ +# -*- coding: utf-8 -*- +"""novelWriter Theme Class + + novelWriter – Theme Class +=========================== + This class reads and store the main theme + + File History: + Created: 2019-05-18 [0.1.3] + +""" + +import logging +import configparser +import nw + +from os import path + +logger = logging.getLogger(__name__) + +class Theme: + + def __init__(self): + + self.mainConf = nw.CONFIG + self.cssName = "styles.css" + self.confName = "theme.conf" + + # Loaded Theme Settings + self.colHead = [0,0,0] + self.colHeadH = [0,0,0] + self.colEmph = [0,0,0] + self.colDialN = [0,0,0] + self.colDialD = [0,0,0] + self.colDialS = [0,0,0] + self.colComm = [0,0,0] + self.colKey = [0,0,0] + self.colVal = [0,0,0] + self.colSpell = [0,0,0] + + # Changeable Settings + self.guiTheme = None + self.themePath = None + self.confFile = None + self.cssFile = None + self.cssData = "" + + self.updateTheme() + + return + + ## + # Actions + ## + + def updateTheme(self): + self.guiTheme = self.mainConf.guiTheme + self.themePath = path.join(self.mainConf.themePath, self.guiTheme) + self.confFile = path.join(self.themePath,self.confName) + self.cssFile = path.join(self.themePath,self.cssName) + return True + + def loadTheme(self): + + logger.debug("Loading theme files") + + # CSS File + try: + if path.isfile(self.cssFile): + with open(self.cssFile,mode="r") as inFile: + self.cssData = inFile.read() + except Exception as e: + logger.error("Could not load theme css file") + return False + + # Color Config + confParser = configparser.ConfigParser() + try: + confParser.read_file(open(self.confFile)) + except Exception as e: + logger.error("Could not load theme config file") + return False + + ## Syntax + cnfSec = "Syntax" + if confParser.has_section(cnfSec): + self.colHead = self._loadColour(confParser,cnfSec,"headertext") + self.colHeadH = self._loadColour(confParser,cnfSec,"headertag") + self.colEmph = self._loadColour(confParser,cnfSec,"emphasis") + self.colDialN = self._loadColour(confParser,cnfSec,"straightquotes") + self.colDialD = self._loadColour(confParser,cnfSec,"doublequotes") + self.colDialS = self._loadColour(confParser,cnfSec,"singlequotes") + self.colComm = self._loadColour(confParser,cnfSec,"hidden") + self.colKey = self._loadColour(confParser,cnfSec,"keyword") + self.colVal = self._loadColour(confParser,cnfSec,"value") + self.colSpell = self._loadColour(confParser,cnfSec,"spellcheckline") + + return True + + ## + # Internal Functions + ## + + def _loadColour(self, confParser, cnfSec, cnfName): + if confParser.has_option(cnfSec,cnfName): + inData = confParser.get(cnfSec,cnfName).split(",") + outData = [] + try: + outData.append(int(inData[0])) + outData.append(int(inData[1])) + outData.append(int(inData[2])) + except: + logger.error("Could not load theme colours for '%s' from config file" % cnfName) + outData = [0,0,0] + else: + logger.warning("Could not find theme colours for '%s' in config file" % cnfName) + outData = [0,0,0] + return outData + +# End Class Theme diff --git a/nw/themes/default.css b/nw/themes/default/styles.css similarity index 100% rename from nw/themes/default.css rename to nw/themes/default/styles.css diff --git a/nw/themes/default/theme.conf b/nw/themes/default/theme.conf new file mode 100644 index 00000000..117f53ea --- /dev/null +++ b/nw/themes/default/theme.conf @@ -0,0 +1,11 @@ +[Syntax] +headertext = 0, 155, 200 +headertag = 0, 105, 135 +emphasis = 200, 120, 0 +straightquotes = 200, 46, 0 +doublequotes = 184, 200, 0 +singlequotes = 136, 200, 0 +hidden = 150, 150, 150 +keyword = 200, 46, 0 +value = 184, 200, 0 +spellcheckline = 200, 46, 0