Annotate config class and extensions
This commit is contained in:
+171
-190
@@ -33,12 +33,13 @@ from pathlib import Path
|
||||
|
||||
from PyQt5.QtGui import QFontDatabase
|
||||
from PyQt5.QtCore import (
|
||||
QT_VERSION, QT_VERSION_STR, PYQT_VERSION, PYQT_VERSION_STR, QStandardPaths,
|
||||
QSysInfo, QLocale, QLibraryInfo, QTranslator
|
||||
PYQT_VERSION, PYQT_VERSION_STR, QT_VERSION, QT_VERSION_STR, QLibraryInfo,
|
||||
QLocale, QStandardPaths, QSysInfo, QTranslator
|
||||
)
|
||||
from PyQt5.QtWidgets import QApplication
|
||||
|
||||
from novelwriter.error import logException, formatException
|
||||
from novelwriter.common import checkPath, formatTimeStamp, NWConfigParser
|
||||
from novelwriter.error import formatException, logException
|
||||
from novelwriter.common import NWConfigParser, checkInt, checkPath, formatTimeStamp
|
||||
from novelwriter.constants import nwFiles, nwUnicode
|
||||
|
||||
if TYPE_CHECKING: # pragma: no cover
|
||||
@@ -52,7 +53,7 @@ class Config:
|
||||
LANG_NW = 1
|
||||
LANG_PROJ = 2
|
||||
|
||||
def __init__(self):
|
||||
def __init__(self) -> None:
|
||||
|
||||
# Initialisation
|
||||
# ==============
|
||||
@@ -236,11 +237,11 @@ class Config:
|
||||
##
|
||||
|
||||
@property
|
||||
def hasError(self):
|
||||
def hasError(self) -> bool:
|
||||
return self._hasError
|
||||
|
||||
@property
|
||||
def recentProjects(self):
|
||||
def recentProjects(self) -> RecentProjects:
|
||||
return self._recentObj
|
||||
|
||||
@property
|
||||
@@ -250,45 +251,45 @@ class Config:
|
||||
return self._themeObj
|
||||
|
||||
@property
|
||||
def mainWinSize(self):
|
||||
def mainWinSize(self) -> list[int]:
|
||||
return [int(x*self.guiScale) for x in self._mainWinSize]
|
||||
|
||||
@property
|
||||
def preferencesWinSize(self):
|
||||
def preferencesWinSize(self) -> list[int]:
|
||||
return [int(x*self.guiScale) for x in self._prefsWinSize]
|
||||
|
||||
@property
|
||||
def projLoadColWidths(self):
|
||||
def projLoadColWidths(self) -> list[int]:
|
||||
return [int(x*self.guiScale) for x in self._projLoadCols]
|
||||
|
||||
@property
|
||||
def mainPanePos(self):
|
||||
def mainPanePos(self) -> list[int]:
|
||||
return [int(x*self.guiScale) for x in self._mainPanePos]
|
||||
|
||||
@property
|
||||
def viewPanePos(self):
|
||||
def viewPanePos(self) -> list[int]:
|
||||
return [int(x*self.guiScale) for x in self._viewPanePos]
|
||||
|
||||
@property
|
||||
def outlinePanePos(self):
|
||||
def outlinePanePos(self) -> list[int]:
|
||||
return [int(x*self.guiScale) for x in self._outlnPanePos]
|
||||
|
||||
##
|
||||
# Getters
|
||||
##
|
||||
|
||||
def getTextWidth(self, focusMode=False):
|
||||
def getTextWidth(self, focusMode: bool = False) -> int:
|
||||
"""Get the text with for the correct editor mode."""
|
||||
if focusMode:
|
||||
return self.pxInt(max(self.focusWidth, 200))
|
||||
else:
|
||||
return self.pxInt(max(self.textWidth, 200))
|
||||
|
||||
def getTextMargin(self):
|
||||
def getTextMargin(self) -> int:
|
||||
"""Get the scaled text margin."""
|
||||
return self.pxInt(max(self.textMargin, 0))
|
||||
|
||||
def getTabWidth(self):
|
||||
def getTabWidth(self) -> int:
|
||||
"""Get the scaled tab width."""
|
||||
return self.pxInt(max(self.tabWidth, 0))
|
||||
|
||||
@@ -301,65 +302,65 @@ class Config:
|
||||
self._themeObj = theme
|
||||
return
|
||||
|
||||
def setMainWinSize(self, newWidth, newHeight):
|
||||
def setMainWinSize(self, width: int, height: int) -> None:
|
||||
"""Set the size of the main window, but only if the change is
|
||||
larger than 5 pixels. The OS window manager will sometimes
|
||||
adjust it a bit, and we don't want the main window to shrink or
|
||||
grow each time the app is opened.
|
||||
"""
|
||||
newWidth = int(newWidth/self.guiScale)
|
||||
newHeight = int(newHeight/self.guiScale)
|
||||
if abs(self._mainWinSize[0] - newWidth) > 5:
|
||||
self._mainWinSize[0] = newWidth
|
||||
if abs(self._mainWinSize[1] - newHeight) > 5:
|
||||
self._mainWinSize[1] = newHeight
|
||||
width = int(width/self.guiScale)
|
||||
height = int(height/self.guiScale)
|
||||
if abs(self._mainWinSize[0] - width) > 5:
|
||||
self._mainWinSize[0] = width
|
||||
if abs(self._mainWinSize[1] - height) > 5:
|
||||
self._mainWinSize[1] = height
|
||||
return
|
||||
|
||||
def setPreferencesWinSize(self, newWidth, newHeight):
|
||||
def setPreferencesWinSize(self, width: int, height: int) -> None:
|
||||
"""Set the size of the Preferences dialog window."""
|
||||
self._prefsWinSize[0] = int(newWidth/self.guiScale)
|
||||
self._prefsWinSize[1] = int(newHeight/self.guiScale)
|
||||
self._prefsWinSize[0] = int(width/self.guiScale)
|
||||
self._prefsWinSize[1] = int(height/self.guiScale)
|
||||
return
|
||||
|
||||
def setProjLoadColWidths(self, colWidths):
|
||||
def setProjLoadColWidths(self, widths: list[int]) -> None:
|
||||
"""Set the column widths of the Load Project dialog."""
|
||||
self._projLoadCols = [int(x/self.guiScale) for x in colWidths]
|
||||
self._projLoadCols = [int(x/self.guiScale) for x in widths]
|
||||
return
|
||||
|
||||
def setMainPanePos(self, panePos):
|
||||
def setMainPanePos(self, pos: list[int]) -> None:
|
||||
"""Set the position of the main GUI splitter."""
|
||||
self._mainPanePos = [int(x/self.guiScale) for x in panePos]
|
||||
self._mainPanePos = [int(x/self.guiScale) for x in pos]
|
||||
return
|
||||
|
||||
def setViewPanePos(self, panePos):
|
||||
def setViewPanePos(self, pos: list[int]) -> None:
|
||||
"""Set the position of the viewer meta data splitter."""
|
||||
self._viewPanePos = [int(x/self.guiScale) for x in panePos]
|
||||
self._viewPanePos = [int(x/self.guiScale) for x in pos]
|
||||
return
|
||||
|
||||
def setOutlinePanePos(self, panePos):
|
||||
def setOutlinePanePos(self, pos: list[int]) -> None:
|
||||
"""Set the position of the outline details splitter."""
|
||||
self._outlnPanePos = [int(x/self.guiScale) for x in panePos]
|
||||
self._outlnPanePos = [int(x/self.guiScale) for x in pos]
|
||||
return
|
||||
|
||||
def setLastPath(self, lastPath):
|
||||
def setLastPath(self, path: str | Path) -> None:
|
||||
"""Set the last used path. Only the folder is saved, so if the
|
||||
path is not a folder, the parent of the path is used instead.
|
||||
"""
|
||||
if isinstance(lastPath, (str, Path)):
|
||||
lastPath = checkPath(lastPath, self._homePath)
|
||||
if not lastPath.is_dir():
|
||||
lastPath = lastPath.parent
|
||||
if lastPath.is_dir():
|
||||
self._lastPath = lastPath
|
||||
if isinstance(path, (str, Path)):
|
||||
path = checkPath(path, self._homePath)
|
||||
if not path.is_dir():
|
||||
path = path.parent
|
||||
if path.is_dir():
|
||||
self._lastPath = path
|
||||
logger.debug("Last path updated: %s" % self._lastPath)
|
||||
return
|
||||
|
||||
def setBackupPath(self, backupPath: Path | str):
|
||||
def setBackupPath(self, path: Path | str) -> None:
|
||||
"""Set the current backup path."""
|
||||
self._backupPath = checkPath(backupPath, self._backPath)
|
||||
self._backupPath = checkPath(path, self._backPath)
|
||||
return
|
||||
|
||||
def setTextFont(self, family: str | None, pointSize: int = 12):
|
||||
def setTextFont(self, family: str | None, pointSize: int = 12) -> None:
|
||||
"""Set the text font if it exists. If it doesn't, or is None,
|
||||
set to default font.
|
||||
"""
|
||||
@@ -383,15 +384,11 @@ class Config:
|
||||
##
|
||||
|
||||
def pxInt(self, value: int) -> int:
|
||||
"""Used to scale fixed gui sizes by the screen scale factor.
|
||||
This function returns an int, which is always rounded down.
|
||||
"""
|
||||
"""Scale fixed gui sizes by the screen scale factor."""
|
||||
return int(value*self.guiScale)
|
||||
|
||||
def rpxInt(self, value: int) -> int:
|
||||
"""Used to un-scale fixed gui sizes by the screen scale factor.
|
||||
This function returns an int, which is always rounded down.
|
||||
"""
|
||||
"""Un-scale fixed gui sizes by the screen scale factor."""
|
||||
return int(value/self.guiScale)
|
||||
|
||||
def dataPath(self, target: str | None = None) -> Path:
|
||||
@@ -461,7 +458,8 @@ class Config:
|
||||
# Config Actions
|
||||
##
|
||||
|
||||
def initConfig(self, confPath: str | Path | None = None, dataPath: str | Path | None = None):
|
||||
def initConfig(self, confPath: str | Path | None = None,
|
||||
dataPath: str | Path | None = None) -> None:
|
||||
"""Initialise the config class. The manual setting of confPath
|
||||
and dataPath is mainly intended for the test suite.
|
||||
"""
|
||||
@@ -505,9 +503,8 @@ class Config:
|
||||
|
||||
return
|
||||
|
||||
def initLocalisation(self, nwApp):
|
||||
"""Initialise the localisation of the GUI.
|
||||
"""
|
||||
def initLocalisation(self, nwApp: QApplication) -> None:
|
||||
"""Initialise the localisation of the GUI."""
|
||||
self._qLocale = QLocale(self.guiLocale)
|
||||
QLocale.setDefault(self._qLocale)
|
||||
self._qtTrans = {}
|
||||
@@ -528,16 +525,15 @@ class Config:
|
||||
|
||||
return
|
||||
|
||||
def loadConfig(self):
|
||||
"""Load preferences from file and replace default settings.
|
||||
"""
|
||||
def loadConfig(self) -> bool:
|
||||
"""Load preferences from file and replace default settings."""
|
||||
logger.debug("Loading config file")
|
||||
|
||||
theConf = NWConfigParser()
|
||||
conf = NWConfigParser()
|
||||
cnfPath = self._confPath / nwFiles.CONF_FILE
|
||||
try:
|
||||
with open(cnfPath, mode="r", encoding="utf-8") as inFile:
|
||||
theConf.read_file(inFile)
|
||||
conf.read_file(inFile)
|
||||
except Exception as exc:
|
||||
logger.error("Could not load config file")
|
||||
logException()
|
||||
@@ -547,98 +543,98 @@ class Config:
|
||||
return False
|
||||
|
||||
# Main
|
||||
cnfSec = "Main"
|
||||
self.guiTheme = theConf.rdStr(cnfSec, "theme", self.guiTheme)
|
||||
self.guiSyntax = theConf.rdStr(cnfSec, "syntax", self.guiSyntax)
|
||||
self.guiFont = theConf.rdStr(cnfSec, "font", self.guiFont)
|
||||
self.guiFontSize = theConf.rdInt(cnfSec, "fontsize", self.guiFontSize)
|
||||
self.guiLocale = theConf.rdStr(cnfSec, "localisation", self.guiLocale)
|
||||
self.hideVScroll = theConf.rdBool(cnfSec, "hidevscroll", self.hideVScroll)
|
||||
self.hideHScroll = theConf.rdBool(cnfSec, "hidehscroll", self.hideHScroll)
|
||||
self.lastNotes = theConf.rdStr(cnfSec, "lastnotes", self.lastNotes)
|
||||
self._lastPath = theConf.rdPath(cnfSec, "lastpath", self._lastPath)
|
||||
sec = "Main"
|
||||
self.guiTheme = conf.rdStr(sec, "theme", self.guiTheme)
|
||||
self.guiSyntax = conf.rdStr(sec, "syntax", self.guiSyntax)
|
||||
self.guiFont = conf.rdStr(sec, "font", self.guiFont)
|
||||
self.guiFontSize = conf.rdInt(sec, "fontsize", self.guiFontSize)
|
||||
self.guiLocale = conf.rdStr(sec, "localisation", self.guiLocale)
|
||||
self.hideVScroll = conf.rdBool(sec, "hidevscroll", self.hideVScroll)
|
||||
self.hideHScroll = conf.rdBool(sec, "hidehscroll", self.hideHScroll)
|
||||
self.lastNotes = conf.rdStr(sec, "lastnotes", self.lastNotes)
|
||||
self._lastPath = conf.rdPath(sec, "lastpath", self._lastPath)
|
||||
|
||||
# Sizes
|
||||
cnfSec = "Sizes"
|
||||
self._mainWinSize = theConf.rdIntList(cnfSec, "mainwindow", self._mainWinSize)
|
||||
self._prefsWinSize = theConf.rdIntList(cnfSec, "preferences", self._prefsWinSize)
|
||||
self._projLoadCols = theConf.rdIntList(cnfSec, "projloadcols", self._projLoadCols)
|
||||
self._mainPanePos = theConf.rdIntList(cnfSec, "mainpane", self._mainPanePos)
|
||||
self._viewPanePos = theConf.rdIntList(cnfSec, "viewpane", self._viewPanePos)
|
||||
self._outlnPanePos = theConf.rdIntList(cnfSec, "outlinepane", self._outlnPanePos)
|
||||
sec = "Sizes"
|
||||
self._mainWinSize = conf.rdIntList(sec, "mainwindow", self._mainWinSize)
|
||||
self._prefsWinSize = conf.rdIntList(sec, "preferences", self._prefsWinSize)
|
||||
self._projLoadCols = conf.rdIntList(sec, "projloadcols", self._projLoadCols)
|
||||
self._mainPanePos = conf.rdIntList(sec, "mainpane", self._mainPanePos)
|
||||
self._viewPanePos = conf.rdIntList(sec, "viewpane", self._viewPanePos)
|
||||
self._outlnPanePos = conf.rdIntList(sec, "outlinepane", self._outlnPanePos)
|
||||
|
||||
# Project
|
||||
cnfSec = "Project"
|
||||
self.autoSaveProj = theConf.rdInt(cnfSec, "autosaveproject", self.autoSaveProj)
|
||||
self.autoSaveDoc = theConf.rdInt(cnfSec, "autosavedoc", self.autoSaveDoc)
|
||||
self.emphLabels = theConf.rdBool(cnfSec, "emphlabels", self.emphLabels)
|
||||
self._backupPath = theConf.rdPath(cnfSec, "backuppath", self._backupPath)
|
||||
self.backupOnClose = theConf.rdBool(cnfSec, "backuponclose", self.backupOnClose)
|
||||
self.askBeforeBackup = theConf.rdBool(cnfSec, "askbeforebackup", self.askBeforeBackup)
|
||||
sec = "Project"
|
||||
self.autoSaveProj = conf.rdInt(sec, "autosaveproject", self.autoSaveProj)
|
||||
self.autoSaveDoc = conf.rdInt(sec, "autosavedoc", self.autoSaveDoc)
|
||||
self.emphLabels = conf.rdBool(sec, "emphlabels", self.emphLabels)
|
||||
self._backupPath = conf.rdPath(sec, "backuppath", self._backupPath)
|
||||
self.backupOnClose = conf.rdBool(sec, "backuponclose", self.backupOnClose)
|
||||
self.askBeforeBackup = conf.rdBool(sec, "askbeforebackup", self.askBeforeBackup)
|
||||
|
||||
# Editor
|
||||
cnfSec = "Editor"
|
||||
self.textFont = theConf.rdStr(cnfSec, "textfont", self.textFont)
|
||||
self.textSize = theConf.rdInt(cnfSec, "textsize", self.textSize)
|
||||
self.textWidth = theConf.rdInt(cnfSec, "width", self.textWidth)
|
||||
self.textMargin = theConf.rdInt(cnfSec, "margin", self.textMargin)
|
||||
self.tabWidth = theConf.rdInt(cnfSec, "tabwidth", self.tabWidth)
|
||||
self.focusWidth = theConf.rdInt(cnfSec, "focuswidth", self.focusWidth)
|
||||
self.hideFocusFooter = theConf.rdBool(cnfSec, "hidefocusfooter", self.hideFocusFooter)
|
||||
self.doJustify = theConf.rdBool(cnfSec, "justify", self.doJustify)
|
||||
self.autoSelect = theConf.rdBool(cnfSec, "autoselect", self.autoSelect)
|
||||
self.doReplace = theConf.rdBool(cnfSec, "autoreplace", self.doReplace)
|
||||
self.doReplaceSQuote = theConf.rdBool(cnfSec, "repsquotes", self.doReplaceSQuote)
|
||||
self.doReplaceDQuote = theConf.rdBool(cnfSec, "repdquotes", self.doReplaceDQuote)
|
||||
self.doReplaceDash = theConf.rdBool(cnfSec, "repdash", self.doReplaceDash)
|
||||
self.doReplaceDots = theConf.rdBool(cnfSec, "repdots", self.doReplaceDots)
|
||||
self.scrollPastEnd = theConf.rdInt(cnfSec, "scrollpastend", self.scrollPastEnd)
|
||||
self.autoScroll = theConf.rdBool(cnfSec, "autoscroll", self.autoScroll)
|
||||
self.autoScrollPos = theConf.rdInt(cnfSec, "autoscrollpos", self.autoScrollPos)
|
||||
self.fmtSQuoteOpen = theConf.rdStr(cnfSec, "fmtsquoteopen", self.fmtSQuoteOpen)
|
||||
self.fmtSQuoteClose = theConf.rdStr(cnfSec, "fmtsquoteclose", self.fmtSQuoteClose)
|
||||
self.fmtDQuoteOpen = theConf.rdStr(cnfSec, "fmtdquoteopen", self.fmtDQuoteOpen)
|
||||
self.fmtDQuoteClose = theConf.rdStr(cnfSec, "fmtdquoteclose", self.fmtDQuoteClose)
|
||||
self.fmtPadBefore = theConf.rdStr(cnfSec, "fmtpadbefore", self.fmtPadBefore)
|
||||
self.fmtPadAfter = theConf.rdStr(cnfSec, "fmtpadafter", self.fmtPadAfter)
|
||||
self.fmtPadThin = theConf.rdBool(cnfSec, "fmtpadthin", self.fmtPadThin)
|
||||
self.spellLanguage = theConf.rdStr(cnfSec, "spellcheck", self.spellLanguage)
|
||||
self.showTabsNSpaces = theConf.rdBool(cnfSec, "showtabsnspaces", self.showTabsNSpaces)
|
||||
self.showLineEndings = theConf.rdBool(cnfSec, "showlineendings", self.showLineEndings)
|
||||
self.showMultiSpaces = theConf.rdBool(cnfSec, "showmultispaces", self.showMultiSpaces)
|
||||
self.wordCountTimer = theConf.rdFlt(cnfSec, "wordcounttimer", self.wordCountTimer)
|
||||
self.bigDocLimit = theConf.rdInt(cnfSec, "bigdoclimit", self.bigDocLimit)
|
||||
self.incNotesWCount = theConf.rdBool(cnfSec, "incnoteswcount", self.incNotesWCount)
|
||||
self.showFullPath = theConf.rdBool(cnfSec, "showfullpath", self.showFullPath)
|
||||
self.highlightQuotes = theConf.rdBool(cnfSec, "highlightquotes", self.highlightQuotes)
|
||||
self.allowOpenSQuote = theConf.rdBool(cnfSec, "allowopensquote", self.allowOpenSQuote)
|
||||
self.allowOpenDQuote = theConf.rdBool(cnfSec, "allowopendquote", self.allowOpenDQuote)
|
||||
self.highlightEmph = theConf.rdBool(cnfSec, "highlightemph", self.highlightEmph)
|
||||
self.stopWhenIdle = theConf.rdBool(cnfSec, "stopwhenidle", self.stopWhenIdle)
|
||||
self.userIdleTime = theConf.rdInt(cnfSec, "useridletime", self.userIdleTime)
|
||||
sec = "Editor"
|
||||
self.textFont = conf.rdStr(sec, "textfont", self.textFont)
|
||||
self.textSize = conf.rdInt(sec, "textsize", self.textSize)
|
||||
self.textWidth = conf.rdInt(sec, "width", self.textWidth)
|
||||
self.textMargin = conf.rdInt(sec, "margin", self.textMargin)
|
||||
self.tabWidth = conf.rdInt(sec, "tabwidth", self.tabWidth)
|
||||
self.focusWidth = conf.rdInt(sec, "focuswidth", self.focusWidth)
|
||||
self.hideFocusFooter = conf.rdBool(sec, "hidefocusfooter", self.hideFocusFooter)
|
||||
self.doJustify = conf.rdBool(sec, "justify", self.doJustify)
|
||||
self.autoSelect = conf.rdBool(sec, "autoselect", self.autoSelect)
|
||||
self.doReplace = conf.rdBool(sec, "autoreplace", self.doReplace)
|
||||
self.doReplaceSQuote = conf.rdBool(sec, "repsquotes", self.doReplaceSQuote)
|
||||
self.doReplaceDQuote = conf.rdBool(sec, "repdquotes", self.doReplaceDQuote)
|
||||
self.doReplaceDash = conf.rdBool(sec, "repdash", self.doReplaceDash)
|
||||
self.doReplaceDots = conf.rdBool(sec, "repdots", self.doReplaceDots)
|
||||
self.scrollPastEnd = conf.rdInt(sec, "scrollpastend", self.scrollPastEnd)
|
||||
self.autoScroll = conf.rdBool(sec, "autoscroll", self.autoScroll)
|
||||
self.autoScrollPos = conf.rdInt(sec, "autoscrollpos", self.autoScrollPos)
|
||||
self.fmtSQuoteOpen = conf.rdStr(sec, "fmtsquoteopen", self.fmtSQuoteOpen)
|
||||
self.fmtSQuoteClose = conf.rdStr(sec, "fmtsquoteclose", self.fmtSQuoteClose)
|
||||
self.fmtDQuoteOpen = conf.rdStr(sec, "fmtdquoteopen", self.fmtDQuoteOpen)
|
||||
self.fmtDQuoteClose = conf.rdStr(sec, "fmtdquoteclose", self.fmtDQuoteClose)
|
||||
self.fmtPadBefore = conf.rdStr(sec, "fmtpadbefore", self.fmtPadBefore)
|
||||
self.fmtPadAfter = conf.rdStr(sec, "fmtpadafter", self.fmtPadAfter)
|
||||
self.fmtPadThin = conf.rdBool(sec, "fmtpadthin", self.fmtPadThin)
|
||||
self.spellLanguage = conf.rdStr(sec, "spellcheck", self.spellLanguage)
|
||||
self.showTabsNSpaces = conf.rdBool(sec, "showtabsnspaces", self.showTabsNSpaces)
|
||||
self.showLineEndings = conf.rdBool(sec, "showlineendings", self.showLineEndings)
|
||||
self.showMultiSpaces = conf.rdBool(sec, "showmultispaces", self.showMultiSpaces)
|
||||
self.wordCountTimer = conf.rdFlt(sec, "wordcounttimer", self.wordCountTimer)
|
||||
self.bigDocLimit = conf.rdInt(sec, "bigdoclimit", self.bigDocLimit)
|
||||
self.incNotesWCount = conf.rdBool(sec, "incnoteswcount", self.incNotesWCount)
|
||||
self.showFullPath = conf.rdBool(sec, "showfullpath", self.showFullPath)
|
||||
self.highlightQuotes = conf.rdBool(sec, "highlightquotes", self.highlightQuotes)
|
||||
self.allowOpenSQuote = conf.rdBool(sec, "allowopensquote", self.allowOpenSQuote)
|
||||
self.allowOpenDQuote = conf.rdBool(sec, "allowopendquote", self.allowOpenDQuote)
|
||||
self.highlightEmph = conf.rdBool(sec, "highlightemph", self.highlightEmph)
|
||||
self.stopWhenIdle = conf.rdBool(sec, "stopwhenidle", self.stopWhenIdle)
|
||||
self.userIdleTime = conf.rdInt(sec, "useridletime", self.userIdleTime)
|
||||
|
||||
# State
|
||||
cnfSec = "State"
|
||||
self.showRefPanel = theConf.rdBool(cnfSec, "showrefpanel", self.showRefPanel)
|
||||
self.viewComments = theConf.rdBool(cnfSec, "viewcomments", self.viewComments)
|
||||
self.viewSynopsis = theConf.rdBool(cnfSec, "viewsynopsis", self.viewSynopsis)
|
||||
self.searchCase = theConf.rdBool(cnfSec, "searchcase", self.searchCase)
|
||||
self.searchWord = theConf.rdBool(cnfSec, "searchword", self.searchWord)
|
||||
self.searchRegEx = theConf.rdBool(cnfSec, "searchregex", self.searchRegEx)
|
||||
self.searchLoop = theConf.rdBool(cnfSec, "searchloop", self.searchLoop)
|
||||
self.searchNextFile = theConf.rdBool(cnfSec, "searchnextfile", self.searchNextFile)
|
||||
self.searchMatchCap = theConf.rdBool(cnfSec, "searchmatchcap", self.searchMatchCap)
|
||||
sec = "State"
|
||||
self.showRefPanel = conf.rdBool(sec, "showrefpanel", self.showRefPanel)
|
||||
self.viewComments = conf.rdBool(sec, "viewcomments", self.viewComments)
|
||||
self.viewSynopsis = conf.rdBool(sec, "viewsynopsis", self.viewSynopsis)
|
||||
self.searchCase = conf.rdBool(sec, "searchcase", self.searchCase)
|
||||
self.searchWord = conf.rdBool(sec, "searchword", self.searchWord)
|
||||
self.searchRegEx = conf.rdBool(sec, "searchregex", self.searchRegEx)
|
||||
self.searchLoop = conf.rdBool(sec, "searchloop", self.searchLoop)
|
||||
self.searchNextFile = conf.rdBool(sec, "searchnextfile", self.searchNextFile)
|
||||
self.searchMatchCap = conf.rdBool(sec, "searchmatchcap", self.searchMatchCap)
|
||||
|
||||
# Deprecated Settings or Locations as of 2.0
|
||||
# ToDo: These will be loaded for a few minor releases until the users have converted them
|
||||
self.guiFont = theConf.rdStr("Main", "guifont", self.guiFont)
|
||||
self.guiFontSize = theConf.rdInt("Main", "guifontsize", self.guiFontSize)
|
||||
self.guiLocale = theConf.rdStr("Main", "guilang", self.guiLocale)
|
||||
self._backupPath = theConf.rdPath("Backup", "backuppath", self._backupPath)
|
||||
self.backupOnClose = theConf.rdBool("Backup", "backuponclose", self.backupOnClose)
|
||||
self.askBeforeBackup = theConf.rdBool("Backup", "askbeforebackup", self.askBeforeBackup)
|
||||
fmtSingleQuotes = theConf.rdStrList(cnfSec, "fmtsinglequote", [])
|
||||
fmtDoubleQuotes = theConf.rdStrList(cnfSec, "fmtdoublequote", [])
|
||||
self.guiFont = conf.rdStr("Main", "guifont", self.guiFont)
|
||||
self.guiFontSize = conf.rdInt("Main", "guifontsize", self.guiFontSize)
|
||||
self.guiLocale = conf.rdStr("Main", "guilang", self.guiLocale)
|
||||
self._backupPath = conf.rdPath("Backup", "backuppath", self._backupPath)
|
||||
self.backupOnClose = conf.rdBool("Backup", "backuponclose", self.backupOnClose)
|
||||
self.askBeforeBackup = conf.rdBool("Backup", "askbeforebackup", self.askBeforeBackup)
|
||||
fmtSingleQuotes = conf.rdStrList(sec, "fmtsinglequote", [])
|
||||
fmtDoubleQuotes = conf.rdStrList(sec, "fmtdoublequote", [])
|
||||
|
||||
if isinstance(fmtSingleQuotes, list) and len(fmtSingleQuotes) == 2:
|
||||
self.fmtSQuoteOpen = fmtSingleQuotes[0]
|
||||
@@ -661,18 +657,17 @@ class Config:
|
||||
|
||||
return True
|
||||
|
||||
def saveConfig(self):
|
||||
"""Save the current preferences to file.
|
||||
"""
|
||||
def saveConfig(self) -> bool:
|
||||
"""Save the current preferences to file."""
|
||||
logger.debug("Saving config file")
|
||||
|
||||
theConf = NWConfigParser()
|
||||
conf = NWConfigParser()
|
||||
|
||||
theConf["Meta"] = {
|
||||
conf["Meta"] = {
|
||||
"timestamp": formatTimeStamp(time()),
|
||||
}
|
||||
|
||||
theConf["Main"] = {
|
||||
conf["Main"] = {
|
||||
"theme": str(self.guiTheme),
|
||||
"syntax": str(self.guiSyntax),
|
||||
"font": str(self.guiFont),
|
||||
@@ -684,7 +679,7 @@ class Config:
|
||||
"lastpath": str(self._lastPath),
|
||||
}
|
||||
|
||||
theConf["Sizes"] = {
|
||||
conf["Sizes"] = {
|
||||
"mainwindow": self._packList(self._mainWinSize),
|
||||
"preferences": self._packList(self._prefsWinSize),
|
||||
"projloadcols": self._packList(self._projLoadCols),
|
||||
@@ -693,7 +688,7 @@ class Config:
|
||||
"outlinepane": self._packList(self._outlnPanePos),
|
||||
}
|
||||
|
||||
theConf["Project"] = {
|
||||
conf["Project"] = {
|
||||
"autosaveproject": str(self.autoSaveProj),
|
||||
"autosavedoc": str(self.autoSaveDoc),
|
||||
"emphlabels": str(self.emphLabels),
|
||||
@@ -702,7 +697,7 @@ class Config:
|
||||
"askbeforebackup": str(self.askBeforeBackup),
|
||||
}
|
||||
|
||||
theConf["Editor"] = {
|
||||
conf["Editor"] = {
|
||||
"textfont": str(self.textFont),
|
||||
"textsize": str(self.textSize),
|
||||
"width": str(self.textWidth),
|
||||
@@ -743,7 +738,7 @@ class Config:
|
||||
"useridletime": str(self.userIdleTime),
|
||||
}
|
||||
|
||||
theConf["State"] = {
|
||||
conf["State"] = {
|
||||
"showrefpanel": str(self.showRefPanel),
|
||||
"viewcomments": str(self.viewComments),
|
||||
"viewsynopsis": str(self.viewSynopsis),
|
||||
@@ -759,7 +754,7 @@ class Config:
|
||||
cnfPath = self._confPath / nwFiles.CONF_FILE
|
||||
try:
|
||||
with open(cnfPath, mode="w", encoding="utf-8") as outFile:
|
||||
theConf.write(outFile)
|
||||
conf.write(outFile)
|
||||
except Exception as exc:
|
||||
logger.error("Could not save config file")
|
||||
logException()
|
||||
@@ -774,26 +769,14 @@ class Config:
|
||||
# Internal Functions
|
||||
##
|
||||
|
||||
def _packList(self, inData):
|
||||
def _packList(self, data: list) -> str:
|
||||
"""Pack a list of items into a comma-separated string for saving
|
||||
to the config file.
|
||||
"""
|
||||
return ", ".join([str(inVal) for inVal in inData])
|
||||
return ", ".join([str(inVal) for inVal in data])
|
||||
|
||||
def _checkNone(self, checkVal):
|
||||
"""Return a NoneType if the value corresponds to None, otherwise
|
||||
return the value unchanged.
|
||||
"""
|
||||
if checkVal is None:
|
||||
return None
|
||||
if isinstance(checkVal, str):
|
||||
if checkVal.lower() == "none":
|
||||
return None
|
||||
return checkVal
|
||||
|
||||
def _checkOptionalPackages(self):
|
||||
"""Check if we have the optional packages used by some features.
|
||||
"""
|
||||
def _checkOptionalPackages(self) -> None:
|
||||
"""Check optional packages used by some features."""
|
||||
try:
|
||||
import enchant # noqa: F401
|
||||
except ImportError:
|
||||
@@ -809,14 +792,13 @@ class Config:
|
||||
|
||||
class RecentProjects:
|
||||
|
||||
def __init__(self, config):
|
||||
def __init__(self, config: Config) -> None:
|
||||
self._conf = config
|
||||
self._data = {}
|
||||
return
|
||||
|
||||
def loadCache(self):
|
||||
"""Load the cache file for recent projects.
|
||||
"""
|
||||
def loadCache(self) -> bool:
|
||||
"""Load the cache file for recent projects."""
|
||||
self._data = {}
|
||||
|
||||
cacheFile = self._conf.dataPath(nwFiles.RECENT_FILE)
|
||||
@@ -839,9 +821,8 @@ class RecentProjects:
|
||||
|
||||
return True
|
||||
|
||||
def saveCache(self):
|
||||
"""Save the cache dictionary of recent projects.
|
||||
"""
|
||||
def saveCache(self) -> bool:
|
||||
"""Save the cache dictionary of recent projects."""
|
||||
cacheFile = self._conf.dataPath(nwFiles.RECENT_FILE)
|
||||
cacheTemp = cacheFile.with_suffix(".tmp")
|
||||
try:
|
||||
@@ -855,27 +836,27 @@ class RecentProjects:
|
||||
|
||||
return True
|
||||
|
||||
def listEntries(self):
|
||||
"""List all items in the cache.
|
||||
"""
|
||||
return [(k, e["title"], e["words"], e["time"]) for k, e in self._data.items()]
|
||||
def listEntries(self) -> list[tuple[str, str, int, int]]:
|
||||
"""List all items in the cache."""
|
||||
return [
|
||||
(str(k), str(e["title"]), checkInt(e["words"], 0), checkInt(e["time"], 0))
|
||||
for k, e in self._data.items()
|
||||
]
|
||||
|
||||
def update(self, projPath, projTitle, wordCount, saveTime):
|
||||
"""Add or update recent cache information on a given project.
|
||||
"""
|
||||
self._data[str(projPath)] = {
|
||||
"title": projTitle,
|
||||
"words": int(wordCount),
|
||||
"time": int(saveTime),
|
||||
def update(self, path: str | Path, title: str, words: int, saved: float | int) -> None:
|
||||
"""Add or update recent cache information on a given project."""
|
||||
self._data[str(path)] = {
|
||||
"title": title,
|
||||
"words": int(words),
|
||||
"time": int(saved),
|
||||
}
|
||||
self.saveCache()
|
||||
return
|
||||
|
||||
def remove(self, projPath):
|
||||
"""Try to remove a path from the recent projects cache.
|
||||
"""
|
||||
if self._data.pop(str(projPath), None) is not None:
|
||||
logger.debug("Removed recent: %s", projPath)
|
||||
def remove(self, path: str | Path) -> None:
|
||||
"""Try to remove a path from the recent projects cache."""
|
||||
if self._data.pop(str(path), None) is not None:
|
||||
logger.debug("Removed recent: %s", path)
|
||||
self.saveCache()
|
||||
return
|
||||
|
||||
|
||||
@@ -100,8 +100,9 @@ class GuiProjectLoad(QDialog):
|
||||
self.listBox.setIconSize(QSize(iPx, iPx))
|
||||
|
||||
treeHead = self.listBox.headerItem()
|
||||
treeHead.setTextAlignment(self.C_COUNT, Qt.AlignRight)
|
||||
treeHead.setTextAlignment(self.C_TIME, Qt.AlignRight)
|
||||
if treeHead:
|
||||
treeHead.setTextAlignment(self.C_COUNT, Qt.AlignRight)
|
||||
treeHead.setTextAlignment(self.C_TIME, Qt.AlignRight)
|
||||
|
||||
self.lblRecent = QLabel("<b>%s</b>" % self.tr("Recently Opened Projects"))
|
||||
self.lblPath = QLabel("<b>%s</b>" % self.tr("Path"))
|
||||
@@ -281,8 +282,7 @@ class GuiProjectLoad(QDialog):
|
||||
newItem.setFont(self.C_TIME, CONFIG.theme.guiFontFixed)
|
||||
self.listBox.addTopLevelItem(newItem)
|
||||
|
||||
if self.listBox.topLevelItemCount() > 0:
|
||||
self.listBox.topLevelItem(0).setSelected(True)
|
||||
self.listBox.setCurrentItem(self.listBox.topLevelItem(0))
|
||||
|
||||
projColWidth = CONFIG.projLoadColWidths
|
||||
if len(projColWidth) == 3:
|
||||
|
||||
@@ -42,7 +42,7 @@ class NProgressCircle(QProgressBar):
|
||||
"_cPen", "_bPen", "_tColor"
|
||||
)
|
||||
|
||||
def __init__(self, parent: QWidget, size: int, point: int):
|
||||
def __init__(self, parent: QWidget, size: int, point: int) -> None:
|
||||
super().__init__(parent=parent)
|
||||
self._text = None
|
||||
self._point = point
|
||||
@@ -60,10 +60,8 @@ class NProgressCircle(QProgressBar):
|
||||
self.setFixedHeight(size)
|
||||
return
|
||||
|
||||
def setColours(
|
||||
self, back: QColor | None = None, track: QColor | None = None,
|
||||
bar: QColor | None = None, text: QColor | None = None
|
||||
):
|
||||
def setColours(self, back: QColor | None = None, track: QColor | None = None,
|
||||
bar: QColor | None = None, text: QColor | None = None) -> None:
|
||||
"""Set the colours of the widget."""
|
||||
if isinstance(back, QColor):
|
||||
self._dPen = QPen(back)
|
||||
@@ -76,13 +74,13 @@ class NProgressCircle(QProgressBar):
|
||||
self._tColor = text
|
||||
return
|
||||
|
||||
def setCentreText(self, text: str | None):
|
||||
def setCentreText(self, text: str | None) -> None:
|
||||
"""Replace the progress text with a custom string."""
|
||||
self._text = text
|
||||
self.setValue(self.value()) # Triggers a redraw
|
||||
return
|
||||
|
||||
def paintEvent(self, event: QPaintEvent):
|
||||
def paintEvent(self, event: QPaintEvent) -> None:
|
||||
"""Custom painter for the progress bar."""
|
||||
progress = 100.0*self.value()/self.maximum()
|
||||
angle = ceil(16*3.6*progress)
|
||||
|
||||
@@ -37,7 +37,7 @@ FONT_SCALE = 0.9
|
||||
|
||||
class NConfigLayout(QGridLayout):
|
||||
|
||||
def __init__(self):
|
||||
def __init__(self) -> None:
|
||||
super().__init__()
|
||||
|
||||
self._nextRow = 0
|
||||
@@ -56,7 +56,8 @@ class NConfigLayout(QGridLayout):
|
||||
# Getters and Setters
|
||||
##
|
||||
|
||||
def setHelpTextStyle(self, color: QColor | list | tuple, fontScale: float = FONT_SCALE):
|
||||
def setHelpTextStyle(self, color: QColor | list | tuple,
|
||||
fontScale: float = FONT_SCALE) -> None:
|
||||
"""Set the text color for the help text."""
|
||||
if isinstance(color, QColor):
|
||||
self._helpCol = color
|
||||
@@ -65,7 +66,7 @@ class NConfigLayout(QGridLayout):
|
||||
self._fontScale = fontScale
|
||||
return
|
||||
|
||||
def setHelpText(self, row: int, text: str):
|
||||
def setHelpText(self, row: int, text: str) -> None:
|
||||
"""Set the text for the help label."""
|
||||
if row in self._itemMap:
|
||||
qHelp = self._itemMap[row][1]
|
||||
@@ -73,7 +74,7 @@ class NConfigLayout(QGridLayout):
|
||||
qHelp.setText(text)
|
||||
return
|
||||
|
||||
def setLabelText(self, row: int, text: str):
|
||||
def setLabelText(self, row: int, text: str) -> None:
|
||||
"""Set the text for the main label."""
|
||||
if row in self._itemMap:
|
||||
self._itemMap[row](0).setText(text)
|
||||
@@ -83,7 +84,7 @@ class NConfigLayout(QGridLayout):
|
||||
# Class Methods
|
||||
##
|
||||
|
||||
def addGroupLabel(self, label: str):
|
||||
def addGroupLabel(self, label: str) -> None:
|
||||
"""Add a text label to separate groups of settings."""
|
||||
hM = CONFIG.pxInt(4)
|
||||
qLabel = QLabel("<b>%s</b>" % label)
|
||||
@@ -94,10 +95,8 @@ class NConfigLayout(QGridLayout):
|
||||
self._nextRow += 1
|
||||
return
|
||||
|
||||
def addRow(
|
||||
self, label: str, widget: QWidget, helpText: str | None = None,
|
||||
unit: str | None = None, button: QWidget | None = None
|
||||
) -> int:
|
||||
def addRow(self, label: str, widget: QWidget, helpText: str | None = None,
|
||||
unit: str | None = None, button: QWidget | None = None) -> int:
|
||||
"""Add a label and a widget as a new row of the grid."""
|
||||
wSp = CONFIG.pxInt(8)
|
||||
qLabel = QLabel(label)
|
||||
@@ -155,7 +154,7 @@ class NSimpleLayout(QGridLayout):
|
||||
column layout.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
def __init__(self) -> None:
|
||||
super().__init__()
|
||||
self._nextRow = 0
|
||||
|
||||
@@ -170,7 +169,7 @@ class NSimpleLayout(QGridLayout):
|
||||
# Methods
|
||||
##
|
||||
|
||||
def addGroupLabel(self, label: str):
|
||||
def addGroupLabel(self, label: str) -> None:
|
||||
"""Add a text label to separate groups of settings."""
|
||||
hM = CONFIG.pxInt(4)
|
||||
qLabel = QLabel("<b>%s</b>" % label)
|
||||
@@ -181,7 +180,7 @@ class NSimpleLayout(QGridLayout):
|
||||
self._nextRow += 1
|
||||
return
|
||||
|
||||
def addRow(self, label: str, widget: QWidget):
|
||||
def addRow(self, label: str, widget: QWidget) -> None:
|
||||
"""Add a label and a widget as a new row of the grid."""
|
||||
wSp = CONFIG.pxInt(8)
|
||||
qLabel = QLabel(label)
|
||||
@@ -208,7 +207,8 @@ class NSimpleLayout(QGridLayout):
|
||||
|
||||
class NHelpLabel(QLabel):
|
||||
|
||||
def __init__(self, text: str, color: QColor | list | tuple, fontSize: float = FONT_SCALE):
|
||||
def __init__(self, text: str, color: QColor | list | tuple,
|
||||
fontSize: float = FONT_SCALE) -> None:
|
||||
super().__init__(text)
|
||||
|
||||
if isinstance(color, QColor):
|
||||
|
||||
@@ -23,10 +23,11 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
from PyQt5.QtCore import QRect, QPoint
|
||||
from PyQt5.QtGui import QPaintEvent
|
||||
from PyQt5.QtCore import QRect, QPoint, QSize
|
||||
from PyQt5.QtWidgets import (
|
||||
QDialog, QHBoxLayout, QStyle, QStyleOptionTab, QStylePainter, QTabBar,
|
||||
QTabWidget, QVBoxLayout
|
||||
QTabWidget, QVBoxLayout, QWidget
|
||||
)
|
||||
|
||||
from novelwriter import CONFIG
|
||||
@@ -34,7 +35,7 @@ from novelwriter import CONFIG
|
||||
|
||||
class NPagedDialog(QDialog):
|
||||
|
||||
def __init__(self, parent=None):
|
||||
def __init__(self, parent: QWidget) -> None:
|
||||
super().__init__(parent=parent)
|
||||
|
||||
self._tabBar = NVerticalTabBar(self)
|
||||
@@ -67,21 +68,18 @@ class NPagedDialog(QDialog):
|
||||
|
||||
return
|
||||
|
||||
def addTab(self, widget, label):
|
||||
"""Forward the adding of tabs to the QTabWidget.
|
||||
"""
|
||||
def addTab(self, widget: QWidget, label: str) -> None:
|
||||
"""Forward the adding of tabs to the QTabWidget."""
|
||||
self._tabBox.addTab(widget, label)
|
||||
return
|
||||
|
||||
def addControls(self, buttonBar):
|
||||
"""Add a button bar to the dialog.
|
||||
"""
|
||||
def addControls(self, buttonBar: QWidget) -> None:
|
||||
"""Add a button bar to the dialog."""
|
||||
self._buttonBox.addWidget(buttonBar)
|
||||
return
|
||||
|
||||
def setCurrentWidget(self, widget):
|
||||
"""Forward the changing of tab to the QTabWidget.
|
||||
"""
|
||||
def setCurrentWidget(self, widget: QWidget) -> None:
|
||||
"""Forward the changing of tab to the QTabWidget."""
|
||||
self._tabBox.setCurrentWidget(widget)
|
||||
return
|
||||
|
||||
@@ -90,20 +88,19 @@ class NPagedDialog(QDialog):
|
||||
|
||||
class NVerticalTabBar(QTabBar):
|
||||
|
||||
def __init__(self, parent=None):
|
||||
def __init__(self, parent: QWidget) -> None:
|
||||
super().__init__(parent=parent)
|
||||
self._mW = CONFIG.pxInt(150)
|
||||
return
|
||||
|
||||
def tabSizeHint(self, index):
|
||||
"""Return a transposed size hint for the rotated bar.
|
||||
"""
|
||||
def tabSizeHint(self, index: int) -> QSize:
|
||||
"""Return a transposed size hint for the rotated bar."""
|
||||
tSize = super().tabSizeHint(index)
|
||||
tSize.transpose()
|
||||
tSize.setWidth(min(tSize.width(), self._mW))
|
||||
return tSize
|
||||
|
||||
def paintEvent(self, event):
|
||||
def paintEvent(self, event: QPaintEvent) -> None:
|
||||
"""Custom implementation of the label painter that rotates the
|
||||
label 90 degrees.
|
||||
"""
|
||||
|
||||
@@ -35,11 +35,11 @@ class NProgressSimple(QProgressBar):
|
||||
A custom widget that paints a plain bar with no other styling.
|
||||
"""
|
||||
|
||||
def __init__(self, parent: QWidget):
|
||||
def __init__(self, parent: QWidget) -> None:
|
||||
super().__init__(parent=parent)
|
||||
return
|
||||
|
||||
def paintEvent(self, event: QPaintEvent):
|
||||
def paintEvent(self, event: QPaintEvent) -> None:
|
||||
"""Custom painter for the progress bar."""
|
||||
if self.value() == 0:
|
||||
return
|
||||
|
||||
@@ -23,9 +23,9 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
from PyQt5.QtGui import QPainter
|
||||
from PyQt5.QtCore import Qt, QRectF, QPropertyAnimation, pyqtProperty
|
||||
from PyQt5.QtWidgets import QSizePolicy, QAbstractButton
|
||||
from PyQt5.QtGui import QMouseEvent, QPainter, QPaintEvent, QResizeEvent
|
||||
from PyQt5.QtCore import QEvent, QPropertyAnimation, QRectF, Qt, pyqtProperty
|
||||
from PyQt5.QtWidgets import QAbstractButton, QSizePolicy, QWidget
|
||||
|
||||
from novelwriter import CONFIG
|
||||
from novelwriter.constants import nwUnicode
|
||||
@@ -33,7 +33,8 @@ from novelwriter.constants import nwUnicode
|
||||
|
||||
class NSwitch(QAbstractButton):
|
||||
|
||||
def __init__(self, parent=None, width=None, height=None):
|
||||
def __init__(self, parent: QWidget | None = None,
|
||||
width: int | None = None, height: int | None = None) -> None:
|
||||
super().__init__(parent=parent)
|
||||
|
||||
if width is None:
|
||||
@@ -64,12 +65,12 @@ class NSwitch(QAbstractButton):
|
||||
# Properties
|
||||
##
|
||||
|
||||
@pyqtProperty(int)
|
||||
def offset(self):
|
||||
@pyqtProperty(int) # type: ignore
|
||||
def offset(self) -> int: # type: ignore
|
||||
return self._offset
|
||||
|
||||
@offset.setter
|
||||
def offset(self, offset):
|
||||
@offset.setter # type: ignore
|
||||
def offset(self, offset: int):
|
||||
self._offset = offset
|
||||
self.update()
|
||||
return
|
||||
@@ -78,33 +79,30 @@ class NSwitch(QAbstractButton):
|
||||
# Getters and Setters
|
||||
##
|
||||
|
||||
def setChecked(self, checked):
|
||||
"""Overload setChecked to also alter the offset.
|
||||
"""
|
||||
def setChecked(self, checked: bool) -> None:
|
||||
"""Overload setChecked to also alter the offset."""
|
||||
super().setChecked(checked)
|
||||
if checked:
|
||||
self.offset = self._xW - self._xR
|
||||
self._offset = self._xW - self._xR
|
||||
else:
|
||||
self.offset = self._xR
|
||||
self._offset = self._xR
|
||||
return
|
||||
|
||||
##
|
||||
# Events
|
||||
##
|
||||
|
||||
def resizeEvent(self, event):
|
||||
"""Overload resize to ensure correct offset.
|
||||
"""
|
||||
def resizeEvent(self, event: QResizeEvent) -> None:
|
||||
"""Overload resize to ensure correct offset."""
|
||||
super().resizeEvent(event)
|
||||
if self.isChecked():
|
||||
self.offset = self._xW - self._xR
|
||||
self._offset = self._xW - self._xR
|
||||
else:
|
||||
self.offset = self._xR
|
||||
self._offset = self._xR
|
||||
return
|
||||
|
||||
def paintEvent(self, event):
|
||||
"""Drawing the switch itself.
|
||||
"""
|
||||
def paintEvent(self, event: QPaintEvent) -> None:
|
||||
"""Drawing the switch itself."""
|
||||
qPaint = QPainter(self)
|
||||
qPaint.setRenderHint(QPainter.Antialiasing, True)
|
||||
qPaint.setPen(Qt.NoPen)
|
||||
@@ -134,27 +132,26 @@ class NSwitch(QAbstractButton):
|
||||
qPaint.drawRoundedRect(0, 0, self._xW, self._xH, self._xR, self._xR)
|
||||
|
||||
qPaint.setBrush(thumbBrush)
|
||||
qPaint.drawEllipse(self.offset - self._rR, self._rB, self._rH, self._rH)
|
||||
qPaint.drawEllipse(self._offset - self._rR, self._rB, self._rH, self._rH)
|
||||
|
||||
theFont = qPaint.font()
|
||||
theFont.setPixelSize(self._xT)
|
||||
qPaint.setPen(textColor)
|
||||
qPaint.setFont(theFont)
|
||||
qPaint.drawText(
|
||||
QRectF(self.offset - self._rR, self._rB, self._rH, self._rH),
|
||||
QRectF(self._offset - self._rR, self._rB, self._rH, self._rH),
|
||||
Qt.AlignCenter, thumbText
|
||||
)
|
||||
|
||||
return
|
||||
|
||||
def mouseReleaseEvent(self, event):
|
||||
"""Animate the switch on mouse release.
|
||||
"""
|
||||
def mouseReleaseEvent(self, event: QMouseEvent) -> None:
|
||||
"""Animate the switch on mouse release."""
|
||||
super().mouseReleaseEvent(event)
|
||||
if event.button() == Qt.LeftButton:
|
||||
doAnim = QPropertyAnimation(self, b"offset", self)
|
||||
doAnim.setDuration(120)
|
||||
doAnim.setStartValue(self.offset)
|
||||
doAnim.setStartValue(self._offset)
|
||||
if self.isChecked():
|
||||
doAnim.setEndValue(self._xW - self._xR)
|
||||
else:
|
||||
@@ -162,9 +159,8 @@ class NSwitch(QAbstractButton):
|
||||
doAnim.start()
|
||||
return
|
||||
|
||||
def enterEvent(self, event):
|
||||
"""Change the cursor when hovering the button.
|
||||
"""
|
||||
def enterEvent(self, event: QEvent) -> None:
|
||||
"""Change the cursor when hovering the button."""
|
||||
self.setCursor(Qt.PointingHandCursor)
|
||||
super().enterEvent(event)
|
||||
return
|
||||
|
||||
@@ -23,8 +23,8 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
from PyQt5.QtCore import Qt, pyqtSignal
|
||||
from PyQt5.QtGui import QIcon
|
||||
from PyQt5.QtCore import Qt, pyqtSignal
|
||||
from PyQt5.QtWidgets import QGridLayout, QLabel, QScrollArea, QSizePolicy, QWidget
|
||||
|
||||
from novelwriter.extensions.switch import NSwitch
|
||||
@@ -39,7 +39,7 @@ class NSwitchBox(QScrollArea):
|
||||
|
||||
switchToggled = pyqtSignal(str, bool)
|
||||
|
||||
def __init__(self, parent: QWidget, baseSize: int):
|
||||
def __init__(self, parent: QWidget, baseSize: int) -> None:
|
||||
super().__init__(parent=parent)
|
||||
self._index = 0
|
||||
self._hSwitch = baseSize
|
||||
@@ -49,7 +49,7 @@ class NSwitchBox(QScrollArea):
|
||||
self.clear()
|
||||
return
|
||||
|
||||
def clear(self):
|
||||
def clear(self) -> None:
|
||||
"""Rebuild the content of the core widget."""
|
||||
self._index = 0
|
||||
self._widgets = []
|
||||
@@ -66,7 +66,7 @@ class NSwitchBox(QScrollArea):
|
||||
|
||||
return
|
||||
|
||||
def addLabel(self, text: str):
|
||||
def addLabel(self, text: str) -> None:
|
||||
"""Add a header label to the content box."""
|
||||
label = QLabel(text)
|
||||
font = label.font()
|
||||
@@ -77,7 +77,7 @@ class NSwitchBox(QScrollArea):
|
||||
self._bumpIndex()
|
||||
return
|
||||
|
||||
def addItem(self, qIcon: QIcon, text: str, identifier: str, default: bool = False):
|
||||
def addItem(self, qIcon: QIcon, text: str, identifier: str, default: bool = False) -> None:
|
||||
"""Add an item to the content box."""
|
||||
icon = QLabel("")
|
||||
icon.setAlignment(Qt.AlignRight | Qt.AlignVCenter)
|
||||
@@ -97,7 +97,7 @@ class NSwitchBox(QScrollArea):
|
||||
|
||||
return
|
||||
|
||||
def addSeparator(self):
|
||||
def addSeparator(self) -> None:
|
||||
"""Add a blank entry in the content box."""
|
||||
spacer = QWidget()
|
||||
spacer.setFixedHeight(int(0.5*self._sIcon))
|
||||
@@ -106,7 +106,7 @@ class NSwitchBox(QScrollArea):
|
||||
self._bumpIndex()
|
||||
return
|
||||
|
||||
def setInnerContentsMargins(self, left: int, top: int, right: int, bottom: int):
|
||||
def setInnerContentsMargins(self, left: int, top: int, right: int, bottom: int) -> None:
|
||||
"""Set the contents margins of the inner layout."""
|
||||
self._content.setContentsMargins(left, top, right, bottom)
|
||||
return
|
||||
@@ -115,12 +115,12 @@ class NSwitchBox(QScrollArea):
|
||||
# Internal Functions
|
||||
##
|
||||
|
||||
def _emitSwitchSignal(self, identifier: str, state: bool):
|
||||
def _emitSwitchSignal(self, identifier: str, state: bool) -> None:
|
||||
"""Emit a signal for a switch toggle."""
|
||||
self.switchToggled.emit(identifier, state)
|
||||
return
|
||||
|
||||
def _bumpIndex(self):
|
||||
def _bumpIndex(self) -> None:
|
||||
"""Increase the index counter and make sure only the last
|
||||
columns is stretching.
|
||||
"""
|
||||
|
||||
@@ -366,14 +366,6 @@ def testBaseConfig_Internal(monkeypatch, fncPath):
|
||||
# Function _packList
|
||||
assert tstConf._packList(["A", 1, 2.0, None, False]) == "A, 1, 2.0, None, False"
|
||||
|
||||
# Function _checkNone
|
||||
assert tstConf._checkNone(None) is None
|
||||
assert tstConf._checkNone("None") is None
|
||||
assert tstConf._checkNone("none") is None
|
||||
assert tstConf._checkNone("NONE") is None
|
||||
assert tstConf._checkNone("NoNe") is None
|
||||
assert tstConf._checkNone(123456) == 123456
|
||||
|
||||
# Function _checkOptionalPackages
|
||||
# (Assumes enchant package exists and is importable)
|
||||
tstConf._checkOptionalPackages()
|
||||
|
||||
Reference in New Issue
Block a user