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