diff --git a/nw/config.py b/nw/config.py
index bb8498b1..50941257 100644
--- a/nw/config.py
+++ b/nw/config.py
@@ -14,9 +14,11 @@ import logging
import configparser
import nw
-from os import path, mkdir, getcwd
-from appdirs import user_config_dir
-from datetime import datetime
+from os import path, mkdir, getcwd
+from appdirs import user_config_dir
+from datetime import datetime
+
+from nw.constants import nwFiles
logger = logging.getLogger(__name__)
@@ -43,6 +45,7 @@ class Config:
self.homePath = None
self.appPath = None
self.appRoot = None
+ self.appIcon = None
self.guiPath = None
self.themeRoot = None
self.themePath = None
@@ -51,7 +54,8 @@ class Config:
self.confChanged = False
## General
- self.guiTheme = "default_dark"
+ self.guiTheme = "default"
+ self.guiSyntax = "default_light"
self.winGeometry = [1100, 650]
self.treeColWidth = [120, 30, 50]
self.mainPanePos = [300, 800]
@@ -110,6 +114,7 @@ class Config:
self.guiPath = path.join(self.appPath,"gui")
self.themeRoot = path.join(self.appPath,"themes")
self.themePath = path.join(self.themeRoot)
+ self.appIcon = path.join(self.appRoot, nwFiles.APP_ICON)
# If config folder does not exist, make it.
# This assumes that the os config folder itself exists.
@@ -144,7 +149,8 @@ class Config:
## Main
cnfSec = "Main"
- self.guiTheme = self._parseLine(cnfParse, cnfSec, "theme", self.CNF_STR, self.guiTheme)
+ self.guiTheme = self._parseLine(cnfParse, cnfSec, "theme", self.CNF_STR, self.guiTheme)
+ self.guiSyntax = self._parseLine(cnfParse, cnfSec, "syntax", self.CNF_STR, self.guiSyntax)
## Sizes
cnfSec = "Sizes"
@@ -197,6 +203,7 @@ class Config:
cnfParse.add_section(cnfSec)
cnfParse.set(cnfSec,"timestamp", datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
cnfParse.set(cnfSec,"theme", str(self.guiTheme))
+ cnfParse.set(cnfSec,"syntax", str(self.guiSyntax))
## Sizes
cnfSec = "Sizes"
diff --git a/nw/graphics/block.svg b/nw/graphics/block.svg
deleted file mode 100644
index 6546646c..00000000
--- a/nw/graphics/block.svg
+++ /dev/null
@@ -1,38 +0,0 @@
-
-
-
-
-
-
- image/svg+xml
-
-
-
-
-
-
-
-
-
diff --git a/nw/graphics/gear.svg b/nw/graphics/gear.svg
new file mode 100644
index 00000000..b5da5b7a
--- /dev/null
+++ b/nw/graphics/gear.svg
@@ -0,0 +1,48 @@
+
+image/svg+xml
+
+
\ No newline at end of file
diff --git a/nw/graphics/gradient.svg b/nw/graphics/gradient.svg
deleted file mode 100644
index 28f83ef1..00000000
--- a/nw/graphics/gradient.svg
+++ /dev/null
@@ -1,60 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
- image/svg+xml
-
-
-
-
-
-
-
-
-
diff --git a/nw/gui/configeditor.py b/nw/gui/configeditor.py
index 569a6402..d90424f8 100644
--- a/nw/gui/configeditor.py
+++ b/nw/gui/configeditor.py
@@ -15,7 +15,7 @@ import nw
from os import path
-from PyQt5.QtCore import Qt
+from PyQt5.QtCore import Qt, QSize
from PyQt5.QtGui import QIcon, QPixmap, QColor, QBrush, QStandardItemModel, QFont
from PyQt5.QtSvg import QSvgWidget
from PyQt5.QtWidgets import (
@@ -43,9 +43,9 @@ class GuiConfigEditor(QDialog):
self.setWindowTitle("Preferences")
- self.gradPath = path.abspath(path.join(self.mainConf.appPath,"graphics","block.svg"))
- self.svgGradient = QSvgWidget(self.gradPath)
- self.svgGradient.setFixedWidth(80)
+ self.gradPath = path.abspath(path.join(self.mainConf.appPath,"graphics","gear.svg"))
+ self.svgGradient = QSvgWidget(path.join(self.gradPath))
+ self.svgGradient.setFixedSize(QSize(64,64))
self.theProject.countStatus()
self.tabMain = GuiConfigEditGeneral(self.theParent)
@@ -56,7 +56,7 @@ class GuiConfigEditor(QDialog):
self.tabWidget.addTab(self.tabEditor, "Editor")
self.setLayout(self.outerBox)
- self.outerBox.addWidget(self.svgGradient)
+ self.outerBox.addWidget(self.svgGradient, 0, Qt.AlignTop)
self.outerBox.addLayout(self.innerBox)
self.buttonBox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
@@ -129,8 +129,19 @@ class GuiConfigEditGeneral(QWidget):
if themeIdx != -1:
self.guiLookTheme.setCurrentIndex(themeIdx)
- self.guiLookForm.addWidget(QLabel("Theme"), 0, 0)
- self.guiLookForm.addWidget(self.guiLookTheme, 0, 1)
+ self.guiLookSyntax = QComboBox()
+ self.guiLookSyntax.setMinimumWidth(200)
+ self.theSyntaxes = self.theParent.theTheme.listSyntax()
+ for syntaxFile, syntaxName in self.theSyntaxes:
+ self.guiLookSyntax.addItem(syntaxName, syntaxFile)
+ syntaxIdx = self.guiLookSyntax.findData(self.mainConf.guiSyntax)
+ if syntaxIdx != -1:
+ self.guiLookSyntax.setCurrentIndex(syntaxIdx)
+
+ self.guiLookForm.addWidget(QLabel("Theme"), 0, 0)
+ self.guiLookForm.addWidget(self.guiLookTheme, 0, 1)
+ self.guiLookForm.addWidget(QLabel("Syntax"), 1, 0)
+ self.guiLookForm.addWidget(self.guiLookSyntax, 1, 1)
# Spell Checking
self.spellLang = QGroupBox("Spell Checker", self)
@@ -188,6 +199,7 @@ class GuiConfigEditGeneral(QWidget):
needsRestart = False
guiTheme = self.guiLookTheme.currentData()
+ guiSyntax = self.guiLookSyntax.currentData()
spellLanguage = self.spellLangList.currentData()
autoSaveDoc = self.autoSaveDoc.value()
autoSaveProj = self.autoSaveProj.value()
@@ -196,6 +208,7 @@ class GuiConfigEditGeneral(QWidget):
needsRestart |= self.mainConf.guiTheme != guiTheme
self.mainConf.guiTheme = guiTheme
+ self.mainConf.guiSyntax = guiSyntax
self.mainConf.spellLanguage = spellLanguage
self.mainConf.autoSaveDoc = autoSaveDoc
self.mainConf.autoSaveProj = autoSaveProj
diff --git a/nw/gui/doceditor.py b/nw/gui/doceditor.py
index a4b7d04a..af81f802 100644
--- a/nw/gui/doceditor.py
+++ b/nw/gui/doceditor.py
@@ -17,7 +17,7 @@ from time import time
from PyQt5.QtCore import Qt, QTimer, QSizeF
from PyQt5.QtWidgets import QTextEdit, QAction, QMenu, QShortcut
-from PyQt5.QtGui import QTextCursor, QTextOption, QIcon, QKeySequence, QFont
+from PyQt5.QtGui import QTextCursor, QTextOption, QIcon, QKeySequence, QFont, QColor, QPalette
from nw.project.document import NWDoc
from nw.gui.dochighlight import GuiDocHighlighter
@@ -37,8 +37,9 @@ class GuiDocEditor(QTextEdit):
# Class Variables
self.mainConf = nw.CONFIG
- self.theParent = theParent
self.theProject = theProject
+ self.theParent = theParent
+ self.theTheme = theParent.theTheme
self.docChanged = False
self.spellCheck = False
self.nwDocument = NWDoc(self.theProject, self.theParent)
@@ -58,6 +59,7 @@ class GuiDocEditor(QTextEdit):
# Core Elements
self.qDocument = self.document()
+ self.qDocument.setDocumentMargin(self.mainConf.textMargin)
self.qDocument.contentsChange.connect(self._docChange)
if self.mainConf.spellTool == "enchant":
from nw.tools.spellenchant import NWSpellEnchant
@@ -89,7 +91,6 @@ class GuiDocEditor(QTextEdit):
self.wCounter = WordCounter(self)
self.wCounter.finished.connect(self._updateCounts)
- self.clearEditor()
self.initEditor()
logger.debug("DocEditor initialisation complete")
@@ -132,9 +133,13 @@ class GuiDocEditor(QTextEdit):
theFont.setPointSize(self.mainConf.textSize)
self.setFont(theFont)
- # Set text fixed width, or alternatively, just margins
+ docPalette = self.palette()
+ docPalette.setColor(QPalette.Base, QColor(*self.theTheme.colBack))
+ docPalette.setColor(QPalette.Text, QColor(*self.theTheme.colText))
+ self.setPalette(docPalette)
+
+ # Set default text margins
self.qDocument.setDocumentMargin(self.mainConf.textMargin)
- self.changeWidth()
# Also set the document text options for the document text flow
theOpt = QTextOption()
@@ -144,12 +149,14 @@ class GuiDocEditor(QTextEdit):
theOpt.setAlignment(Qt.AlignJustify)
self.qDocument.setDefaultTextOption(theOpt)
+ self.hLight.initHighlighter()
+
# If we have a document open, we should reload it in case the font changed
if self.theHandle is not None:
tHandle = self.theHandle
- self.hLight.initHighlighter()
self.clearEditor()
self.loadText(tHandle)
+ self.changeWidth()
return True
@@ -220,18 +227,14 @@ class GuiDocEditor(QTextEdit):
def setSpellCheck(self, theMode):
self.spellCheck = theMode
self.hLight.setSpellCheck(theMode)
- self.rehighlightDocument()
+ self.hLight.rehighlight()
return True
def updateSpellCheck(self):
if self.spellCheck:
- self.rehighlightDocument()
+ self.hLight.rehighlight()
return True
- def rehighlightDocument(self):
- self.hLight.rehighlight()
- return
-
##
# General Class Methods
##
@@ -251,11 +254,11 @@ class GuiDocEditor(QTextEdit):
tM = int((wW - sW - tW)/2)
if tM < 0:
tM = 0
- # print(wW, tW, dW, sW, tM)
- self.setViewportMargins(tM,0,tM,0)
- self.qDocument.setTextWidth(tW)
- else:
- self.setViewportMargins(0,0,0,0)
+ docFormat = self.qDocument.rootFrame().frameFormat()
+ docFormat.setLeftMargin(tM)
+ docFormat.setRightMargin(tM)
+ self.qDocument.rootFrame().setFrameFormat(docFormat)
+
return
def docAction(self, theAction):
@@ -359,7 +362,8 @@ class GuiDocEditor(QTextEdit):
def _docChange(self, thePos, charsRemoved, charsAdded):
self.lastEdit = time()
- self.setDocumentChanged(True)
+ if not self.docChanged:
+ self.setDocumentChanged(True)
if not self.wcTimer.isActive():
self.wcTimer.start()
if self.mainConf.doReplace and not self.hasSelection:
diff --git a/nw/gui/dochighlight.py b/nw/gui/dochighlight.py
index 97fb1e89..f4c8e1f2 100644
--- a/nw/gui/dochighlight.py
+++ b/nw/gui/dochighlight.py
@@ -36,18 +36,18 @@ class GuiDocHighlighter(QSyntaxHighlighter):
self.hRules = []
self.hStyles = {}
- 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.colTagErr = QColor(*self.theTheme.colTagErr)
- self.colRepTag = QColor(*self.theTheme.colRepTag)
+ self.colHead = QColor(0,0,0)
+ self.colHeadH = QColor(0,0,0)
+ self.colEmph = QColor(0,0,0)
+ self.colDialN = QColor(0,0,0)
+ self.colDialD = QColor(0,0,0)
+ self.colDialS = QColor(0,0,0)
+ self.colComm = QColor(0,0,0)
+ self.colKey = QColor(0,0,0)
+ self.colVal = QColor(0,0,0)
+ self.colSpell = QColor(0,0,0)
+ self.colTagErr = QColor(0,0,0)
+ self.colRepTag = QColor(0,0,0)
self.initHighlighter()
@@ -57,6 +57,21 @@ class GuiDocHighlighter(QSyntaxHighlighter):
def initHighlighter(self):
+ logger.debug("Setting up highlighting rules")
+
+ 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.colTagErr = QColor(*self.theTheme.colTagErr)
+ self.colRepTag = QColor(*self.theTheme.colRepTag)
+
self.hStyles = {
"header1" : self._makeFormat(self.colHead, "bold",1.8),
"header2" : self._makeFormat(self.colHead, "bold",1.6),
@@ -80,6 +95,7 @@ class GuiDocHighlighter(QSyntaxHighlighter):
}
# Headers
+ self.hRules = []
self.hRules.append((
r"^(#{1}) (.*)[^\n]", {
0 : self.hStyles["header1"],
diff --git a/nw/gui/doctree.py b/nw/gui/doctree.py
index 3614306e..07002b2c 100644
--- a/nw/gui/doctree.py
+++ b/nw/gui/doctree.py
@@ -360,7 +360,7 @@ class GuiDocTree(QTreeWidget):
newItem.setText(self.C_FLAGS, "")
newItem.setText(self.C_HANDLE, tHandle)
- newItem.setForeground(self.C_COUNT,QColor(0,105,135))
+ # newItem.setForeground(self.C_COUNT,QColor(*self.theParent.theTheme.treeWCount))
newItem.setTextAlignment(self.C_COUNT,Qt.AlignRight)
newItem.setFont(self.C_FLAGS,self.fontFlags)
diff --git a/nw/gui/docviewer.py b/nw/gui/docviewer.py
index 3ea62455..d2062b87 100644
--- a/nw/gui/docviewer.py
+++ b/nw/gui/docviewer.py
@@ -15,7 +15,7 @@ import nw
from PyQt5.QtCore import Qt, QUrl
from PyQt5.QtWidgets import QTextBrowser
-from PyQt5.QtGui import QTextOption, QFont
+from PyQt5.QtGui import QTextOption, QFont, QPalette, QColor
from nw.convert.tokenizer import Tokenizer
from nw.convert.tohtml import ToHtml
@@ -37,57 +37,14 @@ class GuiDocViewer(QTextBrowser):
self.theTheme = theParent.theTheme
self.theHandle = None
- self.theQDoc = self.document()
- self.theQDoc.setDefaultStyleSheet((
- "body {{"
- " font-size: {textSize}pt;"
- " color: rgb({tColR},{tColG},{tColB});"
- "}}\n"
- "h1, h2, h3, h4 {{"
- " color: rgb({hColR},{hColG},{hColB});"
- "}}\n"
- "a {{"
- " color: rgb({aColR},{aColG},{aColB});"
- "}}\n"
- "pre {{"
- " color: rgb({cColR},{cColG},{cColB});"
- " font-size: {preSize}pt;"
- "}}\n"
- "mark {{"
- " color: rgb({eColR},{eColG},{eColB});"
- "}}\n"
- "table {{"
- " margin: 10px 0px;"
- "}}\n"
- "td {{"
- " padding: 0px 4px;"
- "}}\n"
- ).format(
- textSize = self.mainConf.textSize,
- preSize = self.mainConf.textSize*0.9,
- tColR = self.theTheme.colText[0],
- tColG = self.theTheme.colText[1],
- tColB = self.theTheme.colText[2],
- hColR = self.theTheme.colHead[0],
- hColG = self.theTheme.colHead[1],
- hColB = self.theTheme.colHead[2],
- cColR = self.theTheme.colComm[0],
- cColG = self.theTheme.colComm[1],
- cColB = self.theTheme.colComm[2],
- eColR = self.theTheme.colEmph[0],
- eColG = self.theTheme.colEmph[1],
- eColB = self.theTheme.colEmph[2],
- aColR = self.theTheme.colLink[0],
- aColG = self.theTheme.colLink[1],
- aColB = self.theTheme.colLink[2],
- ))
+ self.qDocument = self.document()
self.setMinimumWidth(300)
self.initViewer()
theOpt = QTextOption()
if self.mainConf.doJustify:
theOpt.setAlignment(Qt.AlignJustify)
- self.theQDoc.setDefaultTextOption(theOpt)
+ self.qDocument.setDefaultTextOption(theOpt)
logger.debug("DocViewer initialisation complete")
@@ -102,20 +59,27 @@ class GuiDocViewer(QTextBrowser):
"""Set editor settings from main config.
"""
+ self._makeStyleSheet()
+
# Set Font
theFont = QFont()
if self.mainConf.textFont is None:
# If none is defined, set the default back to config
- self.mainConf.textFont = self.theQDoc.defaultFont().family()
+ self.mainConf.textFont = self.qDocument.defaultFont().family()
theFont.setFamily(self.mainConf.textFont)
theFont.setPointSize(self.mainConf.textSize)
self.setFont(theFont)
- self.theQDoc.setDocumentMargin(self.mainConf.textMargin)
+ docPalette = self.palette()
+ docPalette.setColor(QPalette.Base, QColor(*self.theTheme.colBack))
+ docPalette.setColor(QPalette.Text, QColor(*self.theTheme.colText))
+ self.setPalette(docPalette)
+
+ self.qDocument.setDocumentMargin(self.mainConf.textMargin)
theOpt = QTextOption()
if self.mainConf.doJustify:
theOpt.setAlignment(Qt.AlignJustify)
- self.theQDoc.setDefaultTextOption(theOpt)
+ self.qDocument.setDefaultTextOption(theOpt)
# If we have a document open, we should reload it in case the font changed
if self.theHandle is not None:
@@ -162,4 +126,56 @@ class GuiDocViewer(QTextBrowser):
return True
+ ##
+ # Internal Functions
+ ##
+
+ def _makeStyleSheet(self):
+
+ self.qDocument.setDefaultStyleSheet((
+ "body {{"
+ " font-size: {textSize}pt;"
+ " color: rgb({tColR},{tColG},{tColB});"
+ "}}\n"
+ "h1, h2, h3, h4 {{"
+ " color: rgb({hColR},{hColG},{hColB});"
+ "}}\n"
+ "a {{"
+ " color: rgb({aColR},{aColG},{aColB});"
+ "}}\n"
+ "pre {{"
+ " color: rgb({cColR},{cColG},{cColB});"
+ " font-size: {preSize}pt;"
+ "}}\n"
+ "mark {{"
+ " color: rgb({eColR},{eColG},{eColB});"
+ "}}\n"
+ "table {{"
+ " margin: 10px 0px;"
+ "}}\n"
+ "td {{"
+ " padding: 0px 4px;"
+ "}}\n"
+ ).format(
+ textSize = self.mainConf.textSize,
+ preSize = self.mainConf.textSize*0.9,
+ tColR = self.theTheme.colText[0],
+ tColG = self.theTheme.colText[1],
+ tColB = self.theTheme.colText[2],
+ hColR = self.theTheme.colHead[0],
+ hColG = self.theTheme.colHead[1],
+ hColB = self.theTheme.colHead[2],
+ cColR = self.theTheme.colComm[0],
+ cColG = self.theTheme.colComm[1],
+ cColB = self.theTheme.colComm[2],
+ eColR = self.theTheme.colEmph[0],
+ eColG = self.theTheme.colEmph[1],
+ eColB = self.theTheme.colEmph[2],
+ aColR = self.theTheme.colLink[0],
+ aColG = self.theTheme.colLink[1],
+ aColB = self.theTheme.colLink[2],
+ ))
+
+ return True
+
# END Class GuiDocViewer
diff --git a/nw/gui/itemeditor.py b/nw/gui/itemeditor.py
index 06edf0fd..a049aaf2 100644
--- a/nw/gui/itemeditor.py
+++ b/nw/gui/itemeditor.py
@@ -15,6 +15,7 @@ import nw
from os import path
+from PyQt5.QtCore import Qt, QSize
from PyQt5.QtWidgets import QDialog, QHBoxLayout, QVBoxLayout, QGroupBox, QFormLayout, QLineEdit, QPushButton, QComboBox
from PyQt5.QtSvg import QSvgWidget
@@ -40,11 +41,12 @@ class GuiItemEditor(QDialog):
self.setWindowTitle("Item Settings")
- self.gradPath = path.abspath(path.join(self.mainConf.appPath,"graphics","block.svg"))
+ self.gradPath = path.abspath(path.join(self.mainConf.appPath,"graphics","gear.svg"))
self.svgGradient = QSvgWidget(self.gradPath)
- self.svgGradient.setFixedWidth(80)
+ self.svgGradient.setFixedSize(QSize(64,64))
+
self.setLayout(self.outerBox)
- self.outerBox.addWidget(self.svgGradient)
+ self.outerBox.addWidget(self.svgGradient, 0, Qt.AlignTop)
self.outerBox.addLayout(self.innerBox)
self.mainGroup = QGroupBox("Item Settings")
diff --git a/nw/gui/mainmenu.py b/nw/gui/mainmenu.py
index 5c91f71c..917af5f8 100644
--- a/nw/gui/mainmenu.py
+++ b/nw/gui/mainmenu.py
@@ -104,8 +104,8 @@ class GuiMainMenu(QMenuBar):
return True
def _showAbout(self):
- msgBox = QMessageBox()
- msgBox.about(self.theParent, "About %s" % nw.__package__, (
+ listPrefix = " • "
+ aboutMsg = (
"
About {name:s} "
"Version: {version:s} Release Date: {date:s}
"
"{name:s} is a markdown-like text editor designed for organising and writing novels. "
@@ -121,8 +121,23 @@ class GuiMainMenu(QMenuBar):
date = nw.__date__,
copyright = nw.__copyright__,
website = nw.__url__,
- credits = "".join([" • %s " % x for x in nw.__credits__]),
- ))
+ credits = " ".join(["%s%s" % (listPrefix, x) for x in nw.__credits__]),
+ )
+ theTheme = self.theParent.theTheme
+ if theTheme.themeCredit != "" or theTheme.syntaxCredit != "":
+ aboutMsg += "
GUI Theme and Syntax Highlighting "
+ aboutMsg += ""
+ if theTheme.themeCredit != "":
+ aboutMsg += "%s%s by %s " % (
+ listPrefix, theTheme.themeName, theTheme.themeCredit
+ )
+ if theTheme.syntaxCredit != "":
+ aboutMsg += "%s%s by %s " % (
+ listPrefix, theTheme.syntaxName, theTheme.syntaxCredit
+ )
+ aboutMsg += "
"
+ msgBox = QMessageBox()
+ msgBox.about(self.theParent, "About %s" % nw.__package__, aboutMsg)
return True
def _showAboutQt(self):
diff --git a/nw/gui/projecteditor.py b/nw/gui/projecteditor.py
index c440dca4..8f5bf681 100644
--- a/nw/gui/projecteditor.py
+++ b/nw/gui/projecteditor.py
@@ -15,7 +15,7 @@ import nw
from os import path
-from PyQt5.QtCore import Qt
+from PyQt5.QtCore import Qt, QSize
from PyQt5.QtGui import QIcon, QPixmap, QColor, QBrush, QStandardItemModel
from PyQt5.QtSvg import QSvgWidget
from PyQt5.QtWidgets import (
@@ -37,14 +37,15 @@ class GuiProjectEditor(QDialog):
self.mainConf = nw.CONFIG
self.theParent = theParent
self.theProject = theProject
+
self.outerBox = QHBoxLayout()
self.innerBox = QVBoxLayout()
-
self.setWindowTitle("Project Settings")
+ self.setLayout(self.outerBox)
- self.gradPath = path.abspath(path.join(self.mainConf.appPath,"graphics","block.svg"))
+ self.gradPath = path.abspath(path.join(self.mainConf.appPath,"graphics","gear.svg"))
self.svgGradient = QSvgWidget(self.gradPath)
- self.svgGradient.setFixedWidth(80)
+ self.svgGradient.setFixedSize(QSize(64,64))
self.theProject.countStatus()
self.tabMain = GuiProjectEditMain(self.theParent, self.theProject)
@@ -58,8 +59,7 @@ class GuiProjectEditor(QDialog):
self.tabWidget.addTab(self.tabImport, "Importance")
self.tabWidget.addTab(self.tabReplace,"Auto-Replace")
- self.setLayout(self.outerBox)
- self.outerBox.addWidget(self.svgGradient)
+ self.outerBox.addWidget(self.svgGradient, 0, Qt.AlignTop)
self.outerBox.addLayout(self.innerBox)
self.buttonBox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
diff --git a/nw/gui/statusbar.py b/nw/gui/statusbar.py
index 79952289..d69f50ee 100644
--- a/nw/gui/statusbar.py
+++ b/nw/gui/statusbar.py
@@ -27,15 +27,17 @@ class GuiMainStatus(QStatusBar):
logger.debug("Initialising GuiMainStatus ...")
- self.mainConf = nw.CONFIG
- self.refTime = None
+ self.mainConf = nw.CONFIG
+ self.theParent = theParent
+ self.refTime = None
self.iconGrey = QPixmap(16,16)
- self.iconGrey.fill(QColor(120,120,120))
self.iconYellow = QPixmap(16,16)
- self.iconYellow.fill(QColor(120,120, 40))
self.iconGreen = QPixmap(16,16)
- self.iconGreen.fill(QColor( 40,120, 0))
+
+ self.iconGrey.fill(QColor(*self.theParent.theTheme.statNone))
+ self.iconYellow.fill(QColor(*self.theParent.theTheme.statUnsaved))
+ self.iconGreen.fill(QColor(*self.theParent.theTheme.statSaved))
self.boxStats = QLabel()
self.boxStats.setToolTip("Project Word Count | Session Word Count")
diff --git a/nw/gui/winmain.py b/nw/gui/winmain.py
index da2ed168..374668a6 100644
--- a/nw/gui/winmain.py
+++ b/nw/gui/winmain.py
@@ -48,6 +48,7 @@ class GuiMain(QMainWindow):
def __init__(self):
QWidget.__init__(self)
+ logger.info("Starting %s" % nw.__package__)
logger.debug("Initialising GUI ...")
self.mainConf = nw.CONFIG
self.theTheme = Theme(self)
@@ -57,8 +58,7 @@ class GuiMain(QMainWindow):
self.resize(*self.mainConf.winGeometry)
self._setWindowTitle()
- self.setWindowIcon(QIcon(path.join(self.mainConf.appRoot, nwFiles.APP_ICON)))
- self.theTheme.loadTheme()
+ self.setWindowIcon(QIcon(path.join(self.mainConf.appIcon)))
# Main GUI Elements
self.statusBar = GuiMainStatus(self)
@@ -114,9 +114,6 @@ class GuiMain(QMainWindow):
self.setStatusBar(self.statusBar)
self.statusBar.showMessage("Ready")
- # Load Theme StyleSheet
- self.setStyleSheet(self.theTheme.cssData)
-
# Set Up Autosaving Project Timer
self.asProjTimer = QTimer()
self.asProjTimer.timeout.connect(self._autoSaveProject)
@@ -138,6 +135,7 @@ class GuiMain(QMainWindow):
self.initMain()
self.asProjTimer.start()
self.asDocTimer.start()
+ self.statusBar.clearStatus()
logger.debug("GUI initialisation complete")
@@ -467,6 +465,7 @@ class GuiMain(QMainWindow):
if dlgConf.exec_() == QDialog.Accepted:
logger.debug("Applying new preferences")
self.initMain()
+ self.theTheme.updateTheme()
self.docEditor.initEditor()
self.docViewer.initViewer()
return True
diff --git a/nw/theme.py b/nw/theme.py
index f0a8db3c..5b96c59b 100644
--- a/nw/theme.py
+++ b/nw/theme.py
@@ -16,6 +16,9 @@ import nw
from os import path, listdir
+from PyQt5.QtWidgets import qApp
+from PyQt5.QtGui import QPalette, QColor
+
from nw.enum import nwAlert
logger = logging.getLogger(__name__)
@@ -24,39 +27,60 @@ class Theme:
def __init__(self, theParent):
- self.mainConf = nw.CONFIG
- self.theParent = theParent
- self.cssName = "styles.css"
- self.confName = "theme.conf"
- self.themeList = []
+ self.mainConf = nw.CONFIG
+ self.theParent = theParent
+ self.guiPalette = QPalette()
+ self.guiPath = "gui"
+ self.syntaxPath = "syntax"
+ self.cssName = "style.qss"
+ self.confName = "theme.conf"
+ self.themeList = []
+ self.syntaxList = []
# Loaded Theme Settings
- ## Main
- self.themeName = "No Name"
+ ## Theme
+ self.themeName = ""
+ self.themeAuthor = ""
+ self.themeCredit = ""
+ self.themeUrl = ""
- ## Syntax
- self.colText = [0,0,0]
- self.colLink = [0,0,0]
- 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]
- self.colTagErr = [0,0,0]
- self.colRepTag = [0,0,0]
+ ## GUI
+ self.treeWCount = [ 0, 0, 0]
+ self.statNone = [120,120,120]
+ self.statUnsaved = [120,120, 40]
+ self.statSaved = [ 40,120, 0]
+
+ # Loaded Syntax Settings
+
+ ## Main
+ self.syntaxName = ""
+ self.syntaxAuthor = ""
+ self.syntaxCredit = ""
+ self.syntaxUrl = ""
+
+ ## Colours
+ self.colBack = [255,255,255]
+ self.colText = [ 0, 0, 0]
+ self.colLink = [ 0, 0, 0]
+ 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]
+ self.colTagErr = [ 0, 0, 0]
+ self.colRepTag = [ 0, 0, 0]
# Changeable Settings
- self.guiTheme = None
- self.themePath = None
- self.confFile = None
- self.cssFile = None
- self.cssData = ""
+ self.guiTheme = None
+ self.guiSyntax = None
+ self.themeRoot = None
+ self.cssFile = None
self.updateTheme()
@@ -67,10 +91,18 @@ class Theme:
##
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)
+
+ self.guiTheme = self.mainConf.guiTheme
+ self.guiSyntax = self.mainConf.guiSyntax
+ self.themeRoot = self.mainConf.themeRoot
+ self.themePath = path.join(self.mainConf.themeRoot, self.guiPath, self.guiTheme)
+ self.syntaxFile = path.join(self.themeRoot,self.syntaxPath,self.guiSyntax+".conf")
+ self.confFile = path.join(self.themePath,self.confName)
+ self.cssFile = path.join(self.themePath,self.cssName)
+
+ self.loadTheme()
+ self.loadSyntax()
+
return True
def loadTheme(self):
@@ -78,30 +110,82 @@ class Theme:
logger.debug("Loading theme files")
# CSS File
+ cssData = ""
try:
if path.isfile(self.cssFile):
with open(self.cssFile,mode="r") as inFile:
- self.cssData = inFile.read()
+ cssData = inFile.read()
except Exception as e:
logger.error("Could not load theme css file")
return False
- # Color Config
+ # Config File
confParser = configparser.ConfigParser()
try:
confParser.read_file(open(self.confFile))
except Exception as e:
- logger.error("Could not load theme config file")
+ logger.error("Could not load theme settings from: %s" % self.confFile)
return False
## Main
cnfSec = "Main"
if confParser.has_section(cnfSec):
- self.themeName = confParser.get(cnfSec,"name")
+ self.themeName = self._parseLine(confParser,cnfSec,"name", "")
+ self.themeAuthor = self._parseLine(confParser,cnfSec,"author","")
+ self.themeCredit = self._parseLine(confParser,cnfSec,"credit","")
+ self.themeUrl = self._parseLine(confParser,cnfSec,"url", "")
+
+ ## Palette
+ cnfSec = "Palette"
+ if confParser.has_section(cnfSec):
+ self._setPalette(confParser,cnfSec,"window", QPalette.Window)
+ self._setPalette(confParser,cnfSec,"windowtext", QPalette.WindowText)
+ self._setPalette(confParser,cnfSec,"base", QPalette.Base)
+ self._setPalette(confParser,cnfSec,"alternatebase",QPalette.AlternateBase)
+ self._setPalette(confParser,cnfSec,"text", QPalette.Text)
+ self._setPalette(confParser,cnfSec,"tooltipbase", QPalette.ToolTipBase)
+ self._setPalette(confParser,cnfSec,"tooltiptext", QPalette.ToolTipText)
+ self._setPalette(confParser,cnfSec,"button", QPalette.Button)
+ self._setPalette(confParser,cnfSec,"buttontext", QPalette.ButtonText)
+ self._setPalette(confParser,cnfSec,"brighttext", QPalette.BrightText)
+
+ ## GUI
+ cnfSec = "GUI"
+ if confParser.has_section(cnfSec):
+ self.treeWCount = self._loadColour(confParser,cnfSec,"treewordcount")
+ self.statNone = self._loadColour(confParser,cnfSec,"statusnone")
+ self.statUnsaved = self._loadColour(confParser,cnfSec,"statusunsaved")
+ self.statSaved = self._loadColour(confParser,cnfSec,"statussaved")
+
+ # Apply Styles
+ qApp.setStyleSheet(cssData)
+ qApp.setPalette(self.guiPalette)
+
+ logger.info("Loaded theme '%s'" % self.guiTheme)
+
+ return True
+
+ def loadSyntax(self):
+
+ confParser = configparser.ConfigParser()
+ try:
+ confParser.read_file(open(self.syntaxFile))
+ except Exception as e:
+ logger.error("Could not load syntax colours from: %s" % self.syntaxFile)
+ return False
+
+ ## Main
+ cnfSec = "Main"
+ if confParser.has_section(cnfSec):
+ self.syntaxName = self._parseLine(confParser,cnfSec,"name","")
+ self.syntaxAuthor = self._parseLine(confParser,cnfSec,"author","")
+ self.syntaxCredit = self._parseLine(confParser,cnfSec,"credit","")
+ self.syntaxUrl = self._parseLine(confParser,cnfSec,"url", "")
## Syntax
cnfSec = "Syntax"
if confParser.has_section(cnfSec):
+ self.colBack = self._loadColour(confParser,cnfSec,"background")
self.colText = self._loadColour(confParser,cnfSec,"text")
self.colLink = self._loadColour(confParser,cnfSec,"link")
self.colHead = self._loadColour(confParser,cnfSec,"headertext")
@@ -117,6 +201,8 @@ class Theme:
self.colTagErr = self._loadColour(confParser,cnfSec,"tagerror")
self.colRepTag = self._loadColour(confParser,cnfSec,"replacetag")
+ logger.info("Loaded syntax theme '%s'" % self.guiSyntax)
+
return True
def listThemes(self):
@@ -125,14 +211,14 @@ class Theme:
return self.themeList
confParser = configparser.ConfigParser()
- for themeDir in listdir(self.mainConf.themeRoot):
- themeConf = path.join(self.mainConf.themeRoot, themeDir, self.confName)
+ for themeDir in listdir(path.join(self.mainConf.themeRoot, self.guiPath)):
+ themeConf = path.join(self.mainConf.themeRoot, self.guiPath, themeDir, self.confName)
logger.verbose("Checking theme config for '%s'" % themeDir)
try:
confParser.read_file(open(themeConf))
except Exception as e:
self.theParent.makeAlert(["Could not load theme config file",str(e)],nwAlert.ERROR)
- return []
+ continue
themeName = ""
if confParser.has_section("Main"):
themeName = confParser.get("Main","name")
@@ -140,8 +226,38 @@ class Theme:
if themeName != "":
self.themeList.append((themeDir, themeName))
+ self.themeList = sorted(self.themeList, key=lambda x: x[1])
+
return self.themeList
+ def listSyntax(self):
+
+ if len(self.syntaxList) > 0:
+ return self.syntaxList
+
+ confParser = configparser.ConfigParser()
+ syntaxDir = path.join(self.mainConf.themeRoot, self.syntaxPath)
+ for syntaxFile in listdir(syntaxDir):
+ syntaxPath = path.join(syntaxDir, syntaxFile)
+ if not path.isfile(syntaxPath):
+ continue
+ logger.verbose("Checking theme syntax for '%s'" % syntaxFile)
+ try:
+ confParser.read_file(open(syntaxPath))
+ except Exception as e:
+ self.theParent.makeAlert(["Could not load syntax file",str(e)],nwAlert.ERROR)
+ return []
+ syntaxName = ""
+ if confParser.has_section("Main"):
+ syntaxName = confParser.get("Main","name")
+ if len(syntaxFile) > 5 and syntaxName != "":
+ self.syntaxList.append((syntaxFile[:-5], syntaxName))
+ logger.verbose("Syntax name is '%s'" % syntaxName)
+
+ self.syntaxList = sorted(self.syntaxList, key=lambda x: x[1])
+
+ return self.syntaxList
+
##
# Internal Functions
##
@@ -162,4 +278,25 @@ class Theme:
outData = [0,0,0]
return outData
+ def _setPalette(self, confParser, cnfSec, cnfName, paletteVal):
+ if confParser.has_option(cnfSec,cnfName):
+ inData = confParser.get(cnfSec,cnfName).split(",")
+ readCol = []
+ try:
+ readCol.append(int(inData[0]))
+ readCol.append(int(inData[1]))
+ readCol.append(int(inData[2]))
+ except:
+ logger.error("Could not load theme colours for '%s' from config file" % cnfName)
+ return
+ if len(readCol) == 3:
+ self.guiPalette.setColor(paletteVal, QColor(*readCol))
+ return
+
+ def _parseLine(self, confParser, cnfSec, cnfName, cnfDefault):
+ if confParser.has_section(cnfSec):
+ if confParser.has_option(cnfSec, cnfName):
+ return confParser.get(cnfSec, cnfName)
+ return cnfDefault
+
# End Class Theme
diff --git a/nw/themes/default_dark/styles.css b/nw/themes/default_dark/styles.css
deleted file mode 100644
index c81aecf3..00000000
--- a/nw/themes/default_dark/styles.css
+++ /dev/null
@@ -1,21 +0,0 @@
-/**
- * Default Theme: Dark
- */
-
-* {
- background-color: #999999;
-}
-
-QTextEdit {
- background-color: #141414;
- color: #c7cfd0;
-}
-
-QTextBrowser {
- background-color: #141414;
- color: #c7cfd0;
-}
-
-QTreeView, QHeaderView {
- font-size: 13px;
-}
diff --git a/nw/themes/default_light/theme.conf b/nw/themes/default_light/theme.conf
deleted file mode 100644
index b3d0d5be..00000000
--- a/nw/themes/default_light/theme.conf
+++ /dev/null
@@ -1,18 +0,0 @@
-[Main]
-name = Default Light
-
-[Syntax]
-text = 0, 0, 0
-link = 0, 0, 0
-headertext = 0, 0, 0
-headertag = 0, 0, 0
-emphasis = 0, 0, 0
-straightquotes = 0, 0, 0
-doublequotes = 0, 0, 0
-singlequotes = 0, 0, 0
-hidden = 50, 50, 50
-keyword = 0, 0, 0
-value = 0, 0, 0
-spellcheckline = 0, 0, 0
-tagerror = 0, 0, 0
-replacetag = 0, 0, 0
diff --git a/nw/themes/default_light/styles.css b/nw/themes/gui/default/style.qss
similarity index 100%
rename from nw/themes/default_light/styles.css
rename to nw/themes/gui/default/style.qss
diff --git a/nw/themes/gui/default/theme.conf b/nw/themes/gui/default/theme.conf
new file mode 100644
index 00000000..004b811d
--- /dev/null
+++ b/nw/themes/gui/default/theme.conf
@@ -0,0 +1,2 @@
+[Main]
+name = Default System Theme
diff --git a/nw/themes/gui/default_dark/styles.qss b/nw/themes/gui/default_dark/styles.qss
new file mode 100644
index 00000000..6c847eb6
--- /dev/null
+++ b/nw/themes/gui/default_dark/styles.qss
@@ -0,0 +1,7 @@
+/**
+ * Default Theme: Dark
+ */
+
+QTreeView, QHeaderView {
+ font-size: 13px;
+}
diff --git a/nw/themes/gui/default_dark/theme.conf b/nw/themes/gui/default_dark/theme.conf
new file mode 100644
index 00000000..65bf5f1e
--- /dev/null
+++ b/nw/themes/gui/default_dark/theme.conf
@@ -0,0 +1,23 @@
+[Main]
+name = Default Dark Theme
+author = Veronica Berglyd Olsen
+credit = Veronica Berglyd Olsen
+url = https://github.com/vkbo/novelWriter
+
+[Palette]
+window = 54, 54, 54
+windowtext = 174, 174, 174
+base = 62, 62, 62
+alternatebase = 67, 67, 67
+text = 174, 174, 174
+tooltipbase = 255, 255, 192
+tooltiptext = 21, 21, 13
+button = 62, 62, 62
+buttontext = 174, 174, 174
+brighttext = 174, 174, 174
+
+[GUI]
+treewordcount = 197, 200, 198
+statusnone = 150, 152, 150
+statussaved = 39, 135, 78
+statusunsaved = 138, 32, 32
diff --git a/nw/themes/default_dark/theme.conf b/nw/themes/syntax/default_dark.conf
similarity index 93%
rename from nw/themes/default_dark/theme.conf
rename to nw/themes/syntax/default_dark.conf
index 86b04b45..8d1cd6b4 100644
--- a/nw/themes/default_dark/theme.conf
+++ b/nw/themes/syntax/default_dark.conf
@@ -2,6 +2,7 @@
name = Default Dark
[Syntax]
+background = 54, 54, 54
text = 199, 207, 208
link = 184, 200, 0
headertext = 0, 155, 200
diff --git a/nw/themes/syntax/default_light.conf b/nw/themes/syntax/default_light.conf
new file mode 100644
index 00000000..709a1ab2
--- /dev/null
+++ b/nw/themes/syntax/default_light.conf
@@ -0,0 +1,19 @@
+[Main]
+name = Default Light
+
+[Syntax]
+background = 255, 255, 255
+text = 0, 0, 0
+link = 0, 0, 200
+headertext = 0, 100, 00
+headertag = 50, 100, 50
+emphasis = 150, 110, 30
+straightquotes = 200, 0, 0
+doublequotes = 0, 0, 200
+singlequotes = 0, 0, 200
+hidden = 100, 100, 100
+keyword = 200, 50, 50
+value = 50, 150, 50
+spellcheckline = 200, 0, 0
+tagerror = 0, 150, 0
+replacetag = 0, 150, 0
diff --git a/nw/themes/syntax/tomorrow.conf b/nw/themes/syntax/tomorrow.conf
new file mode 100644
index 00000000..93f16598
--- /dev/null
+++ b/nw/themes/syntax/tomorrow.conf
@@ -0,0 +1,42 @@
+##
+# Theme: Tomorrow
+# Source: https://github.com/chriskempson/tomorrow-theme
+# Credit: Chris Kempson
+##
+# Colours:
+# Background = 2d2d2d : 45, 45, 45
+# Current Line = 393939 : 57, 57, 57
+# Selection = 515151 : 81, 81, 81
+# Foreground = cccccc : 204, 204, 204
+# Comment = 999999 : 153, 153, 153
+# Red = f2777a : 242, 119, 122
+# Orange = f99157 : 249, 145, 57
+# Yellow = ffcc66 : 255, 204, 102
+# Green = 99cc99 : 153, 204, 153
+# Aqua = 66cccc : 102, 204, 204
+# Blue = 6699cc : 102, 153, 204
+# Purple = cc99cc : 204, 153, 204
+##
+
+[Main]
+name = Tomorrow
+author = Veronica Berglyd Olsen
+credit = Chris Kempson
+url = https://github.com/chriskempson/tomorrow-theme
+
+[Syntax]
+background = 45, 45, 45
+text = 204, 204, 204
+link = 102, 153, 204
+headertext = 102, 153, 204
+headertag = 102, 153, 204
+emphasis = 249, 145, 57
+straightquotes = 242, 119, 122
+doublequotes = 153, 204, 153
+singlequotes = 255, 204, 102
+hidden = 153, 153, 153
+keyword = 242, 119, 122
+value = 204, 153, 204
+spellcheckline = 242, 119, 122
+tagerror = 153, 204, 153
+replacetag = 102, 204, 204
diff --git a/nw/themes/syntax/tomorrow_night.conf b/nw/themes/syntax/tomorrow_night.conf
new file mode 100644
index 00000000..09966ff0
--- /dev/null
+++ b/nw/themes/syntax/tomorrow_night.conf
@@ -0,0 +1,42 @@
+##
+# Theme: Tomorrow Night
+# Source: https://github.com/chriskempson/tomorrow-theme
+# Credit: Chris Kempson
+##
+# Colours:
+# Background = 1d1f21 : 29, 31, 33
+# Current Line = 282a2e : 40, 42, 46
+# Selection = 373b41 : 55, 59. 65
+# Foreground = c5c8c6 : 197, 200, 198
+# Comment = 969896 : 150, 152, 150
+# Red = cc6666 : 204, 102, 102
+# Orange = de935f : 222, 147, 95
+# Yellow = f0c674 : 240, 198, 116
+# Green = b5bd68 : 181, 189, 104
+# Aqua = 8abeb7 : 138, 190, 183
+# Blue = 81a2be : 129, 162, 190
+# Purple = b294bb : 178, 148, 187
+##
+
+[Main]
+name = Tomorrow Night
+author = Veronica Berglyd Olsen
+credit = Chris Kempson
+url = https://github.com/chriskempson/tomorrow-theme
+
+[Syntax]
+background = 29, 31, 33
+text = 197, 200, 198
+link = 129, 162, 190
+headertext = 129, 162, 190
+headertag = 129, 162, 190
+emphasis = 222, 147, 95
+straightquotes = 204, 102, 102
+doublequotes = 181, 189, 104
+singlequotes = 240, 198, 116
+hidden = 150, 152, 150
+keyword = 204, 102, 102
+value = 178, 148, 187
+spellcheckline = 204, 102, 102
+tagerror = 181, 189, 104
+replacetag = 138, 190, 183
diff --git a/nw/themes/syntax/tomorrow_night_blue.conf b/nw/themes/syntax/tomorrow_night_blue.conf
new file mode 100644
index 00000000..d05a757b
--- /dev/null
+++ b/nw/themes/syntax/tomorrow_night_blue.conf
@@ -0,0 +1,42 @@
+##
+# Theme: Tomorrow Night Blue
+# Source: https://github.com/chriskempson/tomorrow-theme
+# Credit: Chris Kempson
+##
+# Colours:
+# Background = 002451 : 0, 36, 81
+# Current Line = 00346e : 0, 52, 110
+# Selection = 003f8e : 0, 63, 142
+# Foreground = ffffff : 255, 255, 255
+# Comment = 7285b7 : 114, 133, 183
+# Red = ff9da4 : 255, 157, 164
+# Orange = ffc58f : 255, 197, 143
+# Yellow = ffeead : 255, 238, 173
+# Green = d1f1a9 : 209, 241, 169
+# Aqua = 99ffff : 153, 255, 255
+# Blue = bbdaff : 187, 218, 255
+# Purple = ebbbff : 235, 187, 255
+##
+
+[Main]
+name = Tomorrow Night Blue
+author = Veronica Berglyd Olsen
+credit = Chris Kempson
+url = https://github.com/chriskempson/tomorrow-theme
+
+[Syntax]
+background = 0, 36, 81
+text = 255, 255, 255
+link = 187, 218, 255
+headertext = 187, 218, 255
+headertag = 187, 218, 255
+emphasis = 255, 197, 143
+straightquotes = 255, 157, 164
+doublequotes = 209, 241, 169
+singlequotes = 255, 238, 173
+hidden = 114, 133, 183
+keyword = 255, 157, 164
+value = 235, 187, 255
+spellcheckline = 255, 157, 164
+tagerror = 209, 241, 169
+replacetag = 153, 255, 255
diff --git a/nw/themes/syntax/tomorrow_night_bright.conf b/nw/themes/syntax/tomorrow_night_bright.conf
new file mode 100644
index 00000000..0d9c6c3a
--- /dev/null
+++ b/nw/themes/syntax/tomorrow_night_bright.conf
@@ -0,0 +1,42 @@
+##
+# Theme: Tomorrow Night Bright
+# Source: https://github.com/chriskempson/tomorrow-theme
+# Credit: Chris Kempson
+##
+# Colours:
+# Background = 000000 : 0, 0, 0
+# Current Line = 2a2a2a : 42, 42, 42
+# Selection = 424242 : 66, 66, 66
+# Foreground = eaeaea : 234, 234, 234
+# Comment = 969896 : 150, 152, 150
+# Red = d54e53 : 213, 78, 83
+# Orange = e78c45 : 231, 140, 69
+# Yellow = e7c547 : 231, 197, 71
+# Green = b9ca4a : 185, 202, 74
+# Aqua = 70c0b1 : 112, 192, 177
+# Blue = 7aa6da : 122, 166, 218
+# Purple = c397d8 : 195, 151, 216
+##
+
+[Main]
+name = Tomorrow Night Bright
+author = Veronica Berglyd Olsen
+credit = Chris Kempson
+url = https://github.com/chriskempson/tomorrow-theme
+
+[Syntax]
+background = 0, 0, 0
+text = 234, 234, 234
+link = 122, 166, 218
+headertext = 122, 166, 218
+headertag = 122, 166, 218
+emphasis = 231, 140, 69
+straightquotes = 213, 78, 83
+doublequotes = 185, 202, 74
+singlequotes = 231, 197, 71
+hidden = 150, 152, 150
+keyword = 213, 78, 83
+value = 195, 151, 216
+spellcheckline = 213, 78, 83
+tagerror = 185, 202, 74
+replacetag = 112, 192, 177
diff --git a/nw/themes/syntax/tomorrow_night_eighties.conf b/nw/themes/syntax/tomorrow_night_eighties.conf
new file mode 100644
index 00000000..5bd0c222
--- /dev/null
+++ b/nw/themes/syntax/tomorrow_night_eighties.conf
@@ -0,0 +1,42 @@
+##
+# Theme: Tomorrow Night Eighties
+# Source: https://github.com/chriskempson/tomorrow-theme
+# Credit: Chris Kempson
+##
+# Colours:
+# Background = 2d2d2d : 45, 45, 45
+# Current Line = 393939 : 57, 57, 57
+# Selection = 515151 : 81, 81, 81
+# Foreground = cccccc : 204, 204, 204
+# Comment = 999999 : 153, 153, 153
+# Red = f2777a : 242, 119, 122
+# Orange = f99157 : 249, 145, 57
+# Yellow = ffcc66 : 255, 204, 102
+# Green = 99cc99 : 153, 204, 153
+# Aqua = 66cccc : 102, 204, 204
+# Blue = 6699cc : 102, 153, 204
+# Purple = cc99cc : 204, 153, 204
+##
+
+[Main]
+name = Tomorrow Night Eighties
+author = Veronica Berglyd Olsen
+credit = Chris Kempson
+url = https://github.com/chriskempson/tomorrow-theme
+
+[Syntax]
+background = 45, 45, 45
+text = 204, 204, 204
+link = 102, 153, 204
+headertext = 102, 153, 204
+headertag = 102, 153, 204
+emphasis = 249, 145, 57
+straightquotes = 242, 119, 122
+doublequotes = 153, 204, 153
+singlequotes = 255, 204, 102
+hidden = 153, 153, 153
+keyword = 242, 119, 122
+value = 204, 153, 204
+spellcheckline = 242, 119, 122
+tagerror = 153, 204, 153
+replacetag = 102, 204, 204
diff --git a/sample/sampleNovel/nwProject.nwx b/sample/sampleNovel/nwProject.nwx
index 6b667a58..0081d96a 100644
--- a/sample/sampleNovel/nwProject.nwx
+++ b/sample/sampleNovel/nwProject.nwx
@@ -1,5 +1,5 @@
-
+
Sample Project
Sample Project
@@ -9,7 +9,7 @@
True
636b6aa9b697b
- bc0cbd2a407f3
+ 636b6aa9b697b
581
B
@@ -80,7 +80,7 @@
736
137
6
- 424
+ 69
-
New File
diff --git a/tests/reference/novelwriter.conf b/tests/reference/novelwriter.conf
index 0f0562f9..c0eb784e 100644
--- a/tests/reference/novelwriter.conf
+++ b/tests/reference/novelwriter.conf
@@ -1,6 +1,7 @@
[Main]
-timestamp = 2019-06-15 12:26:17
-theme = default_dark
+timestamp = 2019-06-15 23:10:43
+theme = default
+syntax = default_light
[Sizes]
geometry = 1100, 650