diff --git a/nw/additions/__init__.py b/nw/additions/__init__.py
new file mode 100644
index 00000000..213df1b1
--- /dev/null
+++ b/nw/additions/__init__.py
@@ -0,0 +1,8 @@
+# -*- coding: utf-8 -*-
+from nw.additions.qconfiglayout import QConfigLayout
+from nw.additions.qswitch import QSwitch
+
+__all__ = [
+ "QConfigLayout",
+ "QSwitch",
+]
diff --git a/nw/additions/qconfiglayout.py b/nw/additions/qconfiglayout.py
new file mode 100644
index 00000000..7f706559
--- /dev/null
+++ b/nw/additions/qconfiglayout.py
@@ -0,0 +1,178 @@
+# -*- coding: utf-8 -*-
+"""novelWriter Addition QConfigLayout
+
+ novelWriter – Addition QConfigLayout
+======================================
+ A custom Qt grid layout for config forms similar to QFormLayout
+
+ File History:
+ Created: 2020-05-03 [0.4.5]
+
+ This file is a part of novelWriter
+ Copyright 2020, Veronica Berglyd Olsen
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see https://www.gnu.org/licenses/.
+"""
+
+import logging
+import nw
+
+from PyQt5.QtCore import Qt
+from PyQt5.QtGui import QColor, QPalette
+from PyQt5.QtWidgets import (
+ QGridLayout, QLabel, QWidget, QVBoxLayout, QHBoxLayout
+)
+
+from nw.constants import nwUnicode
+
+logger = logging.getLogger(__name__)
+
+class QConfigLayout(QGridLayout):
+
+ def __init__(self):
+ super().__init__()
+
+ self._nextRow = 0
+ self._helpCol = QColor(0, 0, 0)
+ self._fontScale = 0.9
+
+ self._itemMap = {}
+
+ self.setHorizontalSpacing(8)
+ self.setVerticalSpacing(8)
+
+ return
+
+ ##
+ # Getters and Setters
+ ##
+
+ def setHelpTextStyle(self, helpCol, fontScale=0.9):
+ """Set the text color for the help text.
+ """
+ if isinstance(helpCol, QColor):
+ self._helpCol = helpCol
+ else:
+ self._helpCol = QColor(*helpCol)
+ self._fontScale = fontScale
+ return
+
+ def setHelpText(self, intRow, theText):
+ if intRow in self._itemMap:
+ self._itemMap[intRow]["help"].setText(theText)
+ return
+
+ def setLabelText(self, intRow, theText):
+ if intRow in self._itemMap:
+ self._itemMap[intRow]["label"].setText(theText)
+ return
+
+ ##
+ # Class Methods
+ ##
+
+ def addGroupLabel(self, theLabel):
+ """Adds a text label to separate groups of settings.
+ """
+
+ if isinstance(theLabel, QLabel):
+ qLabel = theLabel
+ elif isinstance(theLabel, str):
+ qLabel = QLabel("%s" % theLabel)
+ else:
+ qLabel = None
+ raise ValueError("theLabel must be a QLabel")
+
+ qLabel.setContentsMargins(0,4,0,4)
+ self.addWidget(qLabel, self._nextRow, 0, 1, 2, Qt.AlignLeft)
+
+ self.setRowStretch(self._nextRow, 0)
+ self.setRowStretch(self._nextRow+1, 1)
+
+ self._nextRow += 1
+
+ return
+
+ def addRow(self, theLabel, theWidget, helpText=None, theUnit=None):
+ """Add a label and a widget as a new row of the grid.
+ """
+
+ thisEntry = {
+ "label" : None,
+ "help" : None,
+ "widget" : None,
+ }
+
+ if isinstance(theLabel, QLabel):
+ qLabel = theLabel
+ elif isinstance(theLabel, str):
+ qLabel = QLabel(theLabel)
+ else:
+ qLabel = None
+ raise ValueError("theLabel must be a QLabel")
+
+ if isinstance(theWidget, QWidget):
+ qWidget = theWidget
+ else:
+ qWidget = None
+ raise ValueError("theWidget must be a QWidget")
+
+ qLabel.setIndent(8)
+ if helpText is not None:
+ qHelp = QLabel(str(helpText))
+ qHelp.setIndent(8)
+
+ lblCol = qHelp.palette()
+ lblCol.setColor(QPalette.WindowText, self._helpCol)
+ qHelp.setPalette(lblCol)
+
+ lblFont = qHelp.font()
+ lblFont.setPointSizeF(self._fontScale*lblFont.pointSizeF())
+ qHelp.setFont(lblFont)
+
+ labelBox = QVBoxLayout()
+ labelBox.addWidget(qLabel)
+ labelBox.addWidget(qHelp)
+ labelBox.setSpacing(0)
+
+ thisEntry["help"] = qHelp
+ self.addLayout(labelBox, self._nextRow, 0, Qt.AlignLeft)
+
+ else:
+ self.addWidget(qLabel, self._nextRow, 0, Qt.AlignLeft)
+
+ if theUnit is not None:
+ controlBox = QHBoxLayout()
+ controlBox.addWidget(qWidget, 0, Qt.AlignVCenter)
+ controlBox.addWidget(QLabel(theUnit), 0, Qt.AlignVCenter)
+ controlBox.setSpacing(8)
+ self.addLayout(controlBox, self._nextRow, 1, Qt.AlignRight)
+ else:
+ self.addWidget(qWidget, self._nextRow, 1, Qt.AlignRight)
+
+ qLabel.setBuddy(qWidget)
+
+ self.setRowStretch(self._nextRow, 0)
+ self.setRowStretch(self._nextRow+1, 1)
+
+ thisEntry["label"] = qLabel
+ thisEntry["widget"] = qWidget
+
+ self._itemMap[self._nextRow] = thisEntry
+
+ self._nextRow += 1
+
+ return self._nextRow - 1
+
+# END Class QConfigLayout
diff --git a/nw/additions/qswitch.py b/nw/additions/qswitch.py
new file mode 100644
index 00000000..f5db98ff
--- /dev/null
+++ b/nw/additions/qswitch.py
@@ -0,0 +1,241 @@
+# -*- coding: utf-8 -*-
+"""novelWriter Addition QSwitch
+
+ novelWriter – Addition QSwitch
+================================
+ A custom Qt switch button
+
+ File History:
+ Created: 2020-05-03 [0.4.5]
+
+ This class is based on Stack Overflow code by Stefan Scherfke, based
+ again on contribution by IMAN4K, published under license CC BY-SA 4.0.
+ https://stackoverflow.com/a/51825815/5825851
+
+ The above code has been modified to integrate with novelWriter, and
+ re-released under compatible GPLv3 (see creativecommons.org).
+
+ This file is a part of novelWriter
+ Copyright 2020, Veronica Berglyd Olsen
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see https://www.gnu.org/licenses/.
+"""
+
+import logging
+import nw
+
+from PyQt5.QtCore import Qt, QSize, QRectF, QPropertyAnimation, pyqtProperty
+from PyQt5.QtWidgets import QAbstractButton, QSizePolicy
+from PyQt5.QtGui import QPainter
+
+from nw.constants import nwUnicode
+
+logger = logging.getLogger(__name__)
+
+class QSwitch(QAbstractButton):
+
+ def __init__(self, parent=None):
+ super().__init__(parent=parent)
+
+ self.setCheckable(True)
+ self.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
+
+ self._trackRadius = 10
+ self._thumbRadius = 8
+
+ self._margin = max(0, self._thumbRadius - self._trackRadius)
+ self._baseOffset = max(self._thumbRadius, self._trackRadius)
+ self._endOffset = {
+ True: lambda: self.width() - self._baseOffset,
+ False: lambda: self._baseOffset,
+ }
+ self._offset = self._baseOffset
+
+ palette = self.palette()
+ if self._thumbRadius > self._trackRadius:
+ self._trackColor = {
+ True: palette.highlight(),
+ False: palette.dark(),
+ }
+ self._thumbColor = {
+ True: palette.highlight(),
+ False: palette.light(),
+ }
+ self._textColor = {
+ True: palette.highlightedText().color(),
+ False: palette.dark().color(),
+ }
+ self._thumbText = {
+ True: '',
+ False: '',
+ }
+ self._trackOpacity = 0.5
+ else:
+ self._thumbColor = {
+ True: palette.highlightedText(),
+ False: palette.light(),
+ }
+ self._trackColor = {
+ True: palette.highlight(),
+ False: palette.dark(),
+ }
+ self._textColor = {
+ True: palette.highlight().color(),
+ False: palette.dark().color(),
+ }
+ self._thumbText = {
+ True: nwUnicode.U_CHECK,
+ False: nwUnicode.U_MULT,
+ }
+ self._trackOpacity = 1.0
+
+ return
+
+ ##
+ # Properties
+ ##
+
+ @pyqtProperty(int)
+ def offset(self):
+ return self._offset
+
+ @offset.setter
+ def offset(self, value):
+ self._offset = value
+ self.update()
+ return
+
+ ##
+ # Getters and Setters
+ ##
+
+ def trackRadius(self):
+ return self._trackRadius
+
+ def setTrackRadius(self, theValue):
+ if isinstance(theValue, int):
+ if theValue > 0:
+ self._trackRadius = theValue
+ return
+ raise ValueError("trackRadius must be an integer > 0")
+ self.update()
+ return
+
+ def thumbRadius(self):
+ return self._thumbRadius
+
+ def setThumbRadius(self, theValue):
+ if isinstance(theValue, int):
+ if theValue > 0:
+ self._thumbRadius = theValue
+ return
+ raise ValueError("thumbRadius must be an integer > 0")
+ self.update()
+ return
+
+ def setChecked(self, checked):
+ super().setChecked(checked)
+ self.offset = self._endOffset[checked]()
+
+ def sizeHint(self):
+ return QSize(
+ 4 * self._trackRadius + 2 * self._margin,
+ 2 * self._trackRadius + 2 * self._margin,
+ )
+
+ ##
+ # Events
+ ##
+
+ def resizeEvent(self, event):
+ """Overload resize to ensure correct offset.
+ """
+ super().resizeEvent(event)
+ self.offset = self._endOffset[self.isChecked()]()
+ return
+
+ def paintEvent(self, event):
+ """Drawing the switch itself.
+ """
+ qPaint = QPainter(self)
+ qPaint.setRenderHint(QPainter.Antialiasing, True)
+ qPaint.setPen(Qt.NoPen)
+ trackOpacity = self._trackOpacity
+ thumbOpacity = 1.0
+ textOpacity = 1.0
+ if self.isEnabled():
+ trackBrush = self._trackColor[self.isChecked()]
+ thumbBrush = self._thumbColor[self.isChecked()]
+ textColor = self._textColor[self.isChecked()]
+ else:
+ trackOpacity *= 0.8
+ trackBrush = self.palette().shadow()
+ thumbBrush = self.palette().mid()
+ textColor = self.palette().shadow().color()
+
+ qPaint.setBrush(trackBrush)
+ qPaint.setOpacity(trackOpacity)
+ qPaint.drawRoundedRect(
+ self._margin,
+ self._margin,
+ self.width() - 2*self._margin,
+ self.height() - 2*self._margin,
+ self._trackRadius,
+ self._trackRadius,
+ )
+ qPaint.setBrush(thumbBrush)
+ qPaint.setOpacity(thumbOpacity)
+ qPaint.drawEllipse(
+ self.offset - self._thumbRadius,
+ self._baseOffset - self._thumbRadius,
+ 2*self._thumbRadius,
+ 2*self._thumbRadius,
+ )
+ qPaint.setPen(textColor)
+ qPaint.setOpacity(textOpacity)
+ theFont = qPaint.font()
+ theFont.setPixelSize(1.5*self._thumbRadius)
+ qPaint.setFont(theFont)
+ qPaint.drawText(
+ QRectF(
+ self.offset - self._thumbRadius,
+ self._baseOffset - self._thumbRadius,
+ 2*self._thumbRadius,
+ 2*self._thumbRadius,
+ ),
+ Qt.AlignCenter,
+ self._thumbText[self.isChecked()],
+ )
+ return
+
+ def mouseReleaseEvent(self, event):
+ """Animate the switch.
+ """
+ super().mouseReleaseEvent(event)
+ if event.button() == Qt.LeftButton:
+ doAnim = QPropertyAnimation(self, b'offset', self)
+ doAnim.setDuration(120)
+ doAnim.setStartValue(self.offset)
+ doAnim.setEndValue(self._endOffset[self.isChecked()]())
+ doAnim.start()
+ return
+
+ def enterEvent(self, event):
+ """Change the cursor when hovering the button.
+ """
+ self.setCursor(Qt.PointingHandCursor)
+ super().enterEvent(event)
+ return
+
+# END Class QSwitch
diff --git a/nw/constants/constants.py b/nw/constants/constants.py
index 3f6192d4..fe327525 100644
--- a/nw/constants/constants.py
+++ b/nw/constants/constants.py
@@ -233,6 +233,8 @@ class nwUnicode:
## Other
U_NBSP = "\u00a0" # Non-breaking space
U_PARA = "\u2029" # Paragraph separator
+ U_CHECK = "\u2714" # Heavy check mark
+ U_MULT = "\u2715" # Multiplication x
## Arrows
U_UTRI = "\u2bc5" # Up-pointing triangle
@@ -270,6 +272,8 @@ class nwUnicode:
## Other
H_NBSP = " "
+ H_CHECK = "✔"
+ H_MULT = "✕"
## Arrows
H_UTRI = "⯅"
diff --git a/nw/gui/dialogs/configeditor.py b/nw/gui/dialogs/configeditor.py
index da26593f..0ffe6700 100644
--- a/nw/gui/dialogs/configeditor.py
+++ b/nw/gui/dialogs/configeditor.py
@@ -33,11 +33,12 @@ from os import path
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QFont
from PyQt5.QtWidgets import (
- QDialog, QHBoxLayout, QVBoxLayout, QLineEdit, QLabel, QWidget, QTabWidget,
- QDialogButtonBox, QSpinBox, QGroupBox, QComboBox, QMessageBox, QCheckBox,
- QGridLayout, QFontComboBox, QPushButton, QFileDialog
+ QDialog, QWidget, QHBoxLayout, QVBoxLayout, QTabWidget, QComboBox, QSpinBox,
+ QPushButton, QFontComboBox, QLineEdit, QDialogButtonBox, QMessageBox,
+ QFileDialog
)
+from nw.additions import QSwitch, QConfigLayout
from nw.tools import NWSpellCheck, NWSpellSimple, NWSpellEnchant
from nw.constants import nwAlert, nwQuotes
@@ -59,12 +60,17 @@ class GuiConfigEditor(QDialog):
self.setWindowTitle("Preferences")
self.guiDeco = self.theParent.theTheme.loadDecoration("settings",(64,64))
- self.tabMain = GuiConfigEditGeneral(self.theParent)
- self.tabEditor = GuiConfigEditEditor(self.theParent)
+ self.tabGeneral = GuiConfigEditGeneralTab(self.theParent)
+ self.tabLayout = GuiConfigEditLayoutTab(self.theParent)
+ self.tabEditing = GuiConfigEditEditingTab(self.theParent)
+ self.tabAutoRep = GuiConfigEditAutoReplaceTab(self.theParent)
self.tabWidget = QTabWidget()
- self.tabWidget.addTab(self.tabMain, "General")
- self.tabWidget.addTab(self.tabEditor, "Editor")
+ self.tabWidget.setMinimumWidth(600)
+ self.tabWidget.addTab(self.tabGeneral, "General")
+ self.tabWidget.addTab(self.tabLayout, "Layout")
+ self.tabWidget.addTab(self.tabEditing, "Editing")
+ self.tabWidget.addTab(self.tabAutoRep, "Auto-Replace")
self.setLayout(self.outerBox)
self.outerBox.addWidget(self.guiDeco, 0, Qt.AlignTop)
@@ -94,11 +100,19 @@ class GuiConfigEditor(QDialog):
validEntries = True
needsRestart = False
- retA, retB = self.tabMain.saveValues()
+ retA, retB = self.tabGeneral.saveValues()
validEntries &= retA
needsRestart |= retB
- retA, retB = self.tabEditor.saveValues()
+ retA, retB = self.tabLayout.saveValues()
+ validEntries &= retA
+ needsRestart |= retB
+
+ retA, retB = self.tabEditing.saveValues()
+ validEntries &= retA
+ needsRestart |= retB
+
+ retA, retB = self.tabAutoRep.saveValues()
validEntries &= retA
needsRestart |= retB
@@ -106,7 +120,7 @@ class GuiConfigEditor(QDialog):
msgBox = QMessageBox()
msgBox.information(
self, "Preferences",
- "Some changes will not be applied until
%s has been restarted." % nw.__package__
+ "Some changes will not be applied until
%s has been restarted" % nw.__package__
)
if validEntries:
@@ -121,7 +135,7 @@ class GuiConfigEditor(QDialog):
# END Class GuiConfigEditor
-class GuiConfigEditGeneral(QWidget):
+class GuiConfigEditGeneralTab(QWidget):
def __init__(self, theParent):
QWidget.__init__(self, theParent)
@@ -129,143 +143,126 @@ class GuiConfigEditGeneral(QWidget):
self.mainConf = nw.CONFIG
self.theParent = theParent
self.theTheme = theParent.theTheme
- self.outerBox = QGridLayout()
- # User Interface
- self.guiLook = QGroupBox("User Interface", self)
- self.guiLookForm = QGridLayout(self)
- self.guiLook.setLayout(self.guiLookForm)
+ # The Form
+ self.mainForm = QConfigLayout()
+ self.mainForm.setHelpTextStyle(self.theTheme.helpText)
+ self.setLayout(self.mainForm)
- self.guiLookTheme = QComboBox()
- self.guiLookTheme.setMinimumWidth(200)
+ # Look and Feel
+ # =============
+ self.mainForm.addGroupLabel("Look and Feel")
+
+ ## Select Theme
+ self.selectTheme = QComboBox()
+ self.selectTheme.setMinimumWidth(200)
self.theThemes = self.theTheme.listThemes()
for themeDir, themeName in self.theThemes:
- self.guiLookTheme.addItem(themeName, themeDir)
- themeIdx = self.guiLookTheme.findData(self.mainConf.guiTheme)
+ self.selectTheme.addItem(themeName, themeDir)
+ themeIdx = self.selectTheme.findData(self.mainConf.guiTheme)
if themeIdx != -1:
- self.guiLookTheme.setCurrentIndex(themeIdx)
+ self.selectTheme.setCurrentIndex(themeIdx)
- self.guiLookSyntax = QComboBox()
- self.guiLookSyntax.setMinimumWidth(200)
+ self.mainForm.addRow(
+ "Main GUI theme",
+ self.selectTheme,
+ "Changing this requires restarting %s" % nw.__package__
+ )
+
+ ## Syntax Highlighting
+ self.selectSyntax = QComboBox()
+ self.selectSyntax.setMinimumWidth(200)
self.theSyntaxes = self.theTheme.listSyntax()
for syntaxFile, syntaxName in self.theSyntaxes:
- self.guiLookSyntax.addItem(syntaxName, syntaxFile)
- syntaxIdx = self.guiLookSyntax.findData(self.mainConf.guiSyntax)
+ self.selectSyntax.addItem(syntaxName, syntaxFile)
+ syntaxIdx = self.selectSyntax.findData(self.mainConf.guiSyntax)
if syntaxIdx != -1:
- self.guiLookSyntax.setCurrentIndex(syntaxIdx)
+ self.selectSyntax.setCurrentIndex(syntaxIdx)
- self.guiDarkIcons = QCheckBox("Prefer icons for dark backgrounds", self)
- self.guiDarkIcons.setToolTip("This may improve the look of icons if the system theme is dark.")
- self.guiDarkIcons.setChecked(self.mainConf.guiDark)
+ self.mainForm.addRow(
+ "Syntax highlight theme",
+ self.selectSyntax
+ )
- 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)
- self.guiLookForm.addWidget(self.guiDarkIcons, 2, 0, 1, 2)
- self.guiLookForm.setColumnStretch(3, 1)
+ ## Dark Icons
+ self.preferDarkIcons = QSwitch()
+ self.preferDarkIcons.setChecked(self.mainConf.guiDark)
+ self.mainForm.addRow(
+ "Prefer icons for dark backgrounds",
+ self.preferDarkIcons,
+ "May improve the look of icons on dark themes"
+ )
- # Spell Checking
- self.spellLang = QGroupBox("Spell Checker", self)
- self.spellLangForm = QGridLayout(self)
- self.spellLang.setLayout(self.spellLangForm)
+ # GUI Settings
+ # ============
+ self.mainForm.addGroupLabel("GUI Settings")
- self.spellLangList = QComboBox(self)
- self.spellToolList = QComboBox(self)
- self.spellToolList.addItem("Internal (difflib)", NWSpellCheck.SP_INTERNAL)
- self.spellToolList.addItem("Spell Enchant (pyenchant)", NWSpellCheck.SP_ENCHANT)
- self.spellToolList.addItem("SymSpell (symspellpy)", NWSpellCheck.SP_SYMSPELL)
+ self.showFullPath = QSwitch()
+ self.showFullPath.setChecked(self.mainConf.showFullPath)
+ self.mainForm.addRow(
+ "Show full path in document header",
+ self.showFullPath
+ )
- theModel = self.spellToolList.model()
- idEnchant = self.spellToolList.findData(NWSpellCheck.SP_ENCHANT)
- idSymSpell = self.spellToolList.findData(NWSpellCheck.SP_SYMSPELL)
- theModel.item(idEnchant).setEnabled(self.mainConf.hasEnchant)
- theModel.item(idSymSpell).setEnabled(self.mainConf.hasSymSpell)
-
- self.spellToolList.currentIndexChanged.connect(self._doUpdateSpellTool)
- toolIdx = self.spellToolList.findData(self.mainConf.spellTool)
- if toolIdx != -1:
- self.spellToolList.setCurrentIndex(toolIdx)
- self._doUpdateSpellTool(0)
-
- self.spellBigDoc = QSpinBox(self)
- self.spellBigDoc.setMinimum(10)
- self.spellBigDoc.setMaximum(10000)
- self.spellBigDoc.setSingleStep(10)
- self.spellBigDoc.setToolTip((
- "Disable spell checking when loading large documents. "
- "Spell checking will only run on paragraphs you edit."
- ))
- self.spellBigDoc.setValue(self.mainConf.bigDocLimit)
-
- self.spellLangForm.addWidget(QLabel("Provider"), 0, 0)
- self.spellLangForm.addWidget(self.spellToolList, 0, 1, 1, 3)
- self.spellLangForm.addWidget(QLabel("Language"), 1, 0)
- self.spellLangForm.addWidget(self.spellLangList, 1, 1, 1, 3)
- self.spellLangForm.addWidget(QLabel("Size limit"), 2, 0)
- self.spellLangForm.addWidget(self.spellBigDoc, 2, 1)
- self.spellLangForm.addWidget(QLabel("kb"), 2, 2)
- self.spellLangForm.setColumnStretch(4, 1)
-
- # AutoSave
- self.autoSave = QGroupBox("Automatic Save", self)
- self.autoSaveForm = QGridLayout(self)
- self.autoSave.setLayout(self.autoSaveForm)
+ # AutoSave Settings
+ # =================
+ self.mainForm.addGroupLabel("Automatic Save")
+ ## Document Save Timer
self.autoSaveDoc = QSpinBox(self)
self.autoSaveDoc.setMinimum(5)
self.autoSaveDoc.setMaximum(600)
self.autoSaveDoc.setSingleStep(1)
self.autoSaveDoc.setValue(self.mainConf.autoSaveDoc)
+ self.backupPathRow = self.mainForm.addRow(
+ "Save interval for the currently open document",
+ self.autoSaveDoc,
+ theUnit="seconds"
+ )
+ ## Project Save Timer
self.autoSaveProj = QSpinBox(self)
self.autoSaveProj.setMinimum(5)
self.autoSaveProj.setMaximum(600)
self.autoSaveProj.setSingleStep(1)
self.autoSaveProj.setValue(self.mainConf.autoSaveProj)
+ self.backupPathRow = self.mainForm.addRow(
+ "Save interval for the currently open project",
+ self.autoSaveProj,
+ theUnit="seconds"
+ )
- self.autoSaveForm.addWidget(QLabel("Document"), 0, 0)
- self.autoSaveForm.addWidget(self.autoSaveDoc, 0, 1)
- self.autoSaveForm.addWidget(QLabel("seconds"), 0, 2)
- self.autoSaveForm.addWidget(QLabel("Project"), 1, 0)
- self.autoSaveForm.addWidget(self.autoSaveProj, 1, 1)
- self.autoSaveForm.addWidget(QLabel("seconds"), 1, 2)
- self.autoSaveForm.setColumnStretch(3, 1)
+ # Backup Settings
+ # ===============
+ self.mainForm.addGroupLabel("Project Backup")
- # Backup
- self.projBackup = QGroupBox("Backup Folder", self)
- self.projBackupForm = QGridLayout(self)
- self.projBackup.setLayout(self.projBackupForm)
+ ## Backup Path
+ self.backupPath = self.mainConf.backupPath
+ self.backupGetPath = QPushButton(self.theTheme.getIcon("folder"),"Select Folder")
+ self.backupGetPath.clicked.connect(self._backupFolder)
+ self.backupPathRow = self.mainForm.addRow(
+ "Backup storage location",
+ self.backupGetPath,
+ "Path: %s" % self.backupPath
+ )
- self.projBackupPath = QLineEdit()
- if path.isdir(self.mainConf.backupPath):
- self.projBackupPath.setText(self.mainConf.backupPath)
+ ## Run when closing
+ self.backupOnClose = QSwitch()
+ self.backupOnClose.setChecked(self.mainConf.backupOnClose)
+ self.backupOnClose.toggled.connect(self._toggledBackupOnClose)
+ self.mainForm.addRow(
+ "Run backup when closing project",
+ self.backupOnClose,
+ "This option can be overridden in project settings"
+ )
- self.projBackupGetPath = QPushButton(self.theTheme.getIcon("folder"),"")
- self.projBackupGetPath.clicked.connect(self._backupFolder)
-
- self.projBackupClose = QCheckBox("Run on close",self)
- self.projBackupClose.setToolTip("Backup automatically on project close.")
- self.projBackupClose.setChecked(self.mainConf.backupOnClose)
-
- self.projBackupAsk = QCheckBox("Ask before backup",self)
- self.projBackupAsk.setToolTip("Ask before backup.")
- self.projBackupAsk.setChecked(self.mainConf.askBeforeBackup)
-
- self.projBackupForm.addWidget(self.projBackupPath, 0, 0, 1, 2)
- self.projBackupForm.addWidget(self.projBackupGetPath, 0, 2)
- self.projBackupForm.addWidget(self.projBackupClose, 1, 0)
- self.projBackupForm.addWidget(self.projBackupAsk, 1, 1, 1, 2)
- self.projBackupForm.setColumnStretch(1, 1)
-
- # Assemble
- self.outerBox.addWidget(self.guiLook, 0, 0)
- self.outerBox.addWidget(self.spellLang, 1, 0)
- self.outerBox.addWidget(self.autoSave, 2, 0)
- self.outerBox.addWidget(self.projBackup, 3, 0, 1, 2)
- self.outerBox.setColumnStretch(1, 1)
- self.outerBox.setRowStretch(4, 1)
- self.setLayout(self.outerBox)
+ ## Ask before backup
+ self.askBeforeBackup = QSwitch()
+ self.askBeforeBackup.setChecked(self.mainConf.askBeforeBackup)
+ self.mainForm.addRow(
+ "Ask before running backup",
+ self.askBeforeBackup
+ )
return
@@ -274,17 +271,15 @@ class GuiConfigEditGeneral(QWidget):
validEntries = True
needsRestart = False
- guiTheme = self.guiLookTheme.currentData()
- guiSyntax = self.guiLookSyntax.currentData()
- guiDark = self.guiDarkIcons.isChecked()
- spellTool = self.spellToolList.currentData()
- spellLanguage = self.spellLangList.currentData()
- bigDocLimit = self.spellBigDoc.value()
+ guiTheme = self.selectTheme.currentData()
+ guiSyntax = self.selectSyntax.currentData()
+ guiDark = self.preferDarkIcons.isChecked()
+ showFullPath = self.showFullPath.isChecked()
autoSaveDoc = self.autoSaveDoc.value()
autoSaveProj = self.autoSaveProj.value()
- backupPath = self.projBackupPath.text()
- backupOnClose = self.projBackupClose.isChecked()
- askBeforeBackup = self.projBackupAsk.isChecked()
+ backupPath = self.backupPath
+ backupOnClose = self.backupOnClose.isChecked()
+ askBeforeBackup = self.askBeforeBackup.isChecked()
# Check if restart is needed
needsRestart |= self.mainConf.guiTheme != guiTheme
@@ -292,9 +287,7 @@ class GuiConfigEditGeneral(QWidget):
self.mainConf.guiTheme = guiTheme
self.mainConf.guiSyntax = guiSyntax
self.mainConf.guiDark = guiDark
- self.mainConf.spellTool = spellTool
- self.mainConf.spellLanguage = spellLanguage
- self.mainConf.bigDocLimit = bigDocLimit
+ self.mainConf.showFullPath = showFullPath
self.mainConf.autoSaveDoc = autoSaveDoc
self.mainConf.autoSaveProj = autoSaveProj
self.mainConf.backupPath = backupPath
@@ -306,12 +299,12 @@ class GuiConfigEditGeneral(QWidget):
return validEntries, needsRestart
##
- # Internal Functions
+ # Slots
##
def _backupFolder(self):
- currDir = self.projBackupPath.text()
+ currDir = self.backupPath
if not path.isdir(currDir):
currDir = ""
@@ -322,11 +315,270 @@ class GuiConfigEditGeneral(QWidget):
self,"Backup Directory",currDir,options=dlgOpt
)
if newDir:
- self.projBackupPath.setText(newDir)
+ self.backupPath = newDir
+ self.mainForm.setHelpText(self.backupPathRow, "Path: %s" % self.backupPath)
return True
return False
+ def _toggledBackupOnClose(self, theState):
+ """Enable or disable switch that depends on the backup on close
+ switch,
+ """
+ self.askBeforeBackup.setEnabled(theState)
+ return
+
+# END Class GuiConfigEditGeneralTab
+
+class GuiConfigEditLayoutTab(QWidget):
+
+ def __init__(self, theParent):
+ QWidget.__init__(self, theParent)
+
+ self.mainConf = nw.CONFIG
+ self.theParent = theParent
+ self.theTheme = theParent.theTheme
+
+ # The Form
+ self.mainForm = QConfigLayout()
+ self.mainForm.setHelpTextStyle(self.theTheme.helpText)
+ self.setLayout(self.mainForm)
+
+ # Text Style
+ # ==========
+ self.mainForm.addGroupLabel("Text Style")
+
+ ## Font Family
+ self.textStyleFont = QFontComboBox()
+ self.textStyleFont.setMaximumWidth(200)
+ self.textStyleFont.setCurrentFont(QFont(self.mainConf.textFont))
+ self.mainForm.addRow(
+ "Font family",
+ self.textStyleFont,
+ "For the document editor and viewer"
+ )
+
+ ## Font Size
+ self.textStyleSize = QSpinBox(self)
+ self.textStyleSize.setMinimum(5)
+ self.textStyleSize.setMaximum(120)
+ self.textStyleSize.setSingleStep(1)
+ self.textStyleSize.setValue(self.mainConf.textSize)
+ self.mainForm.addRow(
+ "Font size",
+ self.textStyleSize,
+ theUnit="pt"
+ )
+
+ # Text Flow
+ # =========
+ self.mainForm.addGroupLabel("Text Flow")
+
+ ## Max Text Width in Normal Mode
+ self.textFlowMax = QSpinBox(self)
+ self.textFlowMax.setMinimum(300)
+ self.textFlowMax.setMaximum(10000)
+ self.textFlowMax.setSingleStep(10)
+ self.textFlowMax.setValue(self.mainConf.textWidth)
+ self.mainForm.addRow(
+ "Maximum text width in Normal mode",
+ self.textFlowMax,
+ theUnit="px"
+ )
+
+ ## Max Text Width in Zen Mode
+ self.zenDocWidth = QSpinBox(self)
+ self.zenDocWidth.setMinimum(300)
+ self.zenDocWidth.setMaximum(10000)
+ self.zenDocWidth.setSingleStep(10)
+ self.zenDocWidth.setValue(self.mainConf.zenWidth)
+ self.mainForm.addRow(
+ "Maximum text width in Zen mode",
+ self.zenDocWidth,
+ theUnit="px"
+ )
+
+ ## Document Fixed Width
+ self.textFlowFixed = QSwitch()
+ self.textFlowFixed.setChecked(not self.mainConf.textFixedW)
+ self.mainForm.addRow(
+ "Disable maximum text width in Normal mode",
+ self.textFlowFixed,
+ "Only fixed margins are applied to the document"
+ )
+
+ ## Justify Text
+ self.textJustify = QSwitch()
+ self.textJustify.setChecked(self.mainConf.textFixedW)
+ self.mainForm.addRow(
+ "Justify the text margins in editor and viewer",
+ self.textJustify
+ )
+
+ ## Document Margins
+ self.textMargin = QSpinBox(self)
+ self.textMargin.setMinimum(0)
+ self.textMargin.setMaximum(900)
+ self.textMargin.setSingleStep(1)
+ self.textMargin.setValue(self.mainConf.textMargin)
+ self.mainForm.addRow(
+ "Document text margin",
+ self.textMargin,
+ "The minimum horizontal text margin if max with is enabled",
+ theUnit="px"
+ )
+
+ ## Tab Width
+ self.tabWidth = QSpinBox(self)
+ self.tabWidth.setMinimum(0)
+ self.tabWidth.setMaximum(200)
+ self.tabWidth.setSingleStep(1)
+ self.tabWidth.setValue(self.mainConf.tabWidth)
+ self.mainForm.addRow(
+ "Editor tab width",
+ self.tabWidth,
+ "This feature requires Qt 5.9 or later",
+ theUnit="px"
+ )
+
+ # Writing Guides
+ # ==============
+ self.mainForm.addGroupLabel("Writing Guides")
+
+ ## Show Tabs and Spaces
+ self.showTabsNSpaces = QSwitch()
+ self.showTabsNSpaces.setChecked(self.mainConf.showTabsNSpaces)
+ self.mainForm.addRow(
+ "Show tabs and spaces",
+ self.showTabsNSpaces
+ )
+
+ ## Show Line Endings
+ self.showLineEndings = QSwitch()
+ self.showLineEndings.setChecked(self.mainConf.showLineEndings)
+ self.mainForm.addRow(
+ "Show line endings",
+ self.showLineEndings
+ )
+
+ return
+
+ def saveValues(self):
+
+ validEntries = True
+ needsRestart = False
+
+ textFont = self.textStyleFont.currentFont().family()
+ textSize = self.textStyleSize.value()
+ textWidth = self.textFlowMax.value()
+ zenWidth = self.zenDocWidth.value()
+ textFixedW = not self.textFlowFixed.isChecked()
+ doJustify = self.textJustify.isChecked()
+ textMargin = self.textMargin.value()
+ tabWidth = self.tabWidth.value()
+ showTabsNSpaces = self.showTabsNSpaces.isChecked()
+ showLineEndings = self.showLineEndings.isChecked()
+
+ self.mainConf.textFont = textFont
+ self.mainConf.textSize = textSize
+ self.mainConf.textWidth = textWidth
+ self.mainConf.zenWidth = zenWidth
+ self.mainConf.textFixedW = textFixedW
+ self.mainConf.doJustify = doJustify
+ self.mainConf.textMargin = textMargin
+ self.mainConf.tabWidth = tabWidth
+ self.mainConf.showTabsNSpaces = showTabsNSpaces
+ self.mainConf.showLineEndings = showLineEndings
+
+ self.mainConf.confChanged = True
+
+ return validEntries, needsRestart
+
+# END Class GuiConfigEditLayoutTab
+
+class GuiConfigEditEditingTab(QWidget):
+
+ def __init__(self, theParent):
+ QWidget.__init__(self, theParent)
+
+ self.mainConf = nw.CONFIG
+ self.theParent = theParent
+ self.theTheme = theParent.theTheme
+
+ # The Form
+ self.mainForm = QConfigLayout()
+ self.mainForm.setHelpTextStyle(self.theTheme.helpText)
+ self.setLayout(self.mainForm)
+
+ # Spell Checking
+ # ==============
+ self.mainForm.addGroupLabel("Spell Checking")
+
+ ## Spell Check Provider and Language
+ self.spellLangList = QComboBox(self)
+ self.spellToolList = QComboBox(self)
+ self.spellToolList.addItem("Internal (difflib)", NWSpellCheck.SP_INTERNAL)
+ self.spellToolList.addItem("Spell Enchant (pyenchant)", NWSpellCheck.SP_ENCHANT)
+ # self.spellToolList.addItem("SymSpell (symspellpy)", NWSpellCheck.SP_SYMSPELL)
+
+ theModel = self.spellToolList.model()
+ idEnchant = self.spellToolList.findData(NWSpellCheck.SP_ENCHANT)
+ # idSymSpell = self.spellToolList.findData(NWSpellCheck.SP_SYMSPELL)
+ theModel.item(idEnchant).setEnabled(self.mainConf.hasEnchant)
+ # theModel.item(idSymSpell).setEnabled(self.mainConf.hasSymSpell)
+
+ self.spellToolList.currentIndexChanged.connect(self._doUpdateSpellTool)
+ toolIdx = self.spellToolList.findData(self.mainConf.spellTool)
+ if toolIdx != -1:
+ self.spellToolList.setCurrentIndex(toolIdx)
+ self._doUpdateSpellTool(0)
+
+ self.mainForm.addRow(
+ "Spell check provider",
+ self.spellToolList,
+ "Note that the internal spell check tool is quite slow"
+ )
+ self.mainForm.addRow(
+ "Spell check language",
+ self.spellLangList
+ )
+
+ ## Big Document Size Limit
+ self.bigDocLimit = QSpinBox(self)
+ self.bigDocLimit.setMinimum(10)
+ self.bigDocLimit.setMaximum(10000)
+ self.bigDocLimit.setSingleStep(10)
+ self.bigDocLimit.setValue(self.mainConf.bigDocLimit)
+ self.mainForm.addRow(
+ "Big document limit",
+ self.bigDocLimit,
+ "Disables full spell checking over the size limit",
+ theUnit="kb"
+ )
+
+ return
+
+ def saveValues(self):
+
+ validEntries = True
+ needsRestart = False
+
+ spellTool = self.spellToolList.currentData()
+ spellLanguage = self.spellLangList.currentData()
+ bigDocLimit = self.bigDocLimit.value()
+
+ self.mainConf.spellTool = spellTool
+ self.mainConf.spellLanguage = spellLanguage
+ self.mainConf.bigDocLimit = bigDocLimit
+
+ self.mainConf.confChanged = True
+
+ return validEntries, needsRestart
+
+ ##
+ # Internal Functions
+ ##
+
def _disableComboItem(self, theList, theValue):
theIdx = theList.findData(theValue)
theModel = theList.model()
@@ -360,218 +612,134 @@ class GuiConfigEditGeneral(QWidget):
return
-# END Class GuiConfigEditGeneral
+# END Class GuiConfigEditEditingTab
-class GuiConfigEditEditor(QWidget):
+class GuiConfigEditAutoReplaceTab(QWidget):
def __init__(self, theParent):
QWidget.__init__(self, theParent)
self.mainConf = nw.CONFIG
self.theParent = theParent
- self.outerBox = QGridLayout()
+ self.theTheme = theParent.theTheme
- # Text Style
- self.textStyle = QGroupBox("Text Style", self)
- self.textStyleForm = QGridLayout(self)
- self.textStyle.setLayout(self.textStyleForm)
-
- self.textStyleFont = QFontComboBox()
- self.textStyleFont.setMaximumWidth(250)
- self.textStyleFont.setCurrentFont(QFont(self.mainConf.textFont))
-
- self.textStyleSize = QSpinBox(self)
- self.textStyleSize.setMinimum(5)
- self.textStyleSize.setMaximum(120)
- self.textStyleSize.setSingleStep(1)
- self.textStyleSize.setValue(self.mainConf.textSize)
-
- self.textStyleForm.addWidget(QLabel("Font family"), 0, 0)
- self.textStyleForm.addWidget(self.textStyleFont, 0, 1)
- self.textStyleForm.addWidget(QLabel("Size"), 0, 2)
- self.textStyleForm.addWidget(self.textStyleSize, 0, 3)
- self.textStyleForm.setColumnStretch(4, 1)
-
- # Text Flow
- self.textFlow = QGroupBox("Text Flow", self)
- self.textFlowForm = QGridLayout(self)
- self.textFlow.setLayout(self.textFlowForm)
-
- self.textFlowFixed = QCheckBox("Max text width",self)
- self.textFlowFixed.setToolTip("Maximum width of the text.")
- self.textFlowFixed.setChecked(self.mainConf.textFixedW)
-
- self.textFlowMax = QSpinBox(self)
- self.textFlowMax.setMinimum(300)
- self.textFlowMax.setMaximum(10000)
- self.textFlowMax.setSingleStep(10)
- self.textFlowMax.setValue(self.mainConf.textWidth)
-
- self.textFlowJustify = QCheckBox("Justify text",self)
- self.textFlowJustify.setToolTip("Justify text in main document editor.")
- self.textFlowJustify.setChecked(self.mainConf.doJustify)
-
- self.textFlowForm.addWidget(self.textFlowFixed, 0, 0)
- self.textFlowForm.addWidget(self.textFlowMax, 0, 1)
- self.textFlowForm.addWidget(QLabel("px"), 0, 2)
- self.textFlowForm.addWidget(self.textFlowJustify, 1, 0)
- self.textFlowForm.setColumnStretch(4, 1)
-
- # Text Margins
- self.textMargin = QGroupBox("Margins", self)
- self.textMarginForm = QGridLayout(self)
- self.textMargin.setLayout(self.textMarginForm)
-
- self.textMarginDoc = QSpinBox(self)
- self.textMarginDoc.setMinimum(0)
- self.textMarginDoc.setMaximum(2000)
- self.textMarginDoc.setSingleStep(1)
- self.textMarginDoc.setValue(self.mainConf.textMargin)
-
- self.textMarginTab = QSpinBox(self)
- self.textMarginTab.setMinimum(0)
- self.textMarginTab.setMaximum(200)
- self.textMarginTab.setSingleStep(1)
- self.textMarginTab.setValue(self.mainConf.tabWidth)
- self.textMarginTab.setToolTip("Requires Qt 5.9 or later.")
-
- self.textMarginForm.addWidget(QLabel("Document"), 0, 0)
- self.textMarginForm.addWidget(self.textMarginDoc, 0, 1)
- self.textMarginForm.addWidget(QLabel("px"), 0, 2)
- self.textMarginForm.addWidget(QLabel("Tab width"), 2, 0)
- self.textMarginForm.addWidget(self.textMarginTab, 2, 1)
- self.textMarginForm.addWidget(QLabel("px"), 2, 2)
- self.textMarginForm.setColumnStretch(4, 1)
-
- # Zen Mode
- self.zenMode = QGroupBox("Zen Mode", self)
- self.zenModeForm = QGridLayout(self)
- self.zenMode.setLayout(self.zenModeForm)
-
- self.zenDocWidth = QSpinBox(self)
- self.zenDocWidth.setMinimum(300)
- self.zenDocWidth.setMaximum(10000)
- self.zenDocWidth.setSingleStep(10)
- self.zenDocWidth.setValue(self.mainConf.zenWidth)
-
- self.zenModeForm.addWidget(QLabel("Document width"), 0, 0)
- self.zenModeForm.addWidget(self.zenDocWidth, 0, 1)
- self.zenModeForm.addWidget(QLabel("px"), 0, 2)
- self.zenModeForm.setColumnStretch(3, 1)
+ # The Form
+ self.mainForm = QConfigLayout()
+ self.mainForm.setHelpTextStyle(self.theTheme.helpText)
+ self.setLayout(self.mainForm)
# Automatic Features
- self.autoReplace = QGroupBox("Automatic Features", self)
- self.autoReplaceForm = QGridLayout(self)
- self.autoReplace.setLayout(self.autoReplaceForm)
+ # ==================
+ self.mainForm.addGroupLabel("Automatic Features")
- self.autoSelect = QCheckBox(self)
- self.autoSelect.setToolTip("Auto-select word under cursor when applying formatting.")
+ ## Auto-Select Word Under Cursor
+ self.autoSelect = QSwitch()
self.autoSelect.setChecked(self.mainConf.autoSelect)
-
- self.autoReplaceMain = QCheckBox(self)
- self.autoReplaceMain.setToolTip("Auto-replace text as you type.")
- self.autoReplaceMain.setChecked(self.mainConf.doReplace)
-
- self.autoReplaceSQ = QCheckBox(self)
- self.autoReplaceSQ.setToolTip("Auto-replace single quotes.")
- self.autoReplaceSQ.setChecked(self.mainConf.doReplaceSQuote)
-
- self.autoReplaceDQ = QCheckBox(self)
- self.autoReplaceDQ.setToolTip("Auto-replace double quotes.")
- self.autoReplaceDQ.setChecked(self.mainConf.doReplaceDQuote)
-
- self.autoReplaceDash = QCheckBox(self)
- self.autoReplaceDash.setToolTip(
- "Auto-replace double and triple hyphens with short and long dash."
+ self.mainForm.addRow(
+ "Auto-select word under cursor",
+ self.autoSelect,
+ "Apply formatting to word under cursor if no selection is made"
)
+
+ ## Auto-Replace as You Type Main Switch
+ self.autoReplaceMain = QSwitch()
+ self.autoReplaceMain.setChecked(self.mainConf.doReplace)
+ self.autoReplaceMain.toggled.connect(self._toggleAutoReplaceMain)
+ self.mainForm.addRow(
+ "Auto-replace text as you type",
+ self.autoReplaceMain,
+ "Apply formatting to word under cursor if no selection is made"
+ )
+
+ # Auto-Replace
+ # ============
+ self.mainForm.addGroupLabel("Replace as You Type")
+
+ ## Auto-Replace Single Quotes
+ self.autoReplaceSQ = QSwitch()
+ self.autoReplaceSQ.setChecked(self.mainConf.doReplaceSQuote)
+ self.mainForm.addRow(
+ "Auto-replace single quotes",
+ self.autoReplaceSQ,
+ "The feature will try to guess opening or closing single quote"
+ )
+
+ ## Auto-Replace Double Quotes
+ self.autoReplaceDQ = QSwitch()
+ self.autoReplaceDQ.setChecked(self.mainConf.doReplaceDQuote)
+ self.mainForm.addRow(
+ "Auto-replace double quotes",
+ self.autoReplaceDQ,
+ "The feature will try to guess opening or closing quote quote"
+ )
+
+ ## Auto-Replace Hyphens
+ self.autoReplaceDash = QSwitch()
self.autoReplaceDash.setChecked(self.mainConf.doReplaceDash)
+ self.mainForm.addRow(
+ "Auto-replace dashes",
+ self.autoReplaceDash,
+ "Auto-replace double and triple hyphens with short and long dash"
+ )
- self.autoReplaceDots = QCheckBox(self)
- self.autoReplaceDots.setToolTip("Auto-replace three dots with ellipsis.")
+ ## Auto-Replace Dots
+ self.autoReplaceDots = QSwitch()
self.autoReplaceDots.setChecked(self.mainConf.doReplaceDots)
+ self.mainForm.addRow(
+ "Auto-replace dots",
+ self.autoReplaceDots,
+ "Auto-replace three dots with ellipsis"
+ )
- self.autoReplaceForm.addWidget(QLabel("Auto-select text"), 0, 0)
- self.autoReplaceForm.addWidget(self.autoSelect, 0, 1)
- self.autoReplaceForm.addWidget(QLabel("Auto-replace:"), 1, 0)
- self.autoReplaceForm.addWidget(self.autoReplaceMain, 1, 1)
- self.autoReplaceForm.addWidget(QLabel("\u2192 Single quotes"), 2, 0)
- self.autoReplaceForm.addWidget(self.autoReplaceSQ, 2, 1)
- self.autoReplaceForm.addWidget(QLabel("\u2192 Double quotes"), 3, 0)
- self.autoReplaceForm.addWidget(self.autoReplaceDQ, 3, 1)
- self.autoReplaceForm.addWidget(QLabel("\u2192 Hyphens with dash"), 4, 0)
- self.autoReplaceForm.addWidget(self.autoReplaceDash, 4, 1)
- self.autoReplaceForm.addWidget(QLabel("\u2192 Dots with ellipsis"), 5, 0)
- self.autoReplaceForm.addWidget(self.autoReplaceDots, 5, 1)
- self.autoReplaceForm.setColumnStretch(2, 1)
- self.autoReplaceForm.setRowStretch(6, 1)
-
- # Quote Style
- self.quoteStyle = QGroupBox("Quotation Style", self)
- self.quoteStyleForm = QGridLayout(self)
- self.quoteStyle.setLayout(self.quoteStyleForm)
+ # Quotation Style
+ # ===============
+ self.mainForm.addGroupLabel("Quotation Style")
+ ## Single Quote Style
self.quoteSingleStyleO = QLineEdit()
self.quoteSingleStyleO.setMaxLength(1)
- self.quoteSingleStyleO.setFixedWidth(30)
+ self.quoteSingleStyleO.setFixedWidth(40)
self.quoteSingleStyleO.setAlignment(Qt.AlignCenter)
self.quoteSingleStyleO.setText(self.mainConf.fmtSingleQuotes[0])
+ self.mainForm.addRow(
+ "Single quote open style",
+ self.quoteSingleStyleO,
+ "Auto-replaces apostrophe before words"
+ )
self.quoteSingleStyleC = QLineEdit()
self.quoteSingleStyleC.setMaxLength(1)
- self.quoteSingleStyleC.setFixedWidth(30)
+ self.quoteSingleStyleC.setFixedWidth(40)
self.quoteSingleStyleC.setAlignment(Qt.AlignCenter)
self.quoteSingleStyleC.setText(self.mainConf.fmtSingleQuotes[1])
+ self.mainForm.addRow(
+ "Single quote close style",
+ self.quoteSingleStyleC,
+ "Auto-replaces apostrophe after words"
+ )
+ ## Double Quote Style
self.quoteDoubleStyleO = QLineEdit()
self.quoteDoubleStyleO.setMaxLength(1)
- self.quoteDoubleStyleO.setFixedWidth(30)
+ self.quoteDoubleStyleO.setFixedWidth(40)
self.quoteDoubleStyleO.setAlignment(Qt.AlignCenter)
self.quoteDoubleStyleO.setText(self.mainConf.fmtDoubleQuotes[0])
+ self.mainForm.addRow(
+ "Double quote open style",
+ self.quoteDoubleStyleO,
+ "Auto-replaces straight quotes before words"
+ )
self.quoteDoubleStyleC = QLineEdit()
self.quoteDoubleStyleC.setMaxLength(1)
- self.quoteDoubleStyleC.setFixedWidth(30)
+ self.quoteDoubleStyleC.setFixedWidth(40)
self.quoteDoubleStyleC.setAlignment(Qt.AlignCenter)
self.quoteDoubleStyleC.setText(self.mainConf.fmtDoubleQuotes[1])
-
- self.quoteStyleForm.addWidget(QLabel("Single Quotes"), 0, 0, 1, 3)
- self.quoteStyleForm.addWidget(QLabel("Open"), 1, 0)
- self.quoteStyleForm.addWidget(self.quoteSingleStyleO, 1, 1)
- self.quoteStyleForm.addWidget(QLabel("Close"), 1, 2)
- self.quoteStyleForm.addWidget(self.quoteSingleStyleC, 1, 3)
- self.quoteStyleForm.addWidget(QLabel("Double Quotes"), 2, 0, 1, 3)
- self.quoteStyleForm.addWidget(QLabel("Open"), 3, 0)
- self.quoteStyleForm.addWidget(self.quoteDoubleStyleO, 3, 1)
- self.quoteStyleForm.addWidget(QLabel("Close"), 3, 2)
- self.quoteStyleForm.addWidget(self.quoteDoubleStyleC, 3, 3)
- self.quoteStyleForm.setColumnStretch(4, 1)
- self.quoteStyleForm.setRowStretch(4, 1)
-
- # Writing Guides
- self.showGuides = QGroupBox("Writing Guides", self)
- self.showGuidesForm = QGridLayout(self)
- self.showGuides.setLayout(self.showGuidesForm)
-
- self.showTabsNSpaces = QCheckBox("Show tabs and spaces",self)
- self.showTabsNSpaces.setChecked(self.mainConf.showTabsNSpaces)
-
- self.showLineEndings = QCheckBox("Show line endings",self)
- self.showLineEndings.setChecked(self.mainConf.showLineEndings)
-
- self.showGuidesForm.addWidget(self.showTabsNSpaces, 0, 0)
- self.showGuidesForm.addWidget(self.showLineEndings, 1, 0)
-
- # Assemble
- self.outerBox.addWidget(self.textStyle, 0, 0, 1, 2)
- self.outerBox.addWidget(self.textFlow, 1, 0)
- self.outerBox.addWidget(self.textMargin, 1, 1)
- self.outerBox.addWidget(self.zenMode, 2, 0)
- self.outerBox.addWidget(self.autoReplace, 3, 0, 2, 1)
- self.outerBox.addWidget(self.quoteStyle, 2, 1, 2, 1)
- self.outerBox.addWidget(self.showGuides, 4, 1)
- self.outerBox.setColumnStretch(2, 1)
- self.outerBox.setRowStretch(5, 1)
- self.setLayout(self.outerBox)
+ self.mainForm.addRow(
+ "Double quote close style",
+ self.quoteDoubleStyleC,
+ "Auto-replaces straight quotes after words"
+ )
return
@@ -579,36 +747,12 @@ class GuiConfigEditEditor(QWidget):
validEntries = True
- textFont = self.textStyleFont.currentFont().family()
- textSize = self.textStyleSize.value()
-
- self.mainConf.textFont = textFont
- self.mainConf.textSize = textSize
-
- textWidth = self.textFlowMax.value()
- textFixedW = self.textFlowFixed.isChecked()
- doJustify = self.textFlowJustify.isChecked()
-
- self.mainConf.textWidth = textWidth
- self.mainConf.textFixedW = textFixedW
- self.mainConf.doJustify = doJustify
-
- zenWidth = self.zenDocWidth.value()
-
- self.mainConf.zenWidth = zenWidth
-
- textMargin = self.textMarginDoc.value()
- tabWidth = self.textMarginTab.value()
-
- self.mainConf.textMargin = textMargin
- self.mainConf.tabWidth = tabWidth
-
autoSelect = self.autoSelect.isChecked()
doReplace = self.autoReplaceMain.isChecked()
doReplaceSQuote = self.autoReplaceSQ.isChecked()
doReplaceDQuote = self.autoReplaceDQ.isChecked()
doReplaceDash = self.autoReplaceDash.isChecked()
- doReplaceDots = self.autoReplaceDash.isChecked()
+ doReplaceDots = self.autoReplaceDots.isChecked()
self.mainConf.autoSelect = autoSelect
self.mainConf.doReplace = doReplace
@@ -654,25 +798,36 @@ class GuiConfigEditEditor(QWidget):
)
validEntries = False
- showTabsNSpaces = self.showTabsNSpaces.isChecked()
- showLineEndings = self.showLineEndings.isChecked()
-
- self.mainConf.showTabsNSpaces = showTabsNSpaces
- self.mainConf.showLineEndings = showLineEndings
-
self.mainConf.confChanged = True
return validEntries, False
+ ##
+ # Slots
+ ##
+
+ def _toggleAutoReplaceMain(self, theState):
+ """Enables or disables switches controlled by the main auto
+ replace switch.
+ """
+ self.autoReplaceSQ.setEnabled(theState)
+ self.autoReplaceDQ.setEnabled(theState)
+ self.autoReplaceDash.setEnabled(theState)
+ self.autoReplaceDots.setEnabled(theState)
+ return
+
##
# Internal Functions
##
def _checkQuoteSymbol(self, toCheck):
+ """Check that the quote symbols entered are in nwQuotes and is
+ therefore a valid quote symbol for this app.
+ """
if len(toCheck) != 1:
return False
if toCheck in nwQuotes.SYMBOLS:
return True
return False
-# END Class GuiConfigEditEditor
+# END Class GuiConfigEditAutoReplaceTab
diff --git a/nw/gui/elements/doctitlebar.py b/nw/gui/elements/doctitlebar.py
index b8d5d739..7ecfc417 100644
--- a/nw/gui/elements/doctitlebar.py
+++ b/nw/gui/elements/doctitlebar.py
@@ -30,7 +30,7 @@ import nw
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QPalette, QColor
-from PyQt5.QtWidgets import QLabel, QFrame, QStyle
+from PyQt5.QtWidgets import QLabel, QFrame
from nw.constants import nwUnicode
diff --git a/nw/gui/theme.py b/nw/gui/theme.py
index 00463aac..2cdc1b2f 100644
--- a/nw/gui/theme.py
+++ b/nw/gui/theme.py
@@ -68,6 +68,7 @@ class GuiTheme:
self.statNone = [120,120,120]
self.statUnsaved = [120,120, 40]
self.statSaved = [ 40,120, 0]
+ self.helpText = [ 0, 0, 0]
# Loaded Syntax Settings
@@ -121,6 +122,8 @@ class GuiTheme:
##
def updateTheme(self):
+ """Update the GUI theme from theme files.
+ """
self.guiTheme = self.mainConf.guiTheme
self.guiSyntax = self.mainConf.guiSyntax
@@ -135,6 +138,20 @@ class GuiTheme:
self.loadTheme()
self.loadSyntax()
+ # Update dependant colours
+ backCol = qApp.palette().window().color()
+ textCol = qApp.palette().windowText().color()
+
+ backLCol = backCol.lightnessF()
+ textLCol = textCol.lightnessF()
+
+ if backLCol > textLCol:
+ helpLCol = textLCol + 0.65*(backLCol - textLCol)
+ else:
+ helpLCol = backLCol + 0.65*(textLCol - backLCol)
+
+ self.helpText = [int(255*helpLCol)]*3
+
return True
def loadTheme(self):