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.
Files changed (110) hide show
  1. {novelWriter-2.2.1.dist-info → novelWriter-2.3b1.dist-info}/METADATA +1 -1
  2. {novelWriter-2.2.1.dist-info → novelWriter-2.3b1.dist-info}/RECORD +102 -92
  3. novelwriter/__init__.py +4 -4
  4. novelwriter/assets/icons/typicons_dark/icons.conf +6 -0
  5. novelwriter/assets/icons/typicons_dark/mixed_import.svg +5 -0
  6. novelwriter/assets/icons/typicons_dark/typ_document-add-col.svg +8 -0
  7. novelwriter/assets/icons/typicons_dark/typ_document-add.svg +4 -0
  8. novelwriter/assets/icons/typicons_dark/typ_document.svg +4 -0
  9. novelwriter/assets/icons/typicons_dark/typ_th-dot-more.svg +4 -0
  10. novelwriter/assets/icons/typicons_light/icons.conf +6 -0
  11. novelwriter/assets/icons/typicons_light/mixed_import.svg +5 -0
  12. novelwriter/assets/icons/typicons_light/typ_document-add-col.svg +8 -0
  13. novelwriter/assets/icons/typicons_light/typ_document-add.svg +4 -0
  14. novelwriter/assets/icons/typicons_light/typ_document.svg +4 -0
  15. novelwriter/assets/icons/typicons_light/typ_th-dot-more.svg +4 -0
  16. novelwriter/assets/images/novelwriter-text-dark.svg +4 -0
  17. novelwriter/assets/images/novelwriter-text-light.svg +4 -0
  18. novelwriter/assets/images/welcome-dark.jpg +0 -0
  19. novelwriter/assets/images/welcome-light.jpg +0 -0
  20. novelwriter/assets/manual.pdf +0 -0
  21. novelwriter/assets/sample.zip +0 -0
  22. novelwriter/assets/syntax/default_dark.conf +1 -0
  23. novelwriter/assets/syntax/default_light.conf +1 -0
  24. novelwriter/assets/syntax/grey_dark.conf +1 -0
  25. novelwriter/assets/syntax/grey_light.conf +1 -0
  26. novelwriter/assets/syntax/light_owl.conf +1 -0
  27. novelwriter/assets/syntax/night_owl.conf +1 -0
  28. novelwriter/assets/syntax/solarized_dark.conf +1 -0
  29. novelwriter/assets/syntax/solarized_light.conf +1 -0
  30. novelwriter/assets/syntax/tomorrow.conf +1 -0
  31. novelwriter/assets/syntax/tomorrow_night.conf +1 -0
  32. novelwriter/assets/syntax/tomorrow_night_blue.conf +1 -0
  33. novelwriter/assets/syntax/tomorrow_night_bright.conf +1 -0
  34. novelwriter/assets/syntax/tomorrow_night_eighties.conf +1 -0
  35. novelwriter/assets/text/credits_en.htm +4 -2
  36. novelwriter/assets/themes/default_dark.conf +2 -2
  37. novelwriter/assets/themes/default_light.conf +2 -2
  38. novelwriter/common.py +48 -37
  39. novelwriter/config.py +36 -41
  40. novelwriter/constants.py +38 -16
  41. novelwriter/core/buildsettings.py +7 -7
  42. novelwriter/core/coretools.py +192 -154
  43. novelwriter/core/docbuild.py +6 -3
  44. novelwriter/core/document.py +6 -6
  45. novelwriter/core/index.py +89 -56
  46. novelwriter/core/item.py +21 -3
  47. novelwriter/core/options.py +8 -7
  48. novelwriter/core/project.py +69 -44
  49. novelwriter/core/projectdata.py +1 -14
  50. novelwriter/core/projectxml.py +13 -41
  51. novelwriter/core/sessions.py +2 -1
  52. novelwriter/core/spellcheck.py +2 -1
  53. novelwriter/core/status.py +2 -1
  54. novelwriter/core/storage.py +178 -140
  55. novelwriter/core/tohtml.py +4 -2
  56. novelwriter/core/tokenizer.py +73 -45
  57. novelwriter/core/toodt.py +40 -30
  58. novelwriter/core/tree.py +3 -2
  59. novelwriter/dialogs/about.py +70 -160
  60. novelwriter/dialogs/docmerge.py +6 -5
  61. novelwriter/dialogs/docsplit.py +6 -6
  62. novelwriter/dialogs/editlabel.py +1 -1
  63. novelwriter/dialogs/preferences.py +553 -703
  64. novelwriter/dialogs/{projsettings.py → projectsettings.py} +288 -262
  65. novelwriter/dialogs/quotes.py +27 -23
  66. novelwriter/dialogs/wordlist.py +96 -40
  67. novelwriter/enum.py +20 -18
  68. novelwriter/error.py +1 -1
  69. novelwriter/extensions/circularprogress.py +11 -11
  70. novelwriter/extensions/configlayout.py +185 -134
  71. novelwriter/extensions/modified.py +81 -0
  72. novelwriter/extensions/novelselector.py +26 -12
  73. novelwriter/extensions/pagedsidebar.py +14 -16
  74. novelwriter/extensions/simpleprogress.py +5 -5
  75. novelwriter/extensions/statusled.py +8 -8
  76. novelwriter/extensions/switch.py +31 -63
  77. novelwriter/extensions/switchbox.py +1 -1
  78. novelwriter/extensions/versioninfo.py +153 -0
  79. novelwriter/gui/doceditor.py +178 -150
  80. novelwriter/gui/dochighlight.py +63 -92
  81. novelwriter/gui/docviewer.py +49 -51
  82. novelwriter/gui/docviewerpanel.py +72 -24
  83. novelwriter/gui/itemdetails.py +7 -7
  84. novelwriter/gui/mainmenu.py +14 -18
  85. novelwriter/gui/noveltree.py +9 -8
  86. novelwriter/gui/outline.py +98 -75
  87. novelwriter/gui/projtree.py +188 -61
  88. novelwriter/gui/sidebar.py +3 -4
  89. novelwriter/gui/statusbar.py +3 -4
  90. novelwriter/gui/theme.py +60 -68
  91. novelwriter/guimain.py +49 -156
  92. novelwriter/shared.py +15 -1
  93. novelwriter/tools/dictionaries.py +5 -6
  94. novelwriter/tools/manuscript.py +6 -6
  95. novelwriter/tools/manussettings.py +192 -221
  96. novelwriter/tools/noveldetails.py +525 -0
  97. novelwriter/tools/welcome.py +802 -0
  98. novelwriter/tools/writingstats.py +9 -9
  99. novelwriter/assets/images/wizard-back.jpg +0 -0
  100. novelwriter/assets/text/gplv3_en.htm +0 -641
  101. novelwriter/assets/text/release_notes.htm +0 -60
  102. novelwriter/dialogs/projdetails.py +0 -518
  103. novelwriter/dialogs/projload.py +0 -294
  104. novelwriter/dialogs/updates.py +0 -172
  105. novelwriter/extensions/pageddialog.py +0 -130
  106. novelwriter/tools/projwizard.py +0 -478
  107. {novelWriter-2.2.1.dist-info → novelWriter-2.3b1.dist-info}/LICENSE.md +0 -0
  108. {novelWriter-2.2.1.dist-info → novelWriter-2.3b1.dist-info}/WHEEL +0 -0
  109. {novelWriter-2.2.1.dist-info → novelWriter-2.3b1.dist-info}/entry_points.txt +0 -0
  110. {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: 2019-06-10 [0.1.5] GuiPreferences
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
- QDialog, QWidget, QComboBox, QSpinBox, QPushButton, QDialogButtonBox,
32
- QLineEdit, QFileDialog, QFontDialog, QDoubleSpinBox, qApp
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.pageddialog import NPagedDialog
39
- from novelwriter.extensions.configlayout import NConfigLayout
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(NPagedDialog):
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
- # Settings
80
- self._updateTheme = False
81
- self._updateSyntax = False
82
- self._needsRestart = False
83
- self._refreshTree = False
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
- logger.debug("Ready: GuiPreferences")
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
- return
76
+ # SideBar
77
+ self.sidebar = NPagedSideBar(self)
78
+ self.sidebar.setLabelColor(SHARED.theme.helpText)
79
+ self.sidebar.buttonClicked.connect(self._sidebarClicked)
88
80
 
89
- def __del__(self) -> None: # pragma: no cover
90
- logger.debug("Delete: GuiPreferences")
91
- return
81
+ # Form
82
+ self.mainForm = NScrollableForm(self)
83
+ self.mainForm.setHelpTextStyle(SHARED.theme.helpText)
92
84
 
93
- ##
94
- # Events
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
- def closeEvent(self, event: QCloseEvent) -> None:
98
- """Capture the close event and perform cleanup."""
99
- logger.debug("Close: GuiPreferences")
100
- self._saveWindowSize()
101
- event.accept()
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
- # Private Slots
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
- @pyqtSlot()
110
- def _doSave(self) -> None:
111
- """Trigger save functions in the tabs and emit ready signal."""
112
- self.tabGeneral.saveValues()
113
- self.tabProjects.saveValues()
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
- CONFIG.saveConfig()
121
- self.newPreferencesReady.emit(
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
- return
113
+ # Build Form
114
+ self.buildForm()
128
115
 
129
- ##
130
- # Internal Functions
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
- def _saveWindowSize(self) -> None:
134
- """Save the dialog window size."""
135
- CONFIG.setPreferencesWinSize(self.width(), self.height())
136
- return
122
+ self.searchText.setCompleter(self.searchCompleter)
137
123
 
138
- # END Class GuiPreferences
124
+ logger.debug("Ready: GuiPreferences")
139
125
 
126
+ return
140
127
 
141
- class GuiPreferencesGeneral(QWidget):
128
+ def __del__(self) -> None: # pragma: no cover
129
+ logger.debug("Delete: GuiPreferences")
130
+ return
142
131
 
143
- def __init__(self, prefsGui: GuiPreferences) -> None:
144
- super().__init__(parent=prefsGui)
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
- self.prefsGui = prefsGui
138
+ # Label
139
+ self.sidebar.addLabel(self.tr("General"))
147
140
 
148
- # The Form
149
- self.mainForm = NConfigLayout()
150
- self.mainForm.setHelpTextStyle(SHARED.theme.helpText)
151
- self.setLayout(self.mainForm)
141
+ # Appearance
142
+ # ==========
152
143
 
153
- # Look and Feel
154
- # =============
155
- self.mainForm.addGroupLabel(self.tr("Look and Feel"))
156
- minWidth = CONFIG.pxInt(200)
144
+ title = self.tr("Appearance")
145
+ section += 1
146
+ self.sidebar.addButton(title, section)
147
+ self.mainForm.addGroupLabel(title, section)
157
148
 
158
- # Select Locale
159
- self.guiLocale = QComboBox(self)
149
+ # Display Language
150
+ self.guiLocale = NComboBox(self)
160
151
  self.guiLocale.setMinimumWidth(minWidth)
161
- theLangs = CONFIG.listLanguages(CONFIG.LANG_NW)
162
- for lang, langName in theLangs:
163
- self.guiLocale.addItem(langName, lang)
164
- langIdx = self.guiLocale.findData(CONFIG.guiLocale)
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("Main GUI language"),
172
- self.guiLocale,
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
- # Select Theme
177
- self.guiTheme = QComboBox(self)
162
+ # Colour Theme
163
+ self.guiTheme = NComboBox(self)
178
164
  self.guiTheme.setMinimumWidth(minWidth)
179
- self.theThemes = SHARED.theme.listThemes()
180
- for themeDir, themeName in self.theThemes:
181
- self.guiTheme.addItem(themeName, themeDir)
182
- themeIdx = self.guiTheme.findData(CONFIG.guiTheme)
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("Editor theme"),
204
- self.guiSyntax,
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.setFixedWidth(CONFIG.pxInt(162))
178
+ self.guiFont.setMinimumWidth(CONFIG.pxInt(162))
212
179
  self.guiFont.setText(CONFIG.guiFont)
213
- self.fontButton = QPushButton("...", self)
214
- self.fontButton.setMaximumWidth(int(2.5*SHARED.theme.getTextWidth("...")))
215
- self.fontButton.clicked.connect(self._selectFont)
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("Font family"),
218
- self.guiFont,
219
- self.tr("Requires restart to take effect."),
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 = QSpinBox(self)
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("Font size"),
231
- self.guiFontSize,
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
- # GUI Settings
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
- self.hideHScroll = NSwitch()
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
- return
216
+ # Document Style
217
+ # ==============
273
218
 
274
- def saveValues(self) -> None:
275
- """Save the values set for this tab."""
276
- guiLocale = self.guiLocale.currentData()
277
- guiTheme = self.guiTheme.currentData()
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
- return
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
- # Private Slots
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
- @pyqtSlot()
308
- def _selectFont(self) -> None:
309
- """Open the QFontDialog and set a font for the font style."""
310
- currFont = QFont()
311
- currFont.setFamily(CONFIG.guiFont)
312
- currFont.setPointSize(CONFIG.guiFontSize)
313
- theFont, theStatus = QFontDialog.getFont(currFont, self)
314
- if theStatus:
315
- self.guiFont.setText(theFont.family())
316
- self.guiFontSize.setValue(theFont.pointSize())
317
- return
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
- # END Class GuiPreferencesGeneral
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
- class GuiPreferencesProjects(QWidget):
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
- def __init__(self, prefsGui: GuiPreferences) -> None:
325
- super().__init__(parent=prefsGui)
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
- # The Form
328
- self.mainForm = NConfigLayout()
329
- self.mainForm.setHelpTextStyle(SHARED.theme.helpText)
330
- self.setLayout(self.mainForm)
285
+ # Auto Save
286
+ # =========
331
287
 
332
- # Automatic Save
333
- # ==============
334
- self.mainForm.addGroupLabel(self.tr("Automatic Save"))
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 = QSpinBox(self)
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.autoSaveDoc,
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 = QSpinBox(self)
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.autoSaveProj,
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
- self.mainForm.addGroupLabel(self.tr("Project Backup"))
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.backupPathRow = self.mainForm.addRow(
371
- self.tr("Backup storage location"),
372
- self.backupGetPath,
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 when closing
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 before backup
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
- # Pause when idle
402
- self.stopWhenIdle = NSwitch()
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 time for idle
411
- self.userIdleTime = QDoubleSpinBox(self)
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
- return
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
- self.mainForm.addGroupLabel(self.tr("Text Flow"))
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 = QSpinBox(self)
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.textWidth,
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 = QSpinBox(self)
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.focusWidth,
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 = QSpinBox(self)
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 = QSpinBox(self)
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
- return
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
- mW = CONFIG.pxInt(250)
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.mainForm.addGroupLabel(self.tr("Spell Checking"))
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(self.tr("None"), "")
469
+ self.spellLanguage.addItem(nwUnicode.U_EMDASH, "")
649
470
  self.spellLanguage.setEnabled(False)
650
471
 
651
- spellIdx = self.spellLanguage.findData(CONFIG.spellLanguage)
652
- if spellIdx != -1:
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.spellLanguage,
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
- # Include Notes in Word Count
679
- self.incNotesWCount = NSwitch()
680
- self.incNotesWCount.setChecked(CONFIG.incNotesWCount)
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("Include project notes in status bar word count"),
683
- self.incNotesWCount
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
- # Scroll Behaviour
502
+ # Editor Scrolling
707
503
  # ================
708
- self.mainForm.addGroupLabel(self.tr("Scroll Behaviour"))
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 = QSpinBox(self)
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.autoScrollPos,
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
- return
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
- self.highlightQuotes = NSwitch()
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
- # Text Emphasis
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
- # Text Errors
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
- return
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
- # The Form
874
- self.mainForm = NConfigLayout()
875
- self.mainForm.setHelpTextStyle(SHARED.theme.helpText)
876
- self.setLayout(self.mainForm)
584
+ title = self.tr("Text Automation")
585
+ section += 1
586
+ self.sidebar.addButton(title, section)
587
+ self.mainForm.addGroupLabel(title, section)
877
588
 
878
- # Automatic Features
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.fmtPadBefore,
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.fmtPadAfter,
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
- qWidth = CONFIG.pxInt(40)
1032
- bWidth = int(2.5*SHARED.theme.getTextWidth("..."))
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 = QPushButton("...", self)
1043
- self.btnSingleStyleO.setMaximumWidth(bWidth)
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 = QPushButton("...", self)
1059
- self.btnSingleStyleC.setMaximumWidth(bWidth)
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 = QPushButton("...", self)
1076
- self.btnDoubleStyleO.setMaximumWidth(bWidth)
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 = QPushButton("...", self)
1092
- self.btnDoubleStyleC.setMaximumWidth(bWidth)
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
- def saveValues(self) -> None:
1104
- """Save the values set for this tab."""
1105
- # Quotation Style
1106
- CONFIG.fmtSQuoteOpen = self.quoteSym["SO"].text()
1107
- CONFIG.fmtSQuoteClose = self.quoteSym["SC"].text()
1108
- CONFIG.fmtDQuoteOpen = self.quoteSym["DO"].text()
1109
- CONFIG.fmtDQuoteClose = self.quoteSym["DC"].text()
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
- # Internal Functions
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
- qtBox = GuiQuoteSelect(self, currentQuote=self.quoteSym[qType].text())
1119
- if qtBox.exec_() == QDialog.Accepted:
1120
- self.quoteSym[qType].setText(qtBox.selectedQuote)
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 GuiPreferencesQuotes
974
+ # END Class GuiPreferences