novelWriter 2.2.1__py3-none-any.whl → 2.3b1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {novelWriter-2.2.1.dist-info → novelWriter-2.3b1.dist-info}/METADATA +1 -1
- {novelWriter-2.2.1.dist-info → novelWriter-2.3b1.dist-info}/RECORD +102 -92
- novelwriter/__init__.py +4 -4
- novelwriter/assets/icons/typicons_dark/icons.conf +6 -0
- novelwriter/assets/icons/typicons_dark/mixed_import.svg +5 -0
- novelwriter/assets/icons/typicons_dark/typ_document-add-col.svg +8 -0
- novelwriter/assets/icons/typicons_dark/typ_document-add.svg +4 -0
- novelwriter/assets/icons/typicons_dark/typ_document.svg +4 -0
- novelwriter/assets/icons/typicons_dark/typ_th-dot-more.svg +4 -0
- novelwriter/assets/icons/typicons_light/icons.conf +6 -0
- novelwriter/assets/icons/typicons_light/mixed_import.svg +5 -0
- novelwriter/assets/icons/typicons_light/typ_document-add-col.svg +8 -0
- novelwriter/assets/icons/typicons_light/typ_document-add.svg +4 -0
- novelwriter/assets/icons/typicons_light/typ_document.svg +4 -0
- novelwriter/assets/icons/typicons_light/typ_th-dot-more.svg +4 -0
- novelwriter/assets/images/novelwriter-text-dark.svg +4 -0
- novelwriter/assets/images/novelwriter-text-light.svg +4 -0
- novelwriter/assets/images/welcome-dark.jpg +0 -0
- novelwriter/assets/images/welcome-light.jpg +0 -0
- novelwriter/assets/manual.pdf +0 -0
- novelwriter/assets/sample.zip +0 -0
- novelwriter/assets/syntax/default_dark.conf +1 -0
- novelwriter/assets/syntax/default_light.conf +1 -0
- novelwriter/assets/syntax/grey_dark.conf +1 -0
- novelwriter/assets/syntax/grey_light.conf +1 -0
- novelwriter/assets/syntax/light_owl.conf +1 -0
- novelwriter/assets/syntax/night_owl.conf +1 -0
- novelwriter/assets/syntax/solarized_dark.conf +1 -0
- novelwriter/assets/syntax/solarized_light.conf +1 -0
- novelwriter/assets/syntax/tomorrow.conf +1 -0
- novelwriter/assets/syntax/tomorrow_night.conf +1 -0
- novelwriter/assets/syntax/tomorrow_night_blue.conf +1 -0
- novelwriter/assets/syntax/tomorrow_night_bright.conf +1 -0
- novelwriter/assets/syntax/tomorrow_night_eighties.conf +1 -0
- novelwriter/assets/text/credits_en.htm +4 -2
- novelwriter/assets/themes/default_dark.conf +2 -2
- novelwriter/assets/themes/default_light.conf +2 -2
- novelwriter/common.py +48 -37
- novelwriter/config.py +36 -41
- novelwriter/constants.py +38 -16
- novelwriter/core/buildsettings.py +7 -7
- novelwriter/core/coretools.py +192 -154
- novelwriter/core/docbuild.py +6 -3
- novelwriter/core/document.py +6 -6
- novelwriter/core/index.py +89 -56
- novelwriter/core/item.py +21 -3
- novelwriter/core/options.py +8 -7
- novelwriter/core/project.py +69 -44
- novelwriter/core/projectdata.py +1 -14
- novelwriter/core/projectxml.py +13 -41
- novelwriter/core/sessions.py +2 -1
- novelwriter/core/spellcheck.py +2 -1
- novelwriter/core/status.py +2 -1
- novelwriter/core/storage.py +178 -140
- novelwriter/core/tohtml.py +4 -2
- novelwriter/core/tokenizer.py +73 -45
- novelwriter/core/toodt.py +40 -30
- novelwriter/core/tree.py +3 -2
- novelwriter/dialogs/about.py +70 -160
- novelwriter/dialogs/docmerge.py +6 -5
- novelwriter/dialogs/docsplit.py +6 -6
- novelwriter/dialogs/editlabel.py +1 -1
- novelwriter/dialogs/preferences.py +553 -703
- novelwriter/dialogs/{projsettings.py → projectsettings.py} +288 -262
- novelwriter/dialogs/quotes.py +27 -23
- novelwriter/dialogs/wordlist.py +96 -40
- novelwriter/enum.py +20 -18
- novelwriter/error.py +1 -1
- novelwriter/extensions/circularprogress.py +11 -11
- novelwriter/extensions/configlayout.py +185 -134
- novelwriter/extensions/modified.py +81 -0
- novelwriter/extensions/novelselector.py +26 -12
- novelwriter/extensions/pagedsidebar.py +14 -16
- novelwriter/extensions/simpleprogress.py +5 -5
- novelwriter/extensions/statusled.py +8 -8
- novelwriter/extensions/switch.py +31 -63
- novelwriter/extensions/switchbox.py +1 -1
- novelwriter/extensions/versioninfo.py +153 -0
- novelwriter/gui/doceditor.py +178 -150
- novelwriter/gui/dochighlight.py +63 -92
- novelwriter/gui/docviewer.py +49 -51
- novelwriter/gui/docviewerpanel.py +72 -24
- novelwriter/gui/itemdetails.py +7 -7
- novelwriter/gui/mainmenu.py +14 -18
- novelwriter/gui/noveltree.py +9 -8
- novelwriter/gui/outline.py +98 -75
- novelwriter/gui/projtree.py +188 -61
- novelwriter/gui/sidebar.py +3 -4
- novelwriter/gui/statusbar.py +3 -4
- novelwriter/gui/theme.py +60 -68
- novelwriter/guimain.py +49 -156
- novelwriter/shared.py +15 -1
- novelwriter/tools/dictionaries.py +5 -6
- novelwriter/tools/manuscript.py +6 -6
- novelwriter/tools/manussettings.py +192 -221
- novelwriter/tools/noveldetails.py +525 -0
- novelwriter/tools/welcome.py +802 -0
- novelwriter/tools/writingstats.py +9 -9
- novelwriter/assets/images/wizard-back.jpg +0 -0
- novelwriter/assets/text/gplv3_en.htm +0 -641
- novelwriter/assets/text/release_notes.htm +0 -60
- novelwriter/dialogs/projdetails.py +0 -518
- novelwriter/dialogs/projload.py +0 -294
- novelwriter/dialogs/updates.py +0 -172
- novelwriter/extensions/pageddialog.py +0 -130
- novelwriter/tools/projwizard.py +0 -478
- {novelWriter-2.2.1.dist-info → novelWriter-2.3b1.dist-info}/LICENSE.md +0 -0
- {novelWriter-2.2.1.dist-info → novelWriter-2.3b1.dist-info}/WHEEL +0 -0
- {novelWriter-2.2.1.dist-info → novelWriter-2.3b1.dist-info}/entry_points.txt +0 -0
- {novelWriter-2.2.1.dist-info → novelWriter-2.3b1.dist-info}/top_level.txt +0 -0
@@ -3,7 +3,8 @@ novelWriter – GUI Preferences
|
|
3
3
|
=============================
|
4
4
|
|
5
5
|
File History:
|
6
|
-
Created:
|
6
|
+
Created: 2019-06-10 [0.1.5] GuiPreferences
|
7
|
+
Rewritten: 2024-01-08 [2.3b1] GuiPreferences
|
7
8
|
|
8
9
|
This file is a part of novelWriter
|
9
10
|
Copyright 2018–2024, Veronica Berglyd Olsen
|
@@ -25,23 +26,26 @@ from __future__ import annotations
|
|
25
26
|
|
26
27
|
import logging
|
27
28
|
|
28
|
-
from PyQt5.QtGui import QCloseEvent, QFont
|
29
|
+
from PyQt5.QtGui import QCloseEvent, QFont, QKeyEvent, QKeySequence
|
29
30
|
from PyQt5.QtCore import Qt, pyqtSignal, pyqtSlot
|
30
31
|
from PyQt5.QtWidgets import (
|
31
|
-
|
32
|
-
QLineEdit,
|
32
|
+
QAbstractButton, QCompleter, QDialog, QDialogButtonBox, QFileDialog,
|
33
|
+
QFontDialog, QHBoxLayout, QLineEdit, QPushButton, QToolButton, QVBoxLayout,
|
34
|
+
QWidget, qApp
|
33
35
|
)
|
34
36
|
|
35
37
|
from novelwriter import CONFIG, SHARED
|
38
|
+
from novelwriter.constants import nwConst, nwUnicode
|
36
39
|
from novelwriter.dialogs.quotes import GuiQuoteSelect
|
37
40
|
from novelwriter.extensions.switch import NSwitch
|
38
|
-
from novelwriter.extensions.
|
39
|
-
from novelwriter.extensions.configlayout import
|
41
|
+
from novelwriter.extensions.modified import NComboBox, NDoubleSpinBox, NSpinBox
|
42
|
+
from novelwriter.extensions.configlayout import NColourLabel, NScrollableForm
|
43
|
+
from novelwriter.extensions.pagedsidebar import NPagedSideBar
|
40
44
|
|
41
45
|
logger = logging.getLogger(__name__)
|
42
46
|
|
43
47
|
|
44
|
-
class GuiPreferences(
|
48
|
+
class GuiPreferences(QDialog):
|
45
49
|
|
46
50
|
newPreferencesReady = pyqtSignal(bool, bool, bool, bool)
|
47
51
|
|
@@ -51,986 +55,623 @@ class GuiPreferences(NPagedDialog):
|
|
51
55
|
logger.debug("Create: GuiPreferences")
|
52
56
|
self.setObjectName("GuiPreferences")
|
53
57
|
self.setWindowTitle(self.tr("Preferences"))
|
54
|
-
|
55
|
-
self.tabGeneral = GuiPreferencesGeneral(self)
|
56
|
-
self.tabProjects = GuiPreferencesProjects(self)
|
57
|
-
self.tabDocs = GuiPreferencesDocuments(self)
|
58
|
-
self.tabEditor = GuiPreferencesEditor(self)
|
59
|
-
self.tabSyntax = GuiPreferencesSyntax(self)
|
60
|
-
self.tabAuto = GuiPreferencesAutomation(self)
|
61
|
-
self.tabQuote = GuiPreferencesQuotes(self)
|
62
|
-
|
63
|
-
self.addTab(self.tabGeneral, self.tr("General"))
|
64
|
-
self.addTab(self.tabProjects, self.tr("Projects"))
|
65
|
-
self.addTab(self.tabDocs, self.tr("Documents"))
|
66
|
-
self.addTab(self.tabEditor, self.tr("Editor"))
|
67
|
-
self.addTab(self.tabSyntax, self.tr("Highlighting"))
|
68
|
-
self.addTab(self.tabAuto, self.tr("Automation"))
|
69
|
-
self.addTab(self.tabQuote, self.tr("Quotes"))
|
70
|
-
|
71
|
-
self.buttonBox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel, self)
|
72
|
-
self.buttonBox.accepted.connect(self._doSave)
|
73
|
-
self.buttonBox.rejected.connect(self.close)
|
74
|
-
self.rejected.connect(self.close)
|
75
|
-
self.addControls(self.buttonBox)
|
76
|
-
|
58
|
+
self.setMinimumSize(CONFIG.pxInt(600), CONFIG.pxInt(500))
|
77
59
|
self.resize(*CONFIG.preferencesWinSize)
|
78
60
|
|
79
|
-
#
|
80
|
-
self.
|
81
|
-
|
82
|
-
|
83
|
-
|
61
|
+
# Title
|
62
|
+
self.titleLabel = NColourLabel(
|
63
|
+
self.tr("Preferences"), SHARED.theme.helpText,
|
64
|
+
parent=self, scale=NColourLabel.HEADER_SCALE, indent=CONFIG.pxInt(4)
|
65
|
+
)
|
84
66
|
|
85
|
-
|
67
|
+
# Search Box
|
68
|
+
self.searchText = QLineEdit(self)
|
69
|
+
self.searchText.setPlaceholderText(self.tr("Search"))
|
70
|
+
self.searchText.setMinimumWidth(CONFIG.pxInt(200))
|
71
|
+
self.searchAction = self.searchText.addAction(
|
72
|
+
SHARED.theme.getIcon("search"), QLineEdit.ActionPosition.TrailingPosition
|
73
|
+
)
|
74
|
+
self.searchAction.triggered.connect(self._gotoSearch)
|
86
75
|
|
87
|
-
|
76
|
+
# SideBar
|
77
|
+
self.sidebar = NPagedSideBar(self)
|
78
|
+
self.sidebar.setLabelColor(SHARED.theme.helpText)
|
79
|
+
self.sidebar.buttonClicked.connect(self._sidebarClicked)
|
88
80
|
|
89
|
-
|
90
|
-
|
91
|
-
|
81
|
+
# Form
|
82
|
+
self.mainForm = NScrollableForm(self)
|
83
|
+
self.mainForm.setHelpTextStyle(SHARED.theme.helpText)
|
92
84
|
|
93
|
-
|
94
|
-
|
95
|
-
|
85
|
+
# Buttons
|
86
|
+
self.buttonBox = QDialogButtonBox(
|
87
|
+
QDialogButtonBox.StandardButton.Apply
|
88
|
+
| QDialogButtonBox.StandardButton.Save
|
89
|
+
| QDialogButtonBox.StandardButton.Close
|
90
|
+
)
|
91
|
+
self.buttonBox.clicked.connect(self._dialogButtonClicked)
|
96
92
|
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
self.
|
101
|
-
|
102
|
-
self.deleteLater()
|
103
|
-
return
|
93
|
+
# Assemble
|
94
|
+
self.searchBox = QHBoxLayout()
|
95
|
+
self.searchBox.addWidget(self.titleLabel)
|
96
|
+
self.searchBox.addStretch(1)
|
97
|
+
self.searchBox.addWidget(self.searchText, 1)
|
104
98
|
|
105
|
-
|
106
|
-
|
107
|
-
|
99
|
+
self.mainBox = QHBoxLayout()
|
100
|
+
self.mainBox.addWidget(self.sidebar)
|
101
|
+
self.mainBox.addWidget(self.mainForm)
|
102
|
+
self.mainBox.setContentsMargins(0, 0, 0, 0)
|
108
103
|
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
self.
|
113
|
-
self.
|
114
|
-
self.tabDocs.saveValues()
|
115
|
-
self.tabEditor.saveValues()
|
116
|
-
self.tabSyntax.saveValues()
|
117
|
-
self.tabAuto.saveValues()
|
118
|
-
self.tabQuote.saveValues()
|
104
|
+
self.outerBox = QVBoxLayout()
|
105
|
+
self.outerBox.addLayout(self.searchBox)
|
106
|
+
self.outerBox.addLayout(self.mainBox)
|
107
|
+
self.outerBox.addWidget(self.buttonBox)
|
108
|
+
self.outerBox.setSpacing(CONFIG.pxInt(8))
|
119
109
|
|
120
|
-
|
121
|
-
self.
|
122
|
-
self._needsRestart, self._refreshTree, self._updateTheme, self._updateSyntax
|
123
|
-
)
|
124
|
-
qApp.processEvents()
|
125
|
-
self.close()
|
110
|
+
self.setLayout(self.outerBox)
|
111
|
+
self.setSizeGripEnabled(True)
|
126
112
|
|
127
|
-
|
113
|
+
# Build Form
|
114
|
+
self.buildForm()
|
128
115
|
|
129
|
-
|
130
|
-
|
131
|
-
|
116
|
+
# Populate Search
|
117
|
+
self.searchCompleter = QCompleter(self.mainForm.labels, self)
|
118
|
+
self.searchCompleter.setCaseSensitivity(Qt.CaseSensitivity.CaseInsensitive)
|
119
|
+
self.searchCompleter.setFilterMode(Qt.MatchFlag.MatchContains)
|
120
|
+
self.searchCompleter.activated.connect(self._gotoSearch)
|
132
121
|
|
133
|
-
|
134
|
-
"""Save the dialog window size."""
|
135
|
-
CONFIG.setPreferencesWinSize(self.width(), self.height())
|
136
|
-
return
|
122
|
+
self.searchText.setCompleter(self.searchCompleter)
|
137
123
|
|
138
|
-
|
124
|
+
logger.debug("Ready: GuiPreferences")
|
139
125
|
|
126
|
+
return
|
140
127
|
|
141
|
-
|
128
|
+
def __del__(self) -> None: # pragma: no cover
|
129
|
+
logger.debug("Delete: GuiPreferences")
|
130
|
+
return
|
142
131
|
|
143
|
-
def
|
144
|
-
|
132
|
+
def buildForm(self) -> None:
|
133
|
+
"""Build the settings form."""
|
134
|
+
section = 0
|
135
|
+
minWidth = CONFIG.pxInt(200)
|
136
|
+
mIcon = SHARED.theme.getIcon("more")
|
145
137
|
|
146
|
-
|
138
|
+
# Label
|
139
|
+
self.sidebar.addLabel(self.tr("General"))
|
147
140
|
|
148
|
-
#
|
149
|
-
|
150
|
-
self.mainForm.setHelpTextStyle(SHARED.theme.helpText)
|
151
|
-
self.setLayout(self.mainForm)
|
141
|
+
# Appearance
|
142
|
+
# ==========
|
152
143
|
|
153
|
-
|
154
|
-
|
155
|
-
self.
|
156
|
-
|
144
|
+
title = self.tr("Appearance")
|
145
|
+
section += 1
|
146
|
+
self.sidebar.addButton(title, section)
|
147
|
+
self.mainForm.addGroupLabel(title, section)
|
157
148
|
|
158
|
-
#
|
159
|
-
self.guiLocale =
|
149
|
+
# Display Language
|
150
|
+
self.guiLocale = NComboBox(self)
|
160
151
|
self.guiLocale.setMinimumWidth(minWidth)
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
if langIdx < 0:
|
166
|
-
langIdx = self.guiLocale.findData("en_GB")
|
167
|
-
if langIdx != -1:
|
168
|
-
self.guiLocale.setCurrentIndex(langIdx)
|
152
|
+
for lang, name in CONFIG.listLanguages(CONFIG.LANG_NW):
|
153
|
+
self.guiLocale.addItem(name, lang)
|
154
|
+
if (idx := self.guiLocale.findData(CONFIG.guiLocale)) != -1:
|
155
|
+
self.guiLocale.setCurrentIndex(idx)
|
169
156
|
|
170
157
|
self.mainForm.addRow(
|
171
|
-
self.tr("
|
172
|
-
self.
|
173
|
-
self.tr("Requires restart to take effect.")
|
158
|
+
self.tr("Display language"), self.guiLocale,
|
159
|
+
self.tr("Requires restart to take effect."), stretch=(3, 2)
|
174
160
|
)
|
175
161
|
|
176
|
-
#
|
177
|
-
self.guiTheme =
|
162
|
+
# Colour Theme
|
163
|
+
self.guiTheme = NComboBox(self)
|
178
164
|
self.guiTheme.setMinimumWidth(minWidth)
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
if themeIdx != -1:
|
184
|
-
self.guiTheme.setCurrentIndex(themeIdx)
|
185
|
-
|
186
|
-
self.mainForm.addRow(
|
187
|
-
self.tr("Main GUI theme"),
|
188
|
-
self.guiTheme,
|
189
|
-
self.tr("General colour theme and icons.")
|
190
|
-
)
|
191
|
-
|
192
|
-
# Editor Theme
|
193
|
-
self.guiSyntax = QComboBox(self)
|
194
|
-
self.guiSyntax.setMinimumWidth(CONFIG.pxInt(200))
|
195
|
-
self.theSyntaxes = SHARED.theme.listSyntax()
|
196
|
-
for syntaxFile, syntaxName in self.theSyntaxes:
|
197
|
-
self.guiSyntax.addItem(syntaxName, syntaxFile)
|
198
|
-
syntaxIdx = self.guiSyntax.findData(CONFIG.guiSyntax)
|
199
|
-
if syntaxIdx != -1:
|
200
|
-
self.guiSyntax.setCurrentIndex(syntaxIdx)
|
165
|
+
for theme, name in SHARED.theme.listThemes():
|
166
|
+
self.guiTheme.addItem(name, theme)
|
167
|
+
if (idx := self.guiTheme.findData(CONFIG.guiTheme)) != -1:
|
168
|
+
self.guiTheme.setCurrentIndex(idx)
|
201
169
|
|
202
170
|
self.mainForm.addRow(
|
203
|
-
self.tr("
|
204
|
-
self.
|
205
|
-
self.tr("Colour theme for the editor and viewer.")
|
171
|
+
self.tr("Colour theme"), self.guiTheme,
|
172
|
+
self.tr("General colour theme and icons."), stretch=(3, 2)
|
206
173
|
)
|
207
174
|
|
208
|
-
# Font Family
|
175
|
+
# Application Font Family
|
209
176
|
self.guiFont = QLineEdit(self)
|
210
177
|
self.guiFont.setReadOnly(True)
|
211
|
-
self.guiFont.
|
178
|
+
self.guiFont.setMinimumWidth(CONFIG.pxInt(162))
|
212
179
|
self.guiFont.setText(CONFIG.guiFont)
|
213
|
-
self.
|
214
|
-
self.
|
215
|
-
self.
|
180
|
+
self.guiFontButton = QToolButton(self)
|
181
|
+
self.guiFontButton.setIcon(mIcon)
|
182
|
+
self.guiFontButton.clicked.connect(self._selectGuiFont)
|
216
183
|
self.mainForm.addRow(
|
217
|
-
self.tr("
|
218
|
-
self.
|
219
|
-
self.
|
220
|
-
button=self.fontButton
|
184
|
+
self.tr("Application font family"), self.guiFont,
|
185
|
+
self.tr("Requires restart to take effect."), stretch=(3, 2),
|
186
|
+
button=self.guiFontButton
|
221
187
|
)
|
222
188
|
|
223
|
-
# Font Size
|
224
|
-
self.guiFontSize =
|
189
|
+
# Application Font Size
|
190
|
+
self.guiFontSize = NSpinBox(self)
|
225
191
|
self.guiFontSize.setMinimum(8)
|
226
192
|
self.guiFontSize.setMaximum(60)
|
227
193
|
self.guiFontSize.setSingleStep(1)
|
228
194
|
self.guiFontSize.setValue(CONFIG.guiFontSize)
|
229
195
|
self.mainForm.addRow(
|
230
|
-
self.tr("
|
231
|
-
self.
|
232
|
-
self.tr("Requires restart to take effect."),
|
233
|
-
unit=self.tr("pt")
|
196
|
+
self.tr("Application font size"), self.guiFontSize,
|
197
|
+
self.tr("Requires restart to take effect."), unit=self.tr("pt")
|
234
198
|
)
|
235
199
|
|
236
|
-
#
|
237
|
-
|
238
|
-
self.mainForm.addGroupLabel(self.tr("GUI Settings"))
|
239
|
-
|
240
|
-
self.emphLabels = NSwitch()
|
241
|
-
self.emphLabels.setChecked(CONFIG.emphLabels)
|
242
|
-
self.mainForm.addRow(
|
243
|
-
self.tr("Emphasise partition and chapter labels"),
|
244
|
-
self.emphLabels,
|
245
|
-
self.tr("Makes them stand out in the project tree."),
|
246
|
-
)
|
247
|
-
|
248
|
-
self.showFullPath = NSwitch()
|
249
|
-
self.showFullPath.setChecked(CONFIG.showFullPath)
|
250
|
-
self.mainForm.addRow(
|
251
|
-
self.tr("Show full path in document header"),
|
252
|
-
self.showFullPath,
|
253
|
-
self.tr("Add the parent folder names to the header.")
|
254
|
-
)
|
255
|
-
|
256
|
-
self.hideVScroll = NSwitch()
|
200
|
+
# Vertical Scrollbars
|
201
|
+
self.hideVScroll = NSwitch(self)
|
257
202
|
self.hideVScroll.setChecked(CONFIG.hideVScroll)
|
258
203
|
self.mainForm.addRow(
|
259
|
-
self.tr("Hide vertical scroll bars in main windows"),
|
260
|
-
self.hideVScroll,
|
204
|
+
self.tr("Hide vertical scroll bars in main windows"), self.hideVScroll,
|
261
205
|
self.tr("Scrolling available with mouse wheel and keys only.")
|
262
206
|
)
|
263
207
|
|
264
|
-
|
208
|
+
# Horizontal Scrollbars
|
209
|
+
self.hideHScroll = NSwitch(self)
|
265
210
|
self.hideHScroll.setChecked(CONFIG.hideHScroll)
|
266
211
|
self.mainForm.addRow(
|
267
|
-
self.tr("Hide horizontal scroll bars in main windows"),
|
268
|
-
self.hideHScroll,
|
212
|
+
self.tr("Hide horizontal scroll bars in main windows"), self.hideHScroll,
|
269
213
|
self.tr("Scrolling available with mouse wheel and keys only.")
|
270
214
|
)
|
271
215
|
|
272
|
-
|
216
|
+
# Document Style
|
217
|
+
# ==============
|
273
218
|
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
guiSyntax = self.guiSyntax.currentData()
|
279
|
-
guiFont = self.guiFont.text()
|
280
|
-
guiFontSize = self.guiFontSize.value()
|
281
|
-
emphLabels = self.emphLabels.isChecked()
|
282
|
-
|
283
|
-
# Update Flags
|
284
|
-
self.prefsGui._updateTheme |= CONFIG.guiTheme != guiTheme
|
285
|
-
self.prefsGui._updateSyntax |= CONFIG.guiSyntax != guiSyntax
|
286
|
-
self.prefsGui._needsRestart |= CONFIG.guiLocale != guiLocale
|
287
|
-
self.prefsGui._needsRestart |= CONFIG.guiFont != guiFont
|
288
|
-
self.prefsGui._needsRestart |= CONFIG.guiFontSize != guiFontSize
|
289
|
-
self.prefsGui._refreshTree |= CONFIG.emphLabels != emphLabels
|
290
|
-
|
291
|
-
CONFIG.guiLocale = guiLocale
|
292
|
-
CONFIG.guiTheme = guiTheme
|
293
|
-
CONFIG.guiSyntax = guiSyntax
|
294
|
-
CONFIG.guiFont = guiFont
|
295
|
-
CONFIG.guiFontSize = guiFontSize
|
296
|
-
CONFIG.emphLabels = emphLabels
|
297
|
-
CONFIG.showFullPath = self.showFullPath.isChecked()
|
298
|
-
CONFIG.hideVScroll = self.hideVScroll.isChecked()
|
299
|
-
CONFIG.hideHScroll = self.hideHScroll.isChecked()
|
219
|
+
title = self.tr("Document Style")
|
220
|
+
section += 1
|
221
|
+
self.sidebar.addButton(title, section)
|
222
|
+
self.mainForm.addGroupLabel(title, section)
|
300
223
|
|
301
|
-
|
224
|
+
# Document Colour Theme
|
225
|
+
self.guiSyntax = NComboBox(self)
|
226
|
+
self.guiSyntax.setMinimumWidth(CONFIG.pxInt(200))
|
227
|
+
for syntax, name in SHARED.theme.listSyntax():
|
228
|
+
self.guiSyntax.addItem(name, syntax)
|
229
|
+
if (idx := self.guiSyntax.findData(CONFIG.guiSyntax)) != -1:
|
230
|
+
self.guiSyntax.setCurrentIndex(idx)
|
302
231
|
|
303
|
-
|
304
|
-
|
305
|
-
|
232
|
+
self.mainForm.addRow(
|
233
|
+
self.tr("Document colour theme"), self.guiSyntax,
|
234
|
+
self.tr("Colour theme for the editor and viewer."), stretch=(3, 2)
|
235
|
+
)
|
306
236
|
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
self.
|
317
|
-
|
237
|
+
# Document Font Family
|
238
|
+
self.textFont = QLineEdit(self)
|
239
|
+
self.textFont.setReadOnly(True)
|
240
|
+
self.textFont.setMinimumWidth(CONFIG.pxInt(162))
|
241
|
+
self.textFont.setText(CONFIG.textFont)
|
242
|
+
self.textFontButton = QToolButton(self)
|
243
|
+
self.textFontButton.setIcon(mIcon)
|
244
|
+
self.textFontButton.clicked.connect(self._selectTextFont)
|
245
|
+
self.mainForm.addRow(
|
246
|
+
self.tr("Document font family"), self.textFont,
|
247
|
+
self.tr("Applies to both document editor and viewer."), stretch=(3, 2),
|
248
|
+
button=self.textFontButton
|
249
|
+
)
|
318
250
|
|
319
|
-
#
|
251
|
+
# Document Font Size
|
252
|
+
self.textSize = NSpinBox(self)
|
253
|
+
self.textSize.setMinimum(8)
|
254
|
+
self.textSize.setMaximum(60)
|
255
|
+
self.textSize.setSingleStep(1)
|
256
|
+
self.textSize.setValue(CONFIG.textSize)
|
257
|
+
self.mainForm.addRow(
|
258
|
+
self.tr("Document font size"), self.textSize,
|
259
|
+
self.tr("Applies to both document editor and viewer."), unit=self.tr("pt")
|
260
|
+
)
|
320
261
|
|
262
|
+
# Emphasise Labels
|
263
|
+
self.emphLabels = NSwitch(self)
|
264
|
+
self.emphLabels.setChecked(CONFIG.emphLabels)
|
265
|
+
self.mainForm.addRow(
|
266
|
+
self.tr("Emphasise partition and chapter labels"), self.emphLabels,
|
267
|
+
self.tr("Makes them stand out in the project tree."),
|
268
|
+
)
|
321
269
|
|
322
|
-
|
270
|
+
# Document Path
|
271
|
+
self.showFullPath = NSwitch(self)
|
272
|
+
self.showFullPath.setChecked(CONFIG.showFullPath)
|
273
|
+
self.mainForm.addRow(
|
274
|
+
self.tr("Show full path in document header"), self.showFullPath,
|
275
|
+
self.tr("Add the parent folder names to the header.")
|
276
|
+
)
|
323
277
|
|
324
|
-
|
325
|
-
|
278
|
+
# Include Notes in Word Count
|
279
|
+
self.incNotesWCount = NSwitch(self)
|
280
|
+
self.incNotesWCount.setChecked(CONFIG.incNotesWCount)
|
281
|
+
self.mainForm.addRow(
|
282
|
+
self.tr("Include project notes in status bar word count"), self.incNotesWCount
|
283
|
+
)
|
326
284
|
|
327
|
-
#
|
328
|
-
|
329
|
-
self.mainForm.setHelpTextStyle(SHARED.theme.helpText)
|
330
|
-
self.setLayout(self.mainForm)
|
285
|
+
# Auto Save
|
286
|
+
# =========
|
331
287
|
|
332
|
-
|
333
|
-
|
334
|
-
self.
|
288
|
+
title = self.tr("Auto Save")
|
289
|
+
section += 1
|
290
|
+
self.sidebar.addButton(title, section)
|
291
|
+
self.mainForm.addGroupLabel(title, section)
|
335
292
|
|
336
293
|
# Document Save Timer
|
337
|
-
self.autoSaveDoc =
|
294
|
+
self.autoSaveDoc = NSpinBox(self)
|
338
295
|
self.autoSaveDoc.setMinimum(5)
|
339
296
|
self.autoSaveDoc.setMaximum(600)
|
340
297
|
self.autoSaveDoc.setSingleStep(1)
|
341
298
|
self.autoSaveDoc.setValue(CONFIG.autoSaveDoc)
|
342
299
|
self.mainForm.addRow(
|
343
|
-
self.tr("Save document interval"),
|
344
|
-
self.
|
345
|
-
self.tr("How often the document is automatically saved."),
|
346
|
-
unit=self.tr("seconds")
|
300
|
+
self.tr("Save document interval"), self.autoSaveDoc,
|
301
|
+
self.tr("How often the document is automatically saved."), unit=self.tr("seconds")
|
347
302
|
)
|
348
303
|
|
349
304
|
# Project Save Timer
|
350
|
-
self.autoSaveProj =
|
305
|
+
self.autoSaveProj = NSpinBox(self)
|
351
306
|
self.autoSaveProj.setMinimum(5)
|
352
307
|
self.autoSaveProj.setMaximum(600)
|
353
308
|
self.autoSaveProj.setSingleStep(1)
|
354
309
|
self.autoSaveProj.setValue(CONFIG.autoSaveProj)
|
355
310
|
self.mainForm.addRow(
|
356
|
-
self.tr("Save project interval"),
|
357
|
-
self.
|
358
|
-
self.tr("How often the project is automatically saved."),
|
359
|
-
unit=self.tr("seconds")
|
311
|
+
self.tr("Save project interval"), self.autoSaveProj,
|
312
|
+
self.tr("How often the project is automatically saved."), unit=self.tr("seconds")
|
360
313
|
)
|
361
314
|
|
362
315
|
# Project Backup
|
363
316
|
# ==============
|
364
|
-
|
317
|
+
|
318
|
+
title = self.tr("Project Backup")
|
319
|
+
section += 1
|
320
|
+
self.sidebar.addButton(title, section)
|
321
|
+
self.mainForm.addGroupLabel(title, section)
|
365
322
|
|
366
323
|
# Backup Path
|
367
324
|
self.backupPath = CONFIG.backupPath()
|
368
|
-
self.backupGetPath = QPushButton(self.tr("Browse"), self)
|
325
|
+
self.backupGetPath = QPushButton(SHARED.theme.getIcon("browse"), self.tr("Browse"), self)
|
369
326
|
self.backupGetPath.clicked.connect(self._backupFolder)
|
370
|
-
self.
|
371
|
-
self.tr("Backup storage location"),
|
372
|
-
self.
|
373
|
-
self.tr("Path: {0}").format(self.backupPath)
|
327
|
+
self.mainForm.addRow(
|
328
|
+
self.tr("Backup storage location"), self.backupGetPath,
|
329
|
+
self.tr("Path: {0}").format(self.backupPath), editable="backupPath"
|
374
330
|
)
|
375
331
|
|
376
|
-
# Run
|
377
|
-
self.backupOnClose = NSwitch()
|
332
|
+
# Run When Closing
|
333
|
+
self.backupOnClose = NSwitch(self)
|
378
334
|
self.backupOnClose.setChecked(CONFIG.backupOnClose)
|
379
335
|
self.backupOnClose.toggled.connect(self._toggledBackupOnClose)
|
380
336
|
self.mainForm.addRow(
|
381
|
-
self.tr("Run backup when the project is closed"),
|
382
|
-
self.backupOnClose,
|
337
|
+
self.tr("Run backup when the project is closed"), self.backupOnClose,
|
383
338
|
self.tr("Can be overridden for individual projects in Project Settings.")
|
384
339
|
)
|
385
340
|
|
386
|
-
# Ask
|
341
|
+
# Ask Before Backup
|
387
342
|
# Only enabled when "Run when closing" is checked
|
388
|
-
self.askBeforeBackup = NSwitch()
|
343
|
+
self.askBeforeBackup = NSwitch(self)
|
389
344
|
self.askBeforeBackup.setChecked(CONFIG.askBeforeBackup)
|
390
345
|
self.askBeforeBackup.setEnabled(CONFIG.backupOnClose)
|
391
346
|
self.mainForm.addRow(
|
392
|
-
self.tr("Ask before running backup"),
|
393
|
-
self.askBeforeBackup,
|
347
|
+
self.tr("Ask before running backup"), self.askBeforeBackup,
|
394
348
|
self.tr("If off, backups will run in the background.")
|
395
349
|
)
|
396
350
|
|
397
351
|
# Session Timer
|
398
352
|
# =============
|
399
|
-
self.mainForm.addGroupLabel(self.tr("Session Timer"))
|
400
353
|
|
401
|
-
|
402
|
-
|
354
|
+
title = self.tr("Session Timer")
|
355
|
+
section += 1
|
356
|
+
self.sidebar.addButton(title, section)
|
357
|
+
self.mainForm.addGroupLabel(title, section)
|
358
|
+
|
359
|
+
# Pause When Idle
|
360
|
+
self.stopWhenIdle = NSwitch(self)
|
403
361
|
self.stopWhenIdle.setChecked(CONFIG.stopWhenIdle)
|
404
362
|
self.mainForm.addRow(
|
405
|
-
self.tr("Pause the session timer when not writing"),
|
406
|
-
self.stopWhenIdle,
|
363
|
+
self.tr("Pause the session timer when not writing"), self.stopWhenIdle,
|
407
364
|
self.tr("Also pauses when the application window does not have focus.")
|
408
365
|
)
|
409
366
|
|
410
|
-
# Inactive
|
411
|
-
self.userIdleTime =
|
367
|
+
# Inactive Time for Idle
|
368
|
+
self.userIdleTime = NDoubleSpinBox(self)
|
412
369
|
self.userIdleTime.setMinimum(0.5)
|
413
370
|
self.userIdleTime.setMaximum(600.0)
|
414
371
|
self.userIdleTime.setSingleStep(0.5)
|
415
372
|
self.userIdleTime.setDecimals(1)
|
416
373
|
self.userIdleTime.setValue(CONFIG.userIdleTime/60.0)
|
417
374
|
self.mainForm.addRow(
|
418
|
-
self.tr("Editor inactive time before pausing timer"),
|
419
|
-
self.userIdleTime,
|
375
|
+
self.tr("Editor inactive time before pausing timer"), self.userIdleTime,
|
420
376
|
self.tr("User activity includes typing and changing the content."),
|
421
377
|
unit=self.tr("minutes")
|
422
378
|
)
|
423
379
|
|
424
|
-
|
425
|
-
|
426
|
-
def saveValues(self) -> None:
|
427
|
-
"""Save the values set for this tab."""
|
428
|
-
# Automatic Save
|
429
|
-
CONFIG.autoSaveDoc = self.autoSaveDoc.value()
|
430
|
-
CONFIG.autoSaveProj = self.autoSaveProj.value()
|
431
|
-
|
432
|
-
# Project Backup
|
433
|
-
CONFIG.setBackupPath(self.backupPath)
|
434
|
-
CONFIG.backupOnClose = self.backupOnClose.isChecked()
|
435
|
-
CONFIG.askBeforeBackup = self.askBeforeBackup.isChecked()
|
436
|
-
|
437
|
-
# Session Timer
|
438
|
-
CONFIG.stopWhenIdle = self.stopWhenIdle.isChecked()
|
439
|
-
CONFIG.userIdleTime = round(self.userIdleTime.value() * 60)
|
440
|
-
|
441
|
-
return
|
442
|
-
|
443
|
-
##
|
444
|
-
# Private Slots
|
445
|
-
##
|
446
|
-
|
447
|
-
@pyqtSlot()
|
448
|
-
def _backupFolder(self) -> None:
|
449
|
-
"""Open a dialog to select the backup folder."""
|
450
|
-
currDir = self.backupPath or ""
|
451
|
-
newDir = QFileDialog.getExistingDirectory(
|
452
|
-
self, self.tr("Backup Directory"), str(currDir), options=QFileDialog.ShowDirsOnly
|
453
|
-
)
|
454
|
-
if newDir:
|
455
|
-
self.backupPath = newDir
|
456
|
-
self.mainForm.setHelpText(
|
457
|
-
self.backupPathRow, self.tr("Path: {0}").format(self.backupPath)
|
458
|
-
)
|
459
|
-
return
|
460
|
-
return
|
461
|
-
|
462
|
-
@pyqtSlot(bool)
|
463
|
-
def _toggledBackupOnClose(self, state: bool) -> None:
|
464
|
-
"""Toggle switch that depends on the backup on close switch."""
|
465
|
-
self.askBeforeBackup.setEnabled(state)
|
466
|
-
return
|
467
|
-
|
468
|
-
# END Class GuiPreferencesProjects
|
469
|
-
|
470
|
-
|
471
|
-
class GuiPreferencesDocuments(QWidget):
|
472
|
-
|
473
|
-
def __init__(self, prefsGui: GuiPreferences) -> None:
|
474
|
-
super().__init__(parent=prefsGui)
|
475
|
-
|
476
|
-
# The Form
|
477
|
-
self.mainForm = NConfigLayout()
|
478
|
-
self.mainForm.setHelpTextStyle(SHARED.theme.helpText)
|
479
|
-
self.setLayout(self.mainForm)
|
480
|
-
|
481
|
-
# Text Style
|
482
|
-
# ==========
|
483
|
-
self.mainForm.addGroupLabel(self.tr("Text Style"))
|
484
|
-
|
485
|
-
# Font Family
|
486
|
-
self.textFont = QLineEdit(self)
|
487
|
-
self.textFont.setReadOnly(True)
|
488
|
-
self.textFont.setFixedWidth(CONFIG.pxInt(162))
|
489
|
-
self.textFont.setText(CONFIG.textFont)
|
490
|
-
self.fontButton = QPushButton("...", self)
|
491
|
-
self.fontButton.setMaximumWidth(int(2.5*SHARED.theme.getTextWidth("...")))
|
492
|
-
self.fontButton.clicked.connect(self._selectFont)
|
493
|
-
self.mainForm.addRow(
|
494
|
-
self.tr("Font family"),
|
495
|
-
self.textFont,
|
496
|
-
self.tr("Applies to both document editor and viewer."),
|
497
|
-
button=self.fontButton
|
498
|
-
)
|
499
|
-
|
500
|
-
# Font Size
|
501
|
-
self.textSize = QSpinBox(self)
|
502
|
-
self.textSize.setMinimum(8)
|
503
|
-
self.textSize.setMaximum(60)
|
504
|
-
self.textSize.setSingleStep(1)
|
505
|
-
self.textSize.setValue(CONFIG.textSize)
|
506
|
-
self.mainForm.addRow(
|
507
|
-
self.tr("Font size"),
|
508
|
-
self.textSize,
|
509
|
-
self.tr("Applies to both document editor and viewer."),
|
510
|
-
unit=self.tr("pt")
|
511
|
-
)
|
380
|
+
# Label
|
381
|
+
self.sidebar.addLabel(self.tr("Writing"))
|
512
382
|
|
513
383
|
# Text Flow
|
514
384
|
# =========
|
515
|
-
|
385
|
+
|
386
|
+
title = self.tr("Text Flow")
|
387
|
+
section += 1
|
388
|
+
self.sidebar.addButton(title, section)
|
389
|
+
self.mainForm.addGroupLabel(title, section)
|
516
390
|
|
517
391
|
# Max Text Width in Normal Mode
|
518
|
-
self.textWidth =
|
392
|
+
self.textWidth = NSpinBox(self)
|
519
393
|
self.textWidth.setMinimum(0)
|
520
394
|
self.textWidth.setMaximum(10000)
|
521
395
|
self.textWidth.setSingleStep(10)
|
522
396
|
self.textWidth.setValue(CONFIG.textWidth)
|
523
397
|
self.mainForm.addRow(
|
524
|
-
self.tr("Maximum text width in \"Normal Mode\""),
|
525
|
-
self.
|
526
|
-
self.tr("Set to 0 to disable this feature."),
|
527
|
-
unit=self.tr("px")
|
398
|
+
self.tr("Maximum text width in \"Normal Mode\""), self.textWidth,
|
399
|
+
self.tr("Set to 0 to disable this feature."), unit=self.tr("px")
|
528
400
|
)
|
529
401
|
|
530
402
|
# Max Text Width in Focus Mode
|
531
|
-
self.focusWidth =
|
403
|
+
self.focusWidth = NSpinBox(self)
|
532
404
|
self.focusWidth.setMinimum(200)
|
533
405
|
self.focusWidth.setMaximum(10000)
|
534
406
|
self.focusWidth.setSingleStep(10)
|
535
407
|
self.focusWidth.setValue(CONFIG.focusWidth)
|
536
408
|
self.mainForm.addRow(
|
537
|
-
self.tr("Maximum text width in \"Focus Mode\""),
|
538
|
-
self.
|
539
|
-
self.tr("The maximum width cannot be disabled."),
|
540
|
-
unit=self.tr("px")
|
409
|
+
self.tr("Maximum text width in \"Focus Mode\""), self.focusWidth,
|
410
|
+
self.tr("The maximum width cannot be disabled."), unit=self.tr("px")
|
541
411
|
)
|
542
412
|
|
543
413
|
# Focus Mode Footer
|
544
|
-
self.hideFocusFooter = NSwitch()
|
414
|
+
self.hideFocusFooter = NSwitch(self)
|
545
415
|
self.hideFocusFooter.setChecked(CONFIG.hideFocusFooter)
|
546
416
|
self.mainForm.addRow(
|
547
|
-
self.tr("Hide document footer in \"Focus Mode\""),
|
548
|
-
self.hideFocusFooter,
|
417
|
+
self.tr("Hide document footer in \"Focus Mode\""), self.hideFocusFooter,
|
549
418
|
self.tr("Hide the information bar in the document editor.")
|
550
419
|
)
|
551
420
|
|
552
421
|
# Justify Text
|
553
|
-
self.doJustify = NSwitch()
|
422
|
+
self.doJustify = NSwitch(self)
|
554
423
|
self.doJustify.setChecked(CONFIG.doJustify)
|
555
424
|
self.mainForm.addRow(
|
556
|
-
self.tr("Justify the text margins"),
|
557
|
-
self.doJustify,
|
425
|
+
self.tr("Justify the text margins"), self.doJustify,
|
558
426
|
self.tr("Applies to both document editor and viewer."),
|
559
427
|
)
|
560
428
|
|
561
429
|
# Document Margins
|
562
|
-
self.textMargin =
|
430
|
+
self.textMargin = NSpinBox(self)
|
563
431
|
self.textMargin.setMinimum(0)
|
564
432
|
self.textMargin.setMaximum(900)
|
565
433
|
self.textMargin.setSingleStep(1)
|
566
434
|
self.textMargin.setValue(CONFIG.textMargin)
|
567
435
|
self.mainForm.addRow(
|
568
|
-
self.tr("Minimum text margin"),
|
569
|
-
self.textMargin,
|
436
|
+
self.tr("Minimum text margin"), self.textMargin,
|
570
437
|
self.tr("Applies to both document editor and viewer."),
|
571
438
|
unit=self.tr("px")
|
572
439
|
)
|
573
440
|
|
574
441
|
# Tab Width
|
575
|
-
self.tabWidth =
|
442
|
+
self.tabWidth = NSpinBox(self)
|
576
443
|
self.tabWidth.setMinimum(0)
|
577
444
|
self.tabWidth.setMaximum(200)
|
578
445
|
self.tabWidth.setSingleStep(1)
|
579
446
|
self.tabWidth.setValue(CONFIG.tabWidth)
|
580
447
|
self.mainForm.addRow(
|
581
|
-
self.tr("Tab width"),
|
582
|
-
self.tabWidth,
|
448
|
+
self.tr("Tab width"), self.tabWidth,
|
583
449
|
self.tr("The width of a tab key press in the editor and viewer."),
|
584
450
|
unit=self.tr("px")
|
585
451
|
)
|
586
452
|
|
587
|
-
|
588
|
-
|
589
|
-
def saveValues(self) -> None:
|
590
|
-
"""Save the values set for this tab."""
|
591
|
-
# Text Style
|
592
|
-
CONFIG.setTextFont(self.textFont.text(), self.textSize.value())
|
593
|
-
|
594
|
-
# Text Flow
|
595
|
-
CONFIG.textWidth = self.textWidth.value()
|
596
|
-
CONFIG.focusWidth = self.focusWidth.value()
|
597
|
-
CONFIG.hideFocusFooter = self.hideFocusFooter.isChecked()
|
598
|
-
CONFIG.doJustify = self.doJustify.isChecked()
|
599
|
-
CONFIG.textMargin = self.textMargin.value()
|
600
|
-
CONFIG.tabWidth = self.tabWidth.value()
|
601
|
-
|
602
|
-
return
|
603
|
-
|
604
|
-
##
|
605
|
-
# Private Slots
|
606
|
-
##
|
607
|
-
|
608
|
-
@pyqtSlot()
|
609
|
-
def _selectFont(self):
|
610
|
-
"""Open the QFontDialog and set a font for the font style."""
|
611
|
-
currFont = QFont()
|
612
|
-
currFont.setFamily(CONFIG.textFont)
|
613
|
-
currFont.setPointSize(CONFIG.textSize)
|
614
|
-
theFont, theStatus = QFontDialog.getFont(currFont, self)
|
615
|
-
if theStatus:
|
616
|
-
self.textFont.setText(theFont.family())
|
617
|
-
self.textSize.setValue(theFont.pointSize())
|
618
|
-
|
619
|
-
return
|
620
|
-
|
621
|
-
# END Class GuiPreferencesDocuments
|
622
|
-
|
623
|
-
|
624
|
-
class GuiPreferencesEditor(QWidget):
|
625
|
-
|
626
|
-
def __init__(self, prefsGui: GuiPreferences) -> None:
|
627
|
-
super().__init__(parent=prefsGui)
|
628
|
-
|
629
|
-
# The Form
|
630
|
-
self.mainForm = NConfigLayout()
|
631
|
-
self.mainForm.setHelpTextStyle(SHARED.theme.helpText)
|
632
|
-
self.setLayout(self.mainForm)
|
453
|
+
# Text Editing
|
454
|
+
# ============
|
633
455
|
|
634
|
-
|
456
|
+
title = self.tr("Text Editing")
|
457
|
+
section += 1
|
458
|
+
self.sidebar.addButton(title, section)
|
459
|
+
self.mainForm.addGroupLabel(title, section)
|
635
460
|
|
636
461
|
# Spell Checking
|
637
|
-
|
638
|
-
self.
|
639
|
-
|
640
|
-
# Spell Check Provider and Language
|
641
|
-
self.spellLanguage = QComboBox(self)
|
642
|
-
self.spellLanguage.setMaximumWidth(mW)
|
462
|
+
self.spellLanguage = NComboBox(self)
|
463
|
+
self.spellLanguage.setMinimumWidth(minWidth)
|
643
464
|
|
644
465
|
if CONFIG.hasEnchant:
|
645
466
|
for tag, language in SHARED.spelling.listDictionaries():
|
646
467
|
self.spellLanguage.addItem(language, tag)
|
647
468
|
else:
|
648
|
-
self.spellLanguage.addItem(
|
469
|
+
self.spellLanguage.addItem(nwUnicode.U_EMDASH, "")
|
649
470
|
self.spellLanguage.setEnabled(False)
|
650
471
|
|
651
|
-
|
652
|
-
|
653
|
-
self.spellLanguage.setCurrentIndex(spellIdx)
|
472
|
+
if (idx := self.spellLanguage.findData(CONFIG.spellLanguage)) != -1:
|
473
|
+
self.spellLanguage.setCurrentIndex(idx)
|
654
474
|
|
655
475
|
self.mainForm.addRow(
|
656
|
-
self.tr("Spell check language"),
|
657
|
-
self.
|
658
|
-
self.tr("Available languages are determined by your system.")
|
659
|
-
)
|
660
|
-
|
661
|
-
# Word Count
|
662
|
-
# ==========
|
663
|
-
self.mainForm.addGroupLabel(self.tr("Word Count"))
|
664
|
-
|
665
|
-
# Word Count Timer
|
666
|
-
self.wordCountTimer = QDoubleSpinBox(self)
|
667
|
-
self.wordCountTimer.setDecimals(1)
|
668
|
-
self.wordCountTimer.setMinimum(2.0)
|
669
|
-
self.wordCountTimer.setMaximum(600.0)
|
670
|
-
self.wordCountTimer.setSingleStep(0.1)
|
671
|
-
self.wordCountTimer.setValue(CONFIG.wordCountTimer)
|
672
|
-
self.mainForm.addRow(
|
673
|
-
self.tr("Word count interval"),
|
674
|
-
self.wordCountTimer,
|
675
|
-
unit=self.tr("seconds")
|
476
|
+
self.tr("Spell check language"), self.spellLanguage,
|
477
|
+
self.tr("Available languages are determined by your system."), stretch=(3, 2)
|
676
478
|
)
|
677
479
|
|
678
|
-
#
|
679
|
-
self.
|
680
|
-
self.
|
480
|
+
# Auto-Select Word Under Cursor
|
481
|
+
self.autoSelect = NSwitch(self)
|
482
|
+
self.autoSelect.setChecked(CONFIG.autoSelect)
|
681
483
|
self.mainForm.addRow(
|
682
|
-
self.tr("
|
683
|
-
self.
|
484
|
+
self.tr("Auto-select word under cursor"), self.autoSelect,
|
485
|
+
self.tr("Apply formatting to word under cursor if no selection is made.")
|
684
486
|
)
|
685
487
|
|
686
|
-
# Writing Guides
|
687
|
-
# ==============
|
688
|
-
self.mainForm.addGroupLabel(self.tr("Writing Guides"))
|
689
|
-
|
690
488
|
# Show Tabs and Spaces
|
691
|
-
self.showTabsNSpaces = NSwitch()
|
489
|
+
self.showTabsNSpaces = NSwitch(self)
|
692
490
|
self.showTabsNSpaces.setChecked(CONFIG.showTabsNSpaces)
|
693
491
|
self.mainForm.addRow(
|
694
|
-
self.tr("Show tabs and spaces"),
|
695
|
-
self.showTabsNSpaces
|
492
|
+
self.tr("Show tabs and spaces"), self.showTabsNSpaces
|
696
493
|
)
|
697
494
|
|
698
495
|
# Show Line Endings
|
699
|
-
self.showLineEndings = NSwitch()
|
496
|
+
self.showLineEndings = NSwitch(self)
|
700
497
|
self.showLineEndings.setChecked(CONFIG.showLineEndings)
|
701
498
|
self.mainForm.addRow(
|
702
|
-
self.tr("Show line endings"),
|
703
|
-
self.showLineEndings
|
499
|
+
self.tr("Show line endings"), self.showLineEndings
|
704
500
|
)
|
705
501
|
|
706
|
-
#
|
502
|
+
# Editor Scrolling
|
707
503
|
# ================
|
708
|
-
|
504
|
+
|
505
|
+
title = self.tr("Editor Scrolling")
|
506
|
+
section += 1
|
507
|
+
self.sidebar.addButton(title, section)
|
508
|
+
self.mainForm.addGroupLabel(title, section)
|
709
509
|
|
710
510
|
# Scroll Past End
|
711
|
-
self.scrollPastEnd = NSwitch()
|
511
|
+
self.scrollPastEnd = NSwitch(self)
|
712
512
|
self.scrollPastEnd.setChecked(CONFIG.scrollPastEnd)
|
713
513
|
self.mainForm.addRow(
|
714
|
-
self.tr("Scroll past end of the document"),
|
715
|
-
self.scrollPastEnd,
|
514
|
+
self.tr("Scroll past end of the document"), self.scrollPastEnd,
|
716
515
|
self.tr("Also centres the cursor when scrolling.")
|
717
516
|
)
|
718
517
|
|
719
518
|
# Typewriter Scrolling
|
720
|
-
self.autoScroll = NSwitch()
|
519
|
+
self.autoScroll = NSwitch(self)
|
721
520
|
self.autoScroll.setChecked(CONFIG.autoScroll)
|
722
521
|
self.mainForm.addRow(
|
723
|
-
self.tr("Typewriter style scrolling when you type"),
|
724
|
-
self.autoScroll,
|
522
|
+
self.tr("Typewriter style scrolling when you type"), self.autoScroll,
|
725
523
|
self.tr("Keeps the cursor at a fixed vertical position.")
|
726
524
|
)
|
727
525
|
|
728
526
|
# Typewriter Position
|
729
|
-
self.autoScrollPos =
|
527
|
+
self.autoScrollPos = NSpinBox(self)
|
730
528
|
self.autoScrollPos.setMinimum(10)
|
731
529
|
self.autoScrollPos.setMaximum(90)
|
732
530
|
self.autoScrollPos.setSingleStep(1)
|
733
531
|
self.autoScrollPos.setValue(int(CONFIG.autoScrollPos))
|
734
532
|
self.mainForm.addRow(
|
735
|
-
self.tr("Minimum position for Typewriter scrolling"),
|
736
|
-
self.
|
737
|
-
self.tr("Percentage of the editor height from the top."),
|
738
|
-
unit="%"
|
533
|
+
self.tr("Minimum position for Typewriter scrolling"), self.autoScrollPos,
|
534
|
+
self.tr("Percentage of the editor height from the top."), unit="%"
|
739
535
|
)
|
740
536
|
|
741
|
-
|
742
|
-
|
743
|
-
def saveValues(self) -> None:
|
744
|
-
"""Save the values set for this tab."""
|
745
|
-
# Spell Checking
|
746
|
-
CONFIG.spellLanguage = self.spellLanguage.currentData()
|
747
|
-
|
748
|
-
# Word Count
|
749
|
-
CONFIG.wordCountTimer = self.wordCountTimer.value()
|
750
|
-
CONFIG.incNotesWCount = self.incNotesWCount.isChecked()
|
751
|
-
|
752
|
-
# Writing Guides
|
753
|
-
CONFIG.showTabsNSpaces = self.showTabsNSpaces.isChecked()
|
754
|
-
CONFIG.showLineEndings = self.showLineEndings.isChecked()
|
755
|
-
|
756
|
-
# Scroll Behaviour
|
757
|
-
CONFIG.autoScroll = self.autoScroll.isChecked()
|
758
|
-
CONFIG.autoScrollPos = self.autoScrollPos.value()
|
759
|
-
CONFIG.scrollPastEnd = self.scrollPastEnd.isChecked()
|
760
|
-
|
761
|
-
return
|
762
|
-
|
763
|
-
# END Class GuiPreferencesEditor
|
764
|
-
|
765
|
-
|
766
|
-
class GuiPreferencesSyntax(QWidget):
|
767
|
-
|
768
|
-
def __init__(self, prefsGui: GuiPreferences) -> None:
|
769
|
-
super().__init__(parent=prefsGui)
|
770
|
-
|
771
|
-
self.prefsGui = prefsGui
|
772
|
-
|
773
|
-
# The Form
|
774
|
-
self.mainForm = NConfigLayout()
|
775
|
-
self.mainForm.setHelpTextStyle(SHARED.theme.helpText)
|
776
|
-
self.setLayout(self.mainForm)
|
777
|
-
|
778
|
-
# Quotes & Dialogue
|
537
|
+
# Text Highlighting
|
779
538
|
# =================
|
780
|
-
self.mainForm.addGroupLabel(self.tr("Quotes & Dialogue"))
|
781
539
|
|
782
|
-
|
540
|
+
title = self.tr("Text Highlighting")
|
541
|
+
section += 1
|
542
|
+
self.sidebar.addButton(title, section)
|
543
|
+
self.mainForm.addGroupLabel(title, section)
|
544
|
+
|
545
|
+
self.highlightQuotes = NSwitch(self)
|
783
546
|
self.highlightQuotes.setChecked(CONFIG.highlightQuotes)
|
784
547
|
self.highlightQuotes.toggled.connect(self._toggleHighlightQuotes)
|
785
548
|
self.mainForm.addRow(
|
786
|
-
self.tr("Highlight text wrapped in quotes"),
|
787
|
-
self.highlightQuotes,
|
549
|
+
self.tr("Highlight text wrapped in quotes"), self.highlightQuotes,
|
788
550
|
self.tr("Applies to the document editor only.")
|
789
551
|
)
|
790
552
|
|
791
|
-
self.allowOpenSQuote = NSwitch()
|
553
|
+
self.allowOpenSQuote = NSwitch(self)
|
792
554
|
self.allowOpenSQuote.setChecked(CONFIG.allowOpenSQuote)
|
793
555
|
self.mainForm.addRow(
|
794
|
-
self.tr("Allow open-ended single quotes"),
|
795
|
-
self.allowOpenSQuote,
|
556
|
+
self.tr("Allow open-ended single quotes"), self.allowOpenSQuote,
|
796
557
|
self.tr("Highlight single-quoted line with no closing quote.")
|
797
558
|
)
|
798
559
|
|
799
|
-
self.allowOpenDQuote = NSwitch()
|
560
|
+
self.allowOpenDQuote = NSwitch(self)
|
800
561
|
self.allowOpenDQuote.setChecked(CONFIG.allowOpenDQuote)
|
801
562
|
self.mainForm.addRow(
|
802
|
-
self.tr("Allow open-ended double quotes"),
|
803
|
-
self.allowOpenDQuote,
|
563
|
+
self.tr("Allow open-ended double quotes"), self.allowOpenDQuote,
|
804
564
|
self.tr("Highlight double-quoted line with no closing quote.")
|
805
565
|
)
|
806
566
|
|
807
|
-
|
808
|
-
# =============
|
809
|
-
self.mainForm.addGroupLabel(self.tr("Text Emphasis"))
|
810
|
-
|
811
|
-
self.highlightEmph = NSwitch()
|
567
|
+
self.highlightEmph = NSwitch(self)
|
812
568
|
self.highlightEmph.setChecked(CONFIG.highlightEmph)
|
813
569
|
self.mainForm.addRow(
|
814
|
-
self.tr("Add highlight colour to emphasised text"),
|
815
|
-
self.highlightEmph,
|
570
|
+
self.tr("Add highlight colour to emphasised text"), self.highlightEmph,
|
816
571
|
self.tr("Applies to the document editor only.")
|
817
572
|
)
|
818
573
|
|
819
|
-
|
820
|
-
# ===========
|
821
|
-
|
822
|
-
self.mainForm.addGroupLabel(self.tr("Text Errors"))
|
823
|
-
|
824
|
-
self.showMultiSpaces = NSwitch()
|
574
|
+
self.showMultiSpaces = NSwitch(self)
|
825
575
|
self.showMultiSpaces.setChecked(CONFIG.showMultiSpaces)
|
826
576
|
self.mainForm.addRow(
|
827
|
-
self.tr("Highlight multiple or trailing spaces"),
|
828
|
-
self.showMultiSpaces,
|
577
|
+
self.tr("Highlight multiple or trailing spaces"), self.showMultiSpaces,
|
829
578
|
self.tr("Applies to the document editor only.")
|
830
579
|
)
|
831
580
|
|
832
|
-
|
833
|
-
|
834
|
-
def saveValues(self) -> None:
|
835
|
-
"""Save the values set for this tab."""
|
836
|
-
highlightQuotes = self.highlightQuotes.isChecked()
|
837
|
-
allowOpenSQuote = self.allowOpenSQuote.isChecked()
|
838
|
-
allowOpenDQuote = self.allowOpenDQuote.isChecked()
|
839
|
-
highlightEmph = self.highlightEmph.isChecked()
|
840
|
-
showMultiSpaces = self.showMultiSpaces.isChecked()
|
841
|
-
|
842
|
-
self.prefsGui._updateSyntax |= CONFIG.highlightQuotes != highlightQuotes
|
843
|
-
self.prefsGui._updateSyntax |= CONFIG.highlightEmph != highlightEmph
|
844
|
-
self.prefsGui._updateSyntax |= CONFIG.showMultiSpaces != showMultiSpaces
|
845
|
-
|
846
|
-
CONFIG.highlightQuotes = highlightQuotes
|
847
|
-
CONFIG.allowOpenSQuote = allowOpenSQuote
|
848
|
-
CONFIG.allowOpenDQuote = allowOpenDQuote
|
849
|
-
CONFIG.highlightEmph = highlightEmph
|
850
|
-
CONFIG.showMultiSpaces = showMultiSpaces
|
851
|
-
|
852
|
-
return
|
853
|
-
|
854
|
-
##
|
855
|
-
# Private Slots
|
856
|
-
##
|
857
|
-
|
858
|
-
@pyqtSlot(bool)
|
859
|
-
def _toggleHighlightQuotes(self, state: bool) -> None:
|
860
|
-
"""Toggle switches controlled by the highlight quotes switch."""
|
861
|
-
self.allowOpenSQuote.setEnabled(state)
|
862
|
-
self.allowOpenDQuote.setEnabled(state)
|
863
|
-
return
|
864
|
-
|
865
|
-
# END Class GuiPreferencesSyntax
|
866
|
-
|
867
|
-
|
868
|
-
class GuiPreferencesAutomation(QWidget):
|
869
|
-
|
870
|
-
def __init__(self, prefsGui: GuiPreferences) -> None:
|
871
|
-
super().__init__(parent=prefsGui)
|
581
|
+
# Text Automation
|
582
|
+
# ===============
|
872
583
|
|
873
|
-
|
874
|
-
|
875
|
-
self.
|
876
|
-
self.
|
584
|
+
title = self.tr("Text Automation")
|
585
|
+
section += 1
|
586
|
+
self.sidebar.addButton(title, section)
|
587
|
+
self.mainForm.addGroupLabel(title, section)
|
877
588
|
|
878
|
-
|
879
|
-
# ==================
|
880
|
-
self.mainForm.addGroupLabel(self.tr("Automatic Features"))
|
881
|
-
|
882
|
-
# Auto-Select Word Under Cursor
|
883
|
-
self.autoSelect = NSwitch()
|
884
|
-
self.autoSelect.setChecked(CONFIG.autoSelect)
|
885
|
-
self.mainForm.addRow(
|
886
|
-
self.tr("Auto-select word under cursor"),
|
887
|
-
self.autoSelect,
|
888
|
-
self.tr("Apply formatting to word under cursor if no selection is made.")
|
889
|
-
)
|
589
|
+
boxWidth = CONFIG.pxInt(150)
|
890
590
|
|
891
591
|
# Auto-Replace as You Type Main Switch
|
892
|
-
self.doReplace = NSwitch()
|
592
|
+
self.doReplace = NSwitch(self)
|
893
593
|
self.doReplace.setChecked(CONFIG.doReplace)
|
894
594
|
self.doReplace.toggled.connect(self._toggleAutoReplaceMain)
|
895
595
|
self.mainForm.addRow(
|
896
|
-
self.tr("Auto-replace text as you type"),
|
897
|
-
self.doReplace,
|
596
|
+
self.tr("Auto-replace text as you type"), self.doReplace,
|
898
597
|
self.tr("Allow the editor to replace symbols as you type.")
|
899
598
|
)
|
900
599
|
|
901
|
-
# Replace as You Type
|
902
|
-
# ===================
|
903
|
-
self.mainForm.addGroupLabel(self.tr("Replace as You Type"))
|
904
|
-
|
905
600
|
# Auto-Replace Single Quotes
|
906
|
-
self.doReplaceSQuote = NSwitch()
|
601
|
+
self.doReplaceSQuote = NSwitch(self)
|
907
602
|
self.doReplaceSQuote.setChecked(CONFIG.doReplaceSQuote)
|
908
603
|
self.doReplaceSQuote.setEnabled(CONFIG.doReplace)
|
909
604
|
self.mainForm.addRow(
|
910
|
-
self.tr("Auto-replace single quotes"),
|
911
|
-
self.doReplaceSQuote,
|
605
|
+
self.tr("Auto-replace single quotes"), self.doReplaceSQuote,
|
912
606
|
self.tr("Try to guess which is an opening or a closing quote.")
|
913
607
|
)
|
914
608
|
|
915
609
|
# Auto-Replace Double Quotes
|
916
|
-
self.doReplaceDQuote = NSwitch()
|
610
|
+
self.doReplaceDQuote = NSwitch(self)
|
917
611
|
self.doReplaceDQuote.setChecked(CONFIG.doReplaceDQuote)
|
918
612
|
self.doReplaceDQuote.setEnabled(CONFIG.doReplace)
|
919
613
|
self.mainForm.addRow(
|
920
|
-
self.tr("Auto-replace double quotes"),
|
921
|
-
self.doReplaceDQuote,
|
614
|
+
self.tr("Auto-replace double quotes"), self.doReplaceDQuote,
|
922
615
|
self.tr("Try to guess which is an opening or a closing quote.")
|
923
616
|
)
|
924
617
|
|
925
618
|
# Auto-Replace Hyphens
|
926
|
-
self.doReplaceDash = NSwitch()
|
619
|
+
self.doReplaceDash = NSwitch(self)
|
927
620
|
self.doReplaceDash.setChecked(CONFIG.doReplaceDash)
|
928
621
|
self.doReplaceDash.setEnabled(CONFIG.doReplace)
|
929
622
|
self.mainForm.addRow(
|
930
|
-
self.tr("Auto-replace dashes"),
|
931
|
-
self.doReplaceDash,
|
623
|
+
self.tr("Auto-replace dashes"), self.doReplaceDash,
|
932
624
|
self.tr("Double and triple hyphens become short and long dashes.")
|
933
625
|
)
|
934
626
|
|
935
627
|
# Auto-Replace Dots
|
936
|
-
self.doReplaceDots = NSwitch()
|
628
|
+
self.doReplaceDots = NSwitch(self)
|
937
629
|
self.doReplaceDots.setChecked(CONFIG.doReplaceDots)
|
938
630
|
self.doReplaceDots.setEnabled(CONFIG.doReplace)
|
939
631
|
self.mainForm.addRow(
|
940
|
-
self.tr("Auto-replace dots"),
|
941
|
-
self.doReplaceDots,
|
632
|
+
self.tr("Auto-replace dots"), self.doReplaceDots,
|
942
633
|
self.tr("Three consecutive dots become ellipsis.")
|
943
634
|
)
|
944
635
|
|
945
|
-
# Automatic Padding
|
946
|
-
# =================
|
947
|
-
self.mainForm.addGroupLabel(self.tr("Automatic Padding"))
|
948
|
-
|
949
636
|
# Pad Before
|
950
637
|
self.fmtPadBefore = QLineEdit(self)
|
951
638
|
self.fmtPadBefore.setMaxLength(32)
|
639
|
+
self.fmtPadBefore.setMinimumWidth(boxWidth)
|
952
640
|
self.fmtPadBefore.setText(CONFIG.fmtPadBefore)
|
953
641
|
self.mainForm.addRow(
|
954
|
-
self.tr("Insert non-breaking space before"),
|
955
|
-
self.
|
956
|
-
self.tr("Automatically add space before any of these symbols."),
|
642
|
+
self.tr("Insert non-breaking space before"), self.fmtPadBefore,
|
643
|
+
self.tr("Automatically add space before any of these symbols."), stretch=(2, 1)
|
957
644
|
)
|
958
645
|
|
959
646
|
# Pad After
|
960
647
|
self.fmtPadAfter = QLineEdit(self)
|
961
648
|
self.fmtPadAfter.setMaxLength(32)
|
649
|
+
self.fmtPadAfter.setMinimumWidth(boxWidth)
|
962
650
|
self.fmtPadAfter.setText(CONFIG.fmtPadAfter)
|
963
651
|
self.mainForm.addRow(
|
964
|
-
self.tr("Insert non-breaking space after"),
|
965
|
-
self.
|
966
|
-
self.tr("Automatically add space after any of these symbols."),
|
652
|
+
self.tr("Insert non-breaking space after"), self.fmtPadAfter,
|
653
|
+
self.tr("Automatically add space after any of these symbols."), stretch=(2, 1)
|
967
654
|
)
|
968
655
|
|
969
656
|
# Use Thin Space
|
970
|
-
self.fmtPadThin = NSwitch()
|
657
|
+
self.fmtPadThin = NSwitch(self)
|
971
658
|
self.fmtPadThin.setChecked(CONFIG.fmtPadThin)
|
972
659
|
self.fmtPadThin.setEnabled(CONFIG.doReplace)
|
973
660
|
self.mainForm.addRow(
|
974
|
-
self.tr("Use thin space instead"),
|
975
|
-
self.fmtPadThin,
|
661
|
+
self.tr("Use thin space instead"), self.fmtPadThin,
|
976
662
|
self.tr("Inserts a thin space instead of a regular space.")
|
977
663
|
)
|
978
664
|
|
979
|
-
return
|
980
|
-
|
981
|
-
def saveValues(self) -> None:
|
982
|
-
"""Save the values set for this tab."""
|
983
|
-
# Automatic Features
|
984
|
-
CONFIG.autoSelect = self.autoSelect.isChecked()
|
985
|
-
CONFIG.doReplace = self.doReplace.isChecked()
|
986
|
-
|
987
|
-
# Replace as You Type
|
988
|
-
CONFIG.doReplaceSQuote = self.doReplaceSQuote.isChecked()
|
989
|
-
CONFIG.doReplaceDQuote = self.doReplaceDQuote.isChecked()
|
990
|
-
CONFIG.doReplaceDash = self.doReplaceDash.isChecked()
|
991
|
-
CONFIG.doReplaceDots = self.doReplaceDots.isChecked()
|
992
|
-
|
993
|
-
# Automatic Padding
|
994
|
-
CONFIG.fmtPadBefore = self.fmtPadBefore.text().strip()
|
995
|
-
CONFIG.fmtPadAfter = self.fmtPadAfter.text().strip()
|
996
|
-
CONFIG.fmtPadThin = self.fmtPadThin.isChecked()
|
997
|
-
|
998
|
-
return
|
999
|
-
|
1000
|
-
##
|
1001
|
-
# Private Slots
|
1002
|
-
##
|
1003
|
-
|
1004
|
-
@pyqtSlot(bool)
|
1005
|
-
def _toggleAutoReplaceMain(self, state: bool) -> None:
|
1006
|
-
"""Toggle switches controlled by the auto replace switch."""
|
1007
|
-
self.doReplaceSQuote.setEnabled(state)
|
1008
|
-
self.doReplaceDQuote.setEnabled(state)
|
1009
|
-
self.doReplaceDash.setEnabled(state)
|
1010
|
-
self.doReplaceDots.setEnabled(state)
|
1011
|
-
self.fmtPadThin.setEnabled(state)
|
1012
|
-
return
|
1013
|
-
|
1014
|
-
# END Class GuiPreferencesAutomation
|
1015
|
-
|
1016
|
-
|
1017
|
-
class GuiPreferencesQuotes(QWidget):
|
1018
|
-
|
1019
|
-
def __init__(self, prefsGui: GuiPreferences) -> None:
|
1020
|
-
super().__init__(parent=prefsGui)
|
1021
|
-
|
1022
|
-
# The Form
|
1023
|
-
self.mainForm = NConfigLayout()
|
1024
|
-
self.mainForm.setHelpTextStyle(SHARED.theme.helpText)
|
1025
|
-
self.setLayout(self.mainForm)
|
1026
|
-
|
1027
665
|
# Quotation Style
|
1028
666
|
# ===============
|
1029
|
-
self.mainForm.addGroupLabel(self.tr("Quotation Style"))
|
1030
667
|
|
1031
|
-
|
1032
|
-
|
668
|
+
title = self.tr("Quotation Style")
|
669
|
+
section += 1
|
670
|
+
self.sidebar.addButton(title, section)
|
671
|
+
self.mainForm.addGroupLabel(title, section)
|
672
|
+
|
1033
673
|
self.quoteSym = {}
|
674
|
+
qWidth = CONFIG.pxInt(40)
|
1034
675
|
|
1035
676
|
# Single Quote Style
|
1036
677
|
self.quoteSym["SO"] = QLineEdit(self)
|
@@ -1039,12 +680,11 @@ class GuiPreferencesQuotes(QWidget):
|
|
1039
680
|
self.quoteSym["SO"].setFixedWidth(qWidth)
|
1040
681
|
self.quoteSym["SO"].setAlignment(Qt.AlignCenter)
|
1041
682
|
self.quoteSym["SO"].setText(CONFIG.fmtSQuoteOpen)
|
1042
|
-
self.btnSingleStyleO =
|
1043
|
-
self.btnSingleStyleO.
|
683
|
+
self.btnSingleStyleO = QToolButton(self)
|
684
|
+
self.btnSingleStyleO.setIcon(mIcon)
|
1044
685
|
self.btnSingleStyleO.clicked.connect(lambda: self._getQuote("SO"))
|
1045
686
|
self.mainForm.addRow(
|
1046
|
-
self.tr("Single quote open style"),
|
1047
|
-
self.quoteSym["SO"],
|
687
|
+
self.tr("Single quote open style"), self.quoteSym["SO"],
|
1048
688
|
self.tr("The symbol to use for a leading single quote."),
|
1049
689
|
button=self.btnSingleStyleO
|
1050
690
|
)
|
@@ -1055,12 +695,11 @@ class GuiPreferencesQuotes(QWidget):
|
|
1055
695
|
self.quoteSym["SC"].setFixedWidth(qWidth)
|
1056
696
|
self.quoteSym["SC"].setAlignment(Qt.AlignCenter)
|
1057
697
|
self.quoteSym["SC"].setText(CONFIG.fmtSQuoteClose)
|
1058
|
-
self.btnSingleStyleC =
|
1059
|
-
self.btnSingleStyleC.
|
698
|
+
self.btnSingleStyleC = QToolButton(self)
|
699
|
+
self.btnSingleStyleC.setIcon(mIcon)
|
1060
700
|
self.btnSingleStyleC.clicked.connect(lambda: self._getQuote("SC"))
|
1061
701
|
self.mainForm.addRow(
|
1062
|
-
self.tr("Single quote close style"),
|
1063
|
-
self.quoteSym["SC"],
|
702
|
+
self.tr("Single quote close style"), self.quoteSym["SC"],
|
1064
703
|
self.tr("The symbol to use for a trailing single quote."),
|
1065
704
|
button=self.btnSingleStyleC
|
1066
705
|
)
|
@@ -1072,12 +711,11 @@ class GuiPreferencesQuotes(QWidget):
|
|
1072
711
|
self.quoteSym["DO"].setFixedWidth(qWidth)
|
1073
712
|
self.quoteSym["DO"].setAlignment(Qt.AlignCenter)
|
1074
713
|
self.quoteSym["DO"].setText(CONFIG.fmtDQuoteOpen)
|
1075
|
-
self.btnDoubleStyleO =
|
1076
|
-
self.btnDoubleStyleO.
|
714
|
+
self.btnDoubleStyleO = QToolButton(self)
|
715
|
+
self.btnDoubleStyleO.setIcon(mIcon)
|
1077
716
|
self.btnDoubleStyleO.clicked.connect(lambda: self._getQuote("DO"))
|
1078
717
|
self.mainForm.addRow(
|
1079
|
-
self.tr("Double quote open style"),
|
1080
|
-
self.quoteSym["DO"],
|
718
|
+
self.tr("Double quote open style"), self.quoteSym["DO"],
|
1081
719
|
self.tr("The symbol to use for a leading double quote."),
|
1082
720
|
button=self.btnDoubleStyleO
|
1083
721
|
)
|
@@ -1088,37 +726,249 @@ class GuiPreferencesQuotes(QWidget):
|
|
1088
726
|
self.quoteSym["DC"].setFixedWidth(qWidth)
|
1089
727
|
self.quoteSym["DC"].setAlignment(Qt.AlignCenter)
|
1090
728
|
self.quoteSym["DC"].setText(CONFIG.fmtDQuoteClose)
|
1091
|
-
self.btnDoubleStyleC =
|
1092
|
-
self.btnDoubleStyleC.
|
729
|
+
self.btnDoubleStyleC = QToolButton(self)
|
730
|
+
self.btnDoubleStyleC.setIcon(mIcon)
|
1093
731
|
self.btnDoubleStyleC.clicked.connect(lambda: self._getQuote("DC"))
|
1094
732
|
self.mainForm.addRow(
|
1095
|
-
self.tr("Double quote close style"),
|
1096
|
-
self.quoteSym["DC"],
|
733
|
+
self.tr("Double quote close style"), self.quoteSym["DC"],
|
1097
734
|
self.tr("The symbol to use for a trailing double quote."),
|
1098
735
|
button=self.btnDoubleStyleC
|
1099
736
|
)
|
1100
737
|
|
738
|
+
self.mainForm.finalise()
|
739
|
+
self.sidebar.setSelected(1)
|
740
|
+
|
1101
741
|
return
|
1102
742
|
|
1103
|
-
|
1104
|
-
|
1105
|
-
|
1106
|
-
|
1107
|
-
|
1108
|
-
|
1109
|
-
|
743
|
+
##
|
744
|
+
# Events
|
745
|
+
##
|
746
|
+
|
747
|
+
def closeEvent(self, event: QCloseEvent) -> None:
|
748
|
+
"""Capture the close event and perform cleanup."""
|
749
|
+
logger.debug("Close: GuiPreferences")
|
750
|
+
self._saveWindowSize()
|
751
|
+
event.accept()
|
752
|
+
qApp.processEvents()
|
753
|
+
self.done(nwConst.DLG_FINISHED)
|
754
|
+
self.deleteLater()
|
755
|
+
return
|
756
|
+
|
757
|
+
def keyPressEvent(self, event: QKeyEvent) -> None:
|
758
|
+
"""Overload keyPressEvent to block enter key to save."""
|
759
|
+
if event.matches(QKeySequence.StandardKey.Cancel):
|
760
|
+
self.close()
|
761
|
+
event.ignore()
|
1110
762
|
return
|
1111
763
|
|
1112
764
|
##
|
1113
|
-
#
|
765
|
+
# Private Slots
|
1114
766
|
##
|
1115
767
|
|
768
|
+
@pyqtSlot("QAbstractButton*")
|
769
|
+
def _dialogButtonClicked(self, button: QAbstractButton) -> None:
|
770
|
+
"""Handle button clicks from the dialog button box."""
|
771
|
+
role = self.buttonBox.buttonRole(button)
|
772
|
+
if role == QDialogButtonBox.ButtonRole.ApplyRole:
|
773
|
+
self._saveValues()
|
774
|
+
elif role == QDialogButtonBox.ButtonRole.AcceptRole:
|
775
|
+
self._saveValues()
|
776
|
+
self.close()
|
777
|
+
elif role == QDialogButtonBox.ButtonRole.RejectRole:
|
778
|
+
self.close()
|
779
|
+
return
|
780
|
+
|
781
|
+
@pyqtSlot(int)
|
782
|
+
def _sidebarClicked(self, section: int) -> None:
|
783
|
+
"""Process a user request to switch page."""
|
784
|
+
self.mainForm.scrollToSection(section)
|
785
|
+
return
|
786
|
+
|
787
|
+
@pyqtSlot()
|
788
|
+
def _gotoSearch(self) -> None:
|
789
|
+
"""Go to the setting indicated by the search text."""
|
790
|
+
self.mainForm.scrollToLabel(self.searchText.text().strip())
|
791
|
+
return
|
792
|
+
|
793
|
+
@pyqtSlot()
|
794
|
+
def _selectGuiFont(self) -> None:
|
795
|
+
"""Open the QFontDialog and set a font for the font style."""
|
796
|
+
current = QFont()
|
797
|
+
current.setFamily(CONFIG.guiFont)
|
798
|
+
current.setPointSize(CONFIG.guiFontSize)
|
799
|
+
font, status = QFontDialog.getFont(current, self)
|
800
|
+
if status:
|
801
|
+
self.guiFont.setText(font.family())
|
802
|
+
self.guiFontSize.setValue(font.pointSize())
|
803
|
+
return
|
804
|
+
|
805
|
+
@pyqtSlot()
|
806
|
+
def _selectTextFont(self):
|
807
|
+
"""Open the QFontDialog and set a font for the font style."""
|
808
|
+
current = QFont()
|
809
|
+
current.setFamily(CONFIG.textFont)
|
810
|
+
current.setPointSize(CONFIG.textSize)
|
811
|
+
font, status = QFontDialog.getFont(current, self)
|
812
|
+
if status:
|
813
|
+
self.textFont.setText(font.family())
|
814
|
+
self.textSize.setValue(font.pointSize())
|
815
|
+
return
|
816
|
+
|
817
|
+
@pyqtSlot()
|
818
|
+
def _backupFolder(self) -> None:
|
819
|
+
"""Open a dialog to select the backup folder."""
|
820
|
+
if path := QFileDialog.getExistingDirectory(
|
821
|
+
self, self.tr("Backup Directory"), str(self.backupPath) or "",
|
822
|
+
options=QFileDialog.ShowDirsOnly
|
823
|
+
):
|
824
|
+
self.backupPath = path
|
825
|
+
self.mainForm.setHelpText("backupPath", self.tr("Path: {0}").format(path))
|
826
|
+
return
|
827
|
+
|
828
|
+
@pyqtSlot(bool)
|
829
|
+
def _toggledBackupOnClose(self, state: bool) -> None:
|
830
|
+
"""Toggle switch that depends on the backup on close switch."""
|
831
|
+
self.askBeforeBackup.setEnabled(state)
|
832
|
+
return
|
833
|
+
|
834
|
+
@pyqtSlot(bool)
|
835
|
+
def _toggleHighlightQuotes(self, state: bool) -> None:
|
836
|
+
"""Toggle switches controlled by the highlight quotes switch."""
|
837
|
+
self.allowOpenSQuote.setEnabled(state)
|
838
|
+
self.allowOpenDQuote.setEnabled(state)
|
839
|
+
return
|
840
|
+
|
841
|
+
@pyqtSlot(bool)
|
842
|
+
def _toggleAutoReplaceMain(self, state: bool) -> None:
|
843
|
+
"""Toggle switches controlled by the auto replace switch."""
|
844
|
+
self.doReplaceSQuote.setEnabled(state)
|
845
|
+
self.doReplaceDQuote.setEnabled(state)
|
846
|
+
self.doReplaceDash.setEnabled(state)
|
847
|
+
self.doReplaceDots.setEnabled(state)
|
848
|
+
self.fmtPadThin.setEnabled(state)
|
849
|
+
return
|
850
|
+
|
1116
851
|
def _getQuote(self, qType: str) -> None:
|
1117
852
|
"""Dialog for single quote open."""
|
1118
|
-
|
1119
|
-
if
|
1120
|
-
self.quoteSym[qType].setText(
|
853
|
+
quote, status = GuiQuoteSelect.getQuote(self, current=self.quoteSym[qType].text())
|
854
|
+
if status:
|
855
|
+
self.quoteSym[qType].setText(quote)
|
856
|
+
return
|
857
|
+
|
858
|
+
##
|
859
|
+
# Internal Functions
|
860
|
+
##
|
861
|
+
|
862
|
+
def _saveWindowSize(self) -> None:
|
863
|
+
"""Save the dialog window size."""
|
864
|
+
CONFIG.setPreferencesWinSize(self.width(), self.height())
|
865
|
+
return
|
866
|
+
|
867
|
+
def _saveValues(self) -> None:
|
868
|
+
"""Save the values set in the form."""
|
869
|
+
updateTheme = False
|
870
|
+
needsRestart = False
|
871
|
+
updateSyntax = False
|
872
|
+
refreshTree = False
|
873
|
+
|
874
|
+
# Appearance
|
875
|
+
guiLocale = self.guiLocale.currentData()
|
876
|
+
guiTheme = self.guiTheme.currentData()
|
877
|
+
guiFont = self.guiFont.text()
|
878
|
+
guiFontSize = self.guiFontSize.value()
|
879
|
+
|
880
|
+
updateTheme |= CONFIG.guiTheme != guiTheme
|
881
|
+
needsRestart |= CONFIG.guiLocale != guiLocale
|
882
|
+
needsRestart |= CONFIG.guiFont != guiFont
|
883
|
+
needsRestart |= CONFIG.guiFontSize != guiFontSize
|
884
|
+
|
885
|
+
CONFIG.guiLocale = guiLocale
|
886
|
+
CONFIG.guiTheme = guiTheme
|
887
|
+
CONFIG.guiFont = guiFont
|
888
|
+
CONFIG.guiFontSize = guiFontSize
|
889
|
+
CONFIG.hideVScroll = self.hideVScroll.isChecked()
|
890
|
+
CONFIG.hideHScroll = self.hideHScroll.isChecked()
|
891
|
+
|
892
|
+
# Document Style
|
893
|
+
guiSyntax = self.guiSyntax.currentData()
|
894
|
+
emphLabels = self.emphLabels.isChecked()
|
895
|
+
|
896
|
+
updateSyntax |= CONFIG.guiSyntax != guiSyntax
|
897
|
+
refreshTree |= CONFIG.emphLabels != emphLabels
|
898
|
+
|
899
|
+
CONFIG.guiSyntax = guiSyntax
|
900
|
+
CONFIG.emphLabels = emphLabels
|
901
|
+
CONFIG.showFullPath = self.showFullPath.isChecked()
|
902
|
+
CONFIG.incNotesWCount = self.incNotesWCount.isChecked()
|
903
|
+
CONFIG.setTextFont(self.textFont.text(), self.textSize.value())
|
904
|
+
|
905
|
+
# Auto Save
|
906
|
+
CONFIG.autoSaveDoc = self.autoSaveDoc.value()
|
907
|
+
CONFIG.autoSaveProj = self.autoSaveProj.value()
|
908
|
+
|
909
|
+
# Project Backup
|
910
|
+
CONFIG.setBackupPath(self.backupPath)
|
911
|
+
CONFIG.backupOnClose = self.backupOnClose.isChecked()
|
912
|
+
CONFIG.askBeforeBackup = self.askBeforeBackup.isChecked()
|
913
|
+
|
914
|
+
# Session Timer
|
915
|
+
CONFIG.stopWhenIdle = self.stopWhenIdle.isChecked()
|
916
|
+
CONFIG.userIdleTime = round(self.userIdleTime.value() * 60)
|
917
|
+
|
918
|
+
# Text Flow
|
919
|
+
CONFIG.textWidth = self.textWidth.value()
|
920
|
+
CONFIG.focusWidth = self.focusWidth.value()
|
921
|
+
CONFIG.hideFocusFooter = self.hideFocusFooter.isChecked()
|
922
|
+
CONFIG.doJustify = self.doJustify.isChecked()
|
923
|
+
CONFIG.textMargin = self.textMargin.value()
|
924
|
+
CONFIG.tabWidth = self.tabWidth.value()
|
925
|
+
|
926
|
+
# Text Editing
|
927
|
+
CONFIG.spellLanguage = self.spellLanguage.currentData()
|
928
|
+
CONFIG.autoSelect = self.autoSelect.isChecked()
|
929
|
+
CONFIG.showTabsNSpaces = self.showTabsNSpaces.isChecked()
|
930
|
+
CONFIG.showLineEndings = self.showLineEndings.isChecked()
|
931
|
+
|
932
|
+
# Editor Scrolling
|
933
|
+
CONFIG.autoScroll = self.autoScroll.isChecked()
|
934
|
+
CONFIG.autoScrollPos = self.autoScrollPos.value()
|
935
|
+
CONFIG.scrollPastEnd = self.scrollPastEnd.isChecked()
|
936
|
+
|
937
|
+
# Text Highlighting
|
938
|
+
highlightQuotes = self.highlightQuotes.isChecked()
|
939
|
+
highlightEmph = self.highlightEmph.isChecked()
|
940
|
+
showMultiSpaces = self.showMultiSpaces.isChecked()
|
941
|
+
|
942
|
+
updateSyntax |= CONFIG.highlightQuotes != highlightQuotes
|
943
|
+
updateSyntax |= CONFIG.highlightEmph != highlightEmph
|
944
|
+
updateSyntax |= CONFIG.showMultiSpaces != showMultiSpaces
|
945
|
+
|
946
|
+
CONFIG.highlightQuotes = highlightQuotes
|
947
|
+
CONFIG.highlightEmph = highlightEmph
|
948
|
+
CONFIG.showMultiSpaces = showMultiSpaces
|
949
|
+
CONFIG.allowOpenSQuote = self.allowOpenSQuote.isChecked()
|
950
|
+
CONFIG.allowOpenDQuote = self.allowOpenDQuote.isChecked()
|
951
|
+
|
952
|
+
# Text Automation
|
953
|
+
CONFIG.doReplace = self.doReplace.isChecked()
|
954
|
+
CONFIG.doReplaceSQuote = self.doReplaceSQuote.isChecked()
|
955
|
+
CONFIG.doReplaceDQuote = self.doReplaceDQuote.isChecked()
|
956
|
+
CONFIG.doReplaceDash = self.doReplaceDash.isChecked()
|
957
|
+
CONFIG.doReplaceDots = self.doReplaceDots.isChecked()
|
958
|
+
CONFIG.fmtPadBefore = self.fmtPadBefore.text().strip()
|
959
|
+
CONFIG.fmtPadAfter = self.fmtPadAfter.text().strip()
|
960
|
+
CONFIG.fmtPadThin = self.fmtPadThin.isChecked()
|
961
|
+
|
962
|
+
# Quotation Style
|
963
|
+
CONFIG.fmtSQuoteOpen = self.quoteSym["SO"].text()
|
964
|
+
CONFIG.fmtSQuoteClose = self.quoteSym["SC"].text()
|
965
|
+
CONFIG.fmtDQuoteOpen = self.quoteSym["DO"].text()
|
966
|
+
CONFIG.fmtDQuoteClose = self.quoteSym["DC"].text()
|
967
|
+
|
968
|
+
# Finalise
|
969
|
+
CONFIG.saveConfig()
|
970
|
+
self.newPreferencesReady.emit(needsRestart, refreshTree, updateTheme, updateSyntax)
|
1121
971
|
|
1122
972
|
return
|
1123
973
|
|
1124
|
-
# END Class
|
974
|
+
# END Class GuiPreferences
|