+20
-2
@@ -48,7 +48,8 @@ class Config:
|
||||
self.guiTheme = "default"
|
||||
self.winGeometry = [1100, 650]
|
||||
self.treeColWidth = [120, 30, 50]
|
||||
self.mainPanePos = [300, 400, 400]
|
||||
self.mainPanePos = [300, 800]
|
||||
self.docPanePos = [400, 400]
|
||||
|
||||
## Project
|
||||
self.autoSaveProj = 60
|
||||
@@ -125,6 +126,12 @@ class Config:
|
||||
|
||||
# Get options
|
||||
|
||||
## Main
|
||||
cnfSec = "Main"
|
||||
if confParser.has_section(cnfSec):
|
||||
if confParser.has_option(cnfSec,"theme"):
|
||||
self.guiTheme = confParser.get(cnfSec,"theme")
|
||||
|
||||
## Sizes
|
||||
cnfSec = "Sizes"
|
||||
if confParser.has_section(cnfSec):
|
||||
@@ -138,7 +145,11 @@ class Config:
|
||||
)
|
||||
if confParser.has_option(cnfSec,"mainpane"):
|
||||
self.mainPanePos = self.unpackList(
|
||||
confParser.get(cnfSec,"mainpane"), 3, self.mainPanePos
|
||||
confParser.get(cnfSec,"mainpane"), 2, self.mainPanePos
|
||||
)
|
||||
if confParser.has_option(cnfSec,"docpane"):
|
||||
self.docPanePos = self.unpackList(
|
||||
confParser.get(cnfSec,"docpane"), 2, self.docPanePos
|
||||
)
|
||||
|
||||
## Project
|
||||
@@ -199,6 +210,7 @@ class Config:
|
||||
cnfSec = "Main"
|
||||
confParser.add_section(cnfSec)
|
||||
confParser.set(cnfSec,"timestamp", datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
|
||||
confParser.set(cnfSec,"theme", str(self.guiTheme))
|
||||
|
||||
## Sizes
|
||||
cnfSec = "Sizes"
|
||||
@@ -206,6 +218,7 @@ class Config:
|
||||
confParser.set(cnfSec,"geometry", self.packList(self.winGeometry))
|
||||
confParser.set(cnfSec,"treecols", self.packList(self.treeColWidth))
|
||||
confParser.set(cnfSec,"mainpane", self.packList(self.mainPanePos))
|
||||
confParser.set(cnfSec,"docpane", self.packList(self.docPanePos))
|
||||
|
||||
## Project
|
||||
cnfSec = "Project"
|
||||
@@ -298,4 +311,9 @@ class Config:
|
||||
self.confChanged = True
|
||||
return True
|
||||
|
||||
def setDocPanePos(self, panePos):
|
||||
self.docPanePos = panePos
|
||||
self.confChanged = True
|
||||
return True
|
||||
|
||||
# End Class Config
|
||||
|
||||
+1
-1
@@ -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
|
||||
|
||||
+12
-12
@@ -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),
|
||||
|
||||
+8
-1
@@ -27,9 +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},{1},{2});"
|
||||
"}}"
|
||||
).format(
|
||||
*self.theTheme.colHead
|
||||
))
|
||||
self.theDoc.setDocumentMargin(self.mainConf.textMargin[0])
|
||||
self.setMinimumWidth(300)
|
||||
|
||||
|
||||
+20
-19
@@ -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)
|
||||
@@ -70,27 +73,29 @@ class GuiMain(QMainWindow):
|
||||
self.treeBox.addWidget(self.docDetails)
|
||||
self.treePane.setLayout(self.treeBox)
|
||||
|
||||
self.splitView = QSplitter(Qt.Horizontal)
|
||||
self.splitView.addWidget(self.docEditor)
|
||||
self.splitView.addWidget(self.docViewer)
|
||||
|
||||
self.splitMain = QSplitter(Qt.Horizontal)
|
||||
self.splitMain.addWidget(self.treePane)
|
||||
self.splitMain.addWidget(self.docEditor)
|
||||
self.splitMain.addWidget(self.docViewer)
|
||||
self.splitMain.addWidget(self.splitView)
|
||||
self.splitMain.setSizes(self.mainConf.mainPanePos)
|
||||
self.splitMain.splitterMoved.connect(self._splitMainMove)
|
||||
|
||||
self.setCentralWidget(self.splitMain)
|
||||
|
||||
self.idxTree = self.splitMain.indexOf(self.treePane)
|
||||
self.idxEditor = self.splitMain.indexOf(self.docEditor)
|
||||
self.idxViewer = self.splitMain.indexOf(self.docViewer)
|
||||
self.idxMain = self.splitMain.indexOf(self.splitView)
|
||||
self.idxEditor = self.splitView.indexOf(self.docEditor)
|
||||
self.idxViewer = self.splitView.indexOf(self.docViewer)
|
||||
|
||||
self.splitMain.setCollapsible(self.idxTree, False)
|
||||
self.splitMain.setCollapsible(self.idxEditor, False)
|
||||
self.splitMain.setCollapsible(self.idxViewer, True)
|
||||
self.splitMain.setCollapsible(self.idxMain, False)
|
||||
self.splitView.setCollapsible(self.idxEditor, False)
|
||||
self.splitView.setCollapsible(self.idxViewer, True)
|
||||
|
||||
self.docViewer.setVisible(False)
|
||||
pPos = self.mainConf.mainPanePos
|
||||
tPos = [pPos[0], pPos[1]+pPos[2]]
|
||||
self.splitMain.setSizes(tPos)
|
||||
|
||||
# Build GUI Elements
|
||||
self.treeView.itemSelectionChanged.connect(self._treeSingleClick)
|
||||
@@ -105,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))
|
||||
@@ -260,11 +261,10 @@ class GuiMain(QMainWindow):
|
||||
|
||||
bPos = self.splitMain.sizes()
|
||||
self.docViewer.setVisible(True)
|
||||
if bPos[2] == 0:
|
||||
bWidth = bPos[1]+bPos[2]
|
||||
bPos[1] = int(bWidth/2)
|
||||
bPos[2] = bWidth-bPos[1]
|
||||
self.splitMain.setSizes(bPos)
|
||||
vPos = [0,0]
|
||||
vPos[0] = int(bPos[1]/2)
|
||||
vPos[1] = bPos[1]-vPos[0]
|
||||
self.splitView.setSizes(vPos)
|
||||
self.docEditor.changeWidth()
|
||||
|
||||
return True
|
||||
@@ -346,6 +346,7 @@ class GuiMain(QMainWindow):
|
||||
self.mainConf.setWinSize(self.width(), self.height())
|
||||
self.mainConf.setTreeColWidths(self.treeView.getColumnSizes())
|
||||
self.mainConf.setMainPanePos(self.splitMain.sizes())
|
||||
self.mainConf.setDocPanePos(self.splitView.sizes())
|
||||
self.mainConf.saveConfig()
|
||||
return
|
||||
|
||||
|
||||
+120
@@ -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
|
||||
@@ -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
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<novelWriterXML appVersion="0.1.3" fileVersion="1.0" timeStamp="2019-05-18 18:12:49">
|
||||
<novelWriterXML appVersion="0.1.3" fileVersion="1.0" timeStamp="2019-05-18 20:51:40">
|
||||
<project>
|
||||
<name>Sample Project</name>
|
||||
<title>Sample Project</title>
|
||||
@@ -8,8 +8,8 @@
|
||||
</project>
|
||||
<settings>
|
||||
<spellCheck>False</spellCheck>
|
||||
<lastEdited>96b68994dfa3d</lastEdited>
|
||||
<lastViewed>96b68994dfa3d</lastViewed>
|
||||
<lastEdited>636b6aa9b697b</lastEdited>
|
||||
<lastViewed>636b6aa9b697b</lastViewed>
|
||||
</settings>
|
||||
<content count="15">
|
||||
<item handle="7031beac91f75" order="0" parent="None">
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
[Main]
|
||||
timestamp = 2019-05-18 15:06:44
|
||||
theme = default
|
||||
|
||||
[Sizes]
|
||||
geometry = 1100, 650
|
||||
treecols = 120, 30, 50
|
||||
mainpane = 300, 400, 400
|
||||
mainpane = 300, 800
|
||||
docpane = 400, 400
|
||||
|
||||
[Project]
|
||||
autosaveproject = 60
|
||||
|
||||
@@ -70,7 +70,8 @@ def testConfigSetMainPanePos(nwTemp,nwRef):
|
||||
refConf = path.join(nwRef, "novelwriter.conf")
|
||||
assert theConf.setMainPanePos([0, 0])
|
||||
assert theConf.confChanged
|
||||
assert theConf.setMainPanePos([300, 400, 400])
|
||||
assert theConf.setMainPanePos([300, 800])
|
||||
assert theConf.setDocPanePos([400, 400])
|
||||
assert theConf.saveConfig()
|
||||
assert cmpFiles(tmpConf, refConf, [2])
|
||||
assert not theConf.confChanged
|
||||
|
||||
Reference in New Issue
Block a user