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
@@ -27,24 +27,24 @@ import logging
27
27
 
28
28
  from typing import TYPE_CHECKING
29
29
 
30
- from PyQt5.QtGui import (
31
- QColor, QFont, QIcon, QSyntaxHighlighter, QTextCharFormat, QTextDocument
32
- )
30
+ from PyQt5.QtGui import QFont, QIcon, QSyntaxHighlighter, QTextCharFormat, QTextDocument
33
31
  from PyQt5.QtCore import QEvent, QSize, Qt, pyqtSignal, pyqtSlot
34
32
  from PyQt5.QtWidgets import (
35
- QAbstractButton, QAbstractItemView, QComboBox, QDialog, QDialogButtonBox,
36
- QDoubleSpinBox, QFontDialog, QFrame, QGridLayout, QHBoxLayout, QHeaderView,
37
- QLabel, QLineEdit, QMenu, QPlainTextEdit, QPushButton, QSpinBox, QSplitter,
38
- QStackedWidget, QToolButton, QTreeWidget, QTreeWidgetItem, QVBoxLayout,
39
- QWidget
33
+ QAbstractButton, QAbstractItemView, QDialog, QDialogButtonBox,
34
+ QFontDialog, QFrame, QGridLayout, QHBoxLayout, QHeaderView, QLabel,
35
+ QLineEdit, QMenu, QPlainTextEdit, QPushButton, QSplitter, QStackedWidget,
36
+ QToolButton, QTreeWidget, QTreeWidgetItem, QVBoxLayout, QWidget
40
37
  )
41
38
 
42
39
  from novelwriter import CONFIG, SHARED
43
40
  from novelwriter.constants import nwHeadFmt, nwLabels, trConst
44
41
  from novelwriter.core.buildsettings import BuildSettings, FilterMode
45
42
  from novelwriter.extensions.switch import NSwitch
43
+ from novelwriter.extensions.modified import NComboBox, NDoubleSpinBox, NSpinBox
46
44
  from novelwriter.extensions.switchbox import NSwitchBox
47
- from novelwriter.extensions.configlayout import NConfigLayout, NSimpleLayout
45
+ from novelwriter.extensions.configlayout import (
46
+ NColourLabel, NFixedPage, NScrollableForm, NScrollablePage
47
+ )
48
48
  from novelwriter.extensions.pagedsidebar import NPagedSideBar
49
49
 
50
50
  if TYPE_CHECKING: # pragma: no cover
@@ -79,47 +79,49 @@ class GuiBuildSettings(QDialog):
79
79
  self._build = build
80
80
 
81
81
  self.setWindowTitle(self.tr("Manuscript Build Settings"))
82
- self.setMinimumWidth(CONFIG.pxInt(700))
83
- self.setMinimumHeight(CONFIG.pxInt(400))
82
+ self.setMinimumSize(CONFIG.pxInt(700), CONFIG.pxInt(400))
84
83
 
85
84
  mPx = CONFIG.pxInt(150)
86
85
  wWin = CONFIG.pxInt(750)
87
86
  hWin = CONFIG.pxInt(550)
88
87
 
89
- pOptions = SHARED.project.options
88
+ options = SHARED.project.options
90
89
  self.resize(
91
- CONFIG.pxInt(pOptions.getInt("GuiBuildSettings", "winWidth", wWin)),
92
- CONFIG.pxInt(pOptions.getInt("GuiBuildSettings", "winHeight", hWin))
90
+ CONFIG.pxInt(options.getInt("GuiBuildSettings", "winWidth", wWin)),
91
+ CONFIG.pxInt(options.getInt("GuiBuildSettings", "winHeight", hWin))
93
92
  )
94
93
 
95
- # Options SideBar
96
- # ===============
94
+ # Title
95
+ self.titleLabel = NColourLabel(
96
+ self.tr("Manuscript Build Settings"), SHARED.theme.helpText,
97
+ parent=self, scale=NColourLabel.HEADER_SCALE, indent=CONFIG.pxInt(4)
98
+ )
97
99
 
98
- self.optSideBar = NPagedSideBar(self)
99
- self.optSideBar.setMinimumWidth(mPx)
100
- self.optSideBar.setMaximumWidth(mPx)
101
- self.optSideBar.setLabelColor(SHARED.theme.helpText)
100
+ # Settings Name
101
+ self.lblBuildName = QLabel(self.tr("Name"))
102
+ self.editBuildName = QLineEdit(self)
102
103
 
103
- self.optSideBar.addLabel(self.tr("Options"))
104
- self.optSideBar.addButton(self.tr("Selection"), self.OPT_FILTERS)
105
- self.optSideBar.addButton(self.tr("Headings"), self.OPT_HEADINGS)
106
- self.optSideBar.addButton(self.tr("Content"), self.OPT_CONTENT)
107
- self.optSideBar.addButton(self.tr("Format"), self.OPT_FORMAT)
108
- self.optSideBar.addButton(self.tr("Output"), self.OPT_OUTPUT)
104
+ # SideBar
105
+ self.sidebar = NPagedSideBar(self)
106
+ self.sidebar.setMinimumWidth(mPx)
107
+ self.sidebar.setMaximumWidth(mPx)
108
+ self.sidebar.setLabelColor(SHARED.theme.helpText)
109
109
 
110
- self.optSideBar.buttonClicked.connect(self._stackPageSelected)
110
+ self.sidebar.addButton(self.tr("Selection"), self.OPT_FILTERS)
111
+ self.sidebar.addButton(self.tr("Headings"), self.OPT_HEADINGS)
112
+ self.sidebar.addButton(self.tr("Content"), self.OPT_CONTENT)
113
+ self.sidebar.addButton(self.tr("Format"), self.OPT_FORMAT)
114
+ self.sidebar.addButton(self.tr("Output"), self.OPT_OUTPUT)
111
115
 
112
- # Options Area
113
- # ============
116
+ self.sidebar.buttonClicked.connect(self._stackPageSelected)
114
117
 
115
- # Create Tabs
118
+ # Content
116
119
  self.optTabSelect = _FilterTab(self, self._build)
117
120
  self.optTabHeadings = _HeadingsTab(self, self._build)
118
121
  self.optTabContent = _ContentTab(self, self._build)
119
122
  self.optTabFormat = _FormatTab(self, self._build)
120
123
  self.optTabOutput = _OutputTab(self, self._build)
121
124
 
122
- # Add Tabs
123
125
  self.toolStack = QStackedWidget(self)
124
126
  self.toolStack.addWidget(self.optTabSelect)
125
127
  self.toolStack.addWidget(self.optTabHeadings)
@@ -127,38 +129,36 @@ class GuiBuildSettings(QDialog):
127
129
  self.toolStack.addWidget(self.optTabContent)
128
130
  self.toolStack.addWidget(self.optTabOutput)
129
131
 
130
- # Main Settings + Buttons
131
- # =======================
132
-
133
- self.lblBuildName = QLabel(self.tr("Name"))
134
- self.editBuildName = QLineEdit()
135
- self.dlgButtons = QDialogButtonBox(
136
- QDialogButtonBox.Apply | QDialogButtonBox.Save | QDialogButtonBox.Close
132
+ # Buttons
133
+ self.buttonBox = QDialogButtonBox(
134
+ QDialogButtonBox.StandardButton.Apply
135
+ | QDialogButtonBox.StandardButton.Save
136
+ | QDialogButtonBox.StandardButton.Close
137
137
  )
138
- self.dlgButtons.clicked.connect(self._dialogButtonClicked)
138
+ self.buttonBox.clicked.connect(self._dialogButtonClicked)
139
139
 
140
- self.buttonBox = QHBoxLayout()
141
- self.buttonBox.addWidget(self.lblBuildName)
142
- self.buttonBox.addWidget(self.editBuildName)
143
- self.buttonBox.addWidget(self.dlgButtons)
144
-
145
- # Assemble GUI
146
- # ============
140
+ # Assemble
141
+ self.topBox = QHBoxLayout()
142
+ self.topBox.addWidget(self.titleLabel)
143
+ self.topBox.addStretch(1)
144
+ self.topBox.addWidget(self.lblBuildName)
145
+ self.topBox.addWidget(self.editBuildName, 1)
147
146
 
148
147
  self.mainBox = QHBoxLayout()
149
- self.mainBox.addWidget(self.optSideBar)
148
+ self.mainBox.addWidget(self.sidebar)
150
149
  self.mainBox.addWidget(self.toolStack)
151
150
  self.mainBox.setContentsMargins(0, 0, 0, 0)
152
151
 
153
152
  self.outerBox = QVBoxLayout()
153
+ self.outerBox.addLayout(self.topBox)
154
154
  self.outerBox.addLayout(self.mainBox)
155
- self.outerBox.addLayout(self.buttonBox)
155
+ self.outerBox.addWidget(self.buttonBox)
156
156
  self.outerBox.setSpacing(CONFIG.pxInt(12))
157
157
 
158
158
  self.setLayout(self.outerBox)
159
159
 
160
160
  # Set Default Tab
161
- self.optSideBar.setSelected(self.OPT_FILTERS)
161
+ self.sidebar.setSelected(self.OPT_FILTERS)
162
162
 
163
163
  logger.debug("Ready: GuiBuildSettings")
164
164
 
@@ -187,6 +187,21 @@ class GuiBuildSettings(QDialog):
187
187
  """The build ID of the build of the dialog."""
188
188
  return self._build.buildID
189
189
 
190
+ ##
191
+ # Events
192
+ ##
193
+
194
+ def closeEvent(self, event: QEvent) -> None:
195
+ """Capture the user closing the window so we can save
196
+ settings.
197
+ """
198
+ logger.debug("Closing: GuiBuildSettings")
199
+ self._askToSaveBuild()
200
+ self._saveSettings()
201
+ event.accept()
202
+ self.deleteLater()
203
+ return
204
+
190
205
  ##
191
206
  # Private Slots
192
207
  ##
@@ -209,7 +224,7 @@ class GuiBuildSettings(QDialog):
209
224
  @pyqtSlot("QAbstractButton*")
210
225
  def _dialogButtonClicked(self, button: QAbstractButton) -> None:
211
226
  """Handle button clicks from the dialog button box."""
212
- role = self.dlgButtons.buttonRole(button)
227
+ role = self.buttonBox.buttonRole(button)
213
228
  if role == QDialogButtonBox.ApplyRole:
214
229
  self._emitBuildData()
215
230
  elif role == QDialogButtonBox.AcceptRole:
@@ -219,21 +234,6 @@ class GuiBuildSettings(QDialog):
219
234
  self.close()
220
235
  return
221
236
 
222
- ##
223
- # Events
224
- ##
225
-
226
- def closeEvent(self, event: QEvent) -> None:
227
- """Capture the user closing the window so we can save
228
- settings.
229
- """
230
- logger.debug("Closing: GuiBuildSettings")
231
- self._askToSaveBuild()
232
- self._saveSettings()
233
- event.accept()
234
- self.deleteLater()
235
- return
236
-
237
237
  ##
238
238
  # Internal Functions
239
239
  ##
@@ -281,7 +281,7 @@ class GuiBuildSettings(QDialog):
281
281
  # END Class GuiBuildSettings
282
282
 
283
283
 
284
- class _FilterTab(QWidget):
284
+ class _FilterTab(NFixedPage):
285
285
 
286
286
  C_DATA = 0
287
287
  C_NAME = 0
@@ -397,11 +397,7 @@ class _FilterTab(QWidget):
397
397
  CONFIG.pxInt(pOptions.getInt("GuiBuildSettings", "filterWidth", 300))
398
398
  ])
399
399
 
400
- self.outerBox = QHBoxLayout()
401
- self.outerBox.addWidget(self.mainSplit)
402
- self.outerBox.setContentsMargins(0, 0, 0, 0)
403
-
404
- self.setLayout(self.outerBox)
400
+ self.setCentralWidget(self.mainSplit)
405
401
 
406
402
  return
407
403
 
@@ -582,7 +578,7 @@ class _FilterTab(QWidget):
582
578
  # END Class _FilterTab
583
579
 
584
580
 
585
- class _HeadingsTab(QWidget):
581
+ class _HeadingsTab(NScrollablePage):
586
582
 
587
583
  EDIT_TITLE = 1
588
584
  EDIT_CHAPTER = 2
@@ -607,9 +603,9 @@ class _HeadingsTab(QWidget):
607
603
 
608
604
  # Title Heading
609
605
  self.lblTitle = QLabel(self._build.getLabel("headings.fmtTitle"))
610
- self.fmtTitle = QLineEdit("")
606
+ self.fmtTitle = QLineEdit("", self)
611
607
  self.fmtTitle.setReadOnly(True)
612
- self.btnTitle = QToolButton()
608
+ self.btnTitle = QToolButton(self)
613
609
  self.btnTitle.setIcon(SHARED.theme.getIcon("edit"))
614
610
  self.btnTitle.clicked.connect(lambda: self._editHeading(self.EDIT_TITLE))
615
611
 
@@ -623,9 +619,9 @@ class _HeadingsTab(QWidget):
623
619
 
624
620
  # Chapter Heading
625
621
  self.lblChapter = QLabel(self._build.getLabel("headings.fmtChapter"))
626
- self.fmtChapter = QLineEdit("")
622
+ self.fmtChapter = QLineEdit("", self)
627
623
  self.fmtChapter.setReadOnly(True)
628
- self.btnChapter = QToolButton()
624
+ self.btnChapter = QToolButton(self)
629
625
  self.btnChapter.setIcon(SHARED.theme.getIcon("edit"))
630
626
  self.btnChapter.clicked.connect(lambda: self._editHeading(self.EDIT_CHAPTER))
631
627
 
@@ -639,9 +635,9 @@ class _HeadingsTab(QWidget):
639
635
 
640
636
  # Unnumbered Chapter Heading
641
637
  self.lblUnnumbered = QLabel(self._build.getLabel("headings.fmtUnnumbered"))
642
- self.fmtUnnumbered = QLineEdit("")
638
+ self.fmtUnnumbered = QLineEdit("", self)
643
639
  self.fmtUnnumbered.setReadOnly(True)
644
- self.btnUnnumbered = QToolButton()
640
+ self.btnUnnumbered = QToolButton(self)
645
641
  self.btnUnnumbered.setIcon(SHARED.theme.getIcon("edit"))
646
642
  self.btnUnnumbered.clicked.connect(lambda: self._editHeading(self.EDIT_UNNUM))
647
643
 
@@ -656,14 +652,14 @@ class _HeadingsTab(QWidget):
656
652
  # Scene Heading
657
653
  sceneHideTip = self._build.getLabel("headings.hideScene")
658
654
  self.lblScene = QLabel(self._build.getLabel("headings.fmtScene"))
659
- self.fmtScene = QLineEdit("")
655
+ self.fmtScene = QLineEdit("", self)
660
656
  self.fmtScene.setReadOnly(True)
661
- self.btnScene = QToolButton()
657
+ self.btnScene = QToolButton(self)
662
658
  self.btnScene.setIcon(SHARED.theme.getIcon("edit"))
663
659
  self.btnScene.clicked.connect(lambda: self._editHeading(self.EDIT_SCENE))
664
660
  self.hdeScene = QLabel(self.tr("Hide"))
665
661
  self.hdeScene.setToolTip(sceneHideTip)
666
- self.swtScene = NSwitch(self, width=2*iPx, height=iPx)
662
+ self.swtScene = NSwitch(self, height=iPx)
667
663
  self.swtScene.setToolTip(sceneHideTip)
668
664
 
669
665
  wrapScene = QHBoxLayout()
@@ -683,14 +679,14 @@ class _HeadingsTab(QWidget):
683
679
  # Section Heading
684
680
  sectionHideTip = self._build.getLabel("headings.hideSection")
685
681
  self.lblSection = QLabel(self._build.getLabel("headings.fmtSection"))
686
- self.fmtSection = QLineEdit("")
682
+ self.fmtSection = QLineEdit("", self)
687
683
  self.fmtSection.setReadOnly(True)
688
- self.btnSection = QToolButton()
684
+ self.btnSection = QToolButton(self)
689
685
  self.btnSection.setIcon(SHARED.theme.getIcon("edit"))
690
686
  self.btnSection.clicked.connect(lambda: self._editHeading(self.EDIT_SECTION))
691
687
  self.hdeSection = QLabel(self.tr("Hide"))
692
688
  self.hdeSection.setToolTip(sectionHideTip)
693
- self.swtSection = NSwitch(self, width=2*iPx, height=iPx)
689
+ self.swtSection = NSwitch(self, height=iPx)
694
690
  self.swtSection.setToolTip(sectionHideTip)
695
691
 
696
692
  wrapSection = QHBoxLayout()
@@ -726,6 +722,8 @@ class _HeadingsTab(QWidget):
726
722
  self.aInsChRomL = self.menuInsert.addAction(self.tr("Chapter Number (Lower Case Roman)"))
727
723
  self.aInsScNum = self.menuInsert.addAction(self.tr("Scene Number (In Chapter)"))
728
724
  self.aInsScAbs = self.menuInsert.addAction(self.tr("Scene Number (Absolute)"))
725
+ self.aInsCharPOV = self.menuInsert.addAction(self.tr("Point of View Character"))
726
+ self.aInsCharFocus = self.menuInsert.addAction(self.tr("Focus Character"))
729
727
 
730
728
  self.aInsTitle.triggered.connect(lambda: self._insertIntoForm(nwHeadFmt.TITLE))
731
729
  self.aInsChNum.triggered.connect(lambda: self._insertIntoForm(nwHeadFmt.CH_NUM))
@@ -734,6 +732,8 @@ class _HeadingsTab(QWidget):
734
732
  self.aInsChRomL.triggered.connect(lambda: self._insertIntoForm(nwHeadFmt.CH_ROML))
735
733
  self.aInsScNum.triggered.connect(lambda: self._insertIntoForm(nwHeadFmt.SC_NUM))
736
734
  self.aInsScAbs.triggered.connect(lambda: self._insertIntoForm(nwHeadFmt.SC_ABS))
735
+ self.aInsCharPOV.triggered.connect(lambda: self._insertIntoForm(nwHeadFmt.CHAR_POV))
736
+ self.aInsCharFocus.triggered.connect(lambda: self._insertIntoForm(nwHeadFmt.CHAR_FOCUS))
737
737
 
738
738
  self.btnInsert = QPushButton(self.tr("Insert"))
739
739
  self.btnInsert.setMenu(self.menuInsert)
@@ -760,7 +760,7 @@ class _HeadingsTab(QWidget):
760
760
  self.outerBox.addLayout(self.editFormBox)
761
761
  self.outerBox.addStretch(1)
762
762
 
763
- self.setLayout(self.outerBox)
763
+ self.setCentralLayout(self.outerBox)
764
764
 
765
765
  return
766
766
 
@@ -827,6 +827,7 @@ class _HeadingsTab(QWidget):
827
827
  # Private Slots
828
828
  ##
829
829
 
830
+ @pyqtSlot()
830
831
  def _saveFormat(self) -> None:
831
832
  """Save the format from the edit text box."""
832
833
  heading = self._editing
@@ -862,14 +863,14 @@ class _HeadingSyntaxHighlighter(QSyntaxHighlighter):
862
863
  def __init__(self, document: QTextDocument) -> None:
863
864
  super().__init__(document)
864
865
  self._fmtSymbol = QTextCharFormat()
865
- self._fmtSymbol.setForeground(QColor(*SHARED.theme.colHead))
866
+ self._fmtSymbol.setForeground(SHARED.theme.colHead)
866
867
  self._fmtFormat = QTextCharFormat()
867
- self._fmtFormat.setForeground(QColor(*SHARED.theme.colEmph))
868
+ self._fmtFormat.setForeground(SHARED.theme.colEmph)
868
869
  return
869
870
 
870
871
  def highlightBlock(self, text: str) -> None:
871
872
  """Add syntax highlighting to the text block."""
872
- for heading in nwHeadFmt.ALL:
873
+ for heading in nwHeadFmt.PAGE_HEADERS:
873
874
  pos = text.find(heading)
874
875
  if pos >= 0:
875
876
  chars = len(heading)
@@ -883,7 +884,7 @@ class _HeadingSyntaxHighlighter(QSyntaxHighlighter):
883
884
  # END Class _HeadingSyntaxHighlighter
884
885
 
885
886
 
886
- class _ContentTab(QWidget):
887
+ class _ContentTab(NScrollableForm):
887
888
 
888
889
  def __init__(self, buildMain: GuiBuildSettings, build: BuildSettings) -> None:
889
890
  super().__init__(parent=buildMain)
@@ -892,42 +893,26 @@ class _ContentTab(QWidget):
892
893
 
893
894
  iPx = SHARED.theme.baseIconSize
894
895
 
895
- # Left Form
896
- # =========
897
-
898
- self.formLeft = NSimpleLayout()
899
- self.formLeft.addGroupLabel(self._build.getLabel("text.grpContent"))
900
-
901
- self.incSynopsis = NSwitch(self, width=2*iPx, height=iPx)
902
- self.incComments = NSwitch(self, width=2*iPx, height=iPx)
903
- self.incKeywords = NSwitch(self, width=2*iPx, height=iPx)
904
- self.incBodyText = NSwitch(self, width=2*iPx, height=iPx)
905
-
906
- self.formLeft.addRow(self._build.getLabel("text.includeSynopsis"), self.incSynopsis)
907
- self.formLeft.addRow(self._build.getLabel("text.includeComments"), self.incComments)
908
- self.formLeft.addRow(self._build.getLabel("text.includeKeywords"), self.incKeywords)
909
- self.formLeft.addRow(self._build.getLabel("text.includeBodyText"), self.incBodyText)
896
+ # Text Content
897
+ self.incSynopsis = NSwitch(self, height=iPx)
898
+ self.incComments = NSwitch(self, height=iPx)
899
+ self.incKeywords = NSwitch(self, height=iPx)
900
+ self.incBodyText = NSwitch(self, height=iPx)
910
901
 
911
- # Right Form
912
- # ==========
902
+ self.addGroupLabel(self._build.getLabel("text.grpContent"))
903
+ self.addRow(self._build.getLabel("text.includeSynopsis"), self.incSynopsis)
904
+ self.addRow(self._build.getLabel("text.includeComments"), self.incComments)
905
+ self.addRow(self._build.getLabel("text.includeKeywords"), self.incKeywords)
906
+ self.addRow(self._build.getLabel("text.includeBodyText"), self.incBodyText)
913
907
 
914
- self.formRight = NSimpleLayout()
915
- self.formRight.addGroupLabel(self._build.getLabel("text.grpInsert"))
908
+ # Insert Content
909
+ self.addNoteHead = NSwitch(self, height=iPx)
916
910
 
917
- self.addNoteHead = NSwitch(self, width=2*iPx, height=iPx)
911
+ self.addGroupLabel(self._build.getLabel("text.grpInsert"))
912
+ self.addRow(self._build.getLabel("text.addNoteHeadings"), self.addNoteHead)
918
913
 
919
- self.formRight.addRow(self._build.getLabel("text.addNoteHeadings"), self.addNoteHead)
920
-
921
- # Assemble GUI
922
- # ============
923
-
924
- self.outerBox = QHBoxLayout()
925
- self.outerBox.addLayout(self.formLeft, 1)
926
- self.outerBox.addLayout(self.formRight, 1)
927
- self.outerBox.setContentsMargins(0, 0, 0, 0)
928
- self.outerBox.setSpacing(CONFIG.pxInt(16))
929
-
930
- self.setLayout(self.outerBox)
914
+ # Finalise
915
+ self.finalise()
931
916
 
932
917
  return
933
918
 
@@ -952,7 +937,7 @@ class _ContentTab(QWidget):
952
937
  # END Class _ContentTab
953
938
 
954
939
 
955
- class _FormatTab(QWidget):
940
+ class _FormatTab(NScrollableForm):
956
941
 
957
942
  def __init__(self, buildMain: GuiBuildSettings, build: BuildSettings) -> None:
958
943
  super().__init__(parent=buildMain)
@@ -966,127 +951,98 @@ class _FormatTab(QWidget):
966
951
  spW = 6*SHARED.theme.textNWidth
967
952
  dbW = 8*SHARED.theme.textNWidth
968
953
 
969
- # Text Format Form
970
- # ================
954
+ # Text Format
955
+ # ===========
971
956
 
972
- self.formFormat = NConfigLayout()
973
- self.formFormat.addGroupLabel(self._build.getLabel("format.grpFormat"))
957
+ self.addGroupLabel(self._build.getLabel("format.grpFormat"))
974
958
 
975
959
  # Font Family
976
- self.textFont = QLineEdit()
960
+ self.textFont = QLineEdit(self)
977
961
  self.textFont.setReadOnly(True)
978
962
  self.btnTextFont = QPushButton("...")
979
963
  self.btnTextFont.setMaximumWidth(int(2.5*SHARED.theme.getTextWidth("...")))
980
964
  self.btnTextFont.clicked.connect(self._selectFont)
981
- self.formFormat.addRow(
982
- self._build.getLabel("format.textFont"), self.textFont, button=self.btnTextFont
965
+ self.addRow(
966
+ self._build.getLabel("format.textFont"), self.textFont,
967
+ button=self.btnTextFont, stretch=(3, 2)
983
968
  )
984
969
 
985
970
  # Font Size
986
- self.textSize = QSpinBox(self)
971
+ self.textSize = NSpinBox(self)
987
972
  self.textSize.setMinimum(8)
988
973
  self.textSize.setMaximum(60)
989
974
  self.textSize.setSingleStep(1)
990
975
  self.textSize.setMinimumWidth(spW)
991
- self.formFormat.addRow(
992
- self._build.getLabel("format.textSize"), self.textSize, unit="pt"
993
- )
976
+ self.addRow(self._build.getLabel("format.textSize"), self.textSize, unit="pt")
994
977
 
995
978
  # Line Height
996
- self.lineHeight = QDoubleSpinBox(self)
979
+ self.lineHeight = NDoubleSpinBox(self)
997
980
  self.lineHeight.setFixedWidth(spW)
998
981
  self.lineHeight.setMinimum(0.75)
999
982
  self.lineHeight.setMaximum(3.0)
1000
983
  self.lineHeight.setSingleStep(0.05)
1001
984
  self.lineHeight.setDecimals(2)
1002
- self.formFormat.addRow(
1003
- self._build.getLabel("format.lineHeight"), self.lineHeight, unit="em"
1004
- )
985
+ self.addRow(self._build.getLabel("format.lineHeight"), self.lineHeight, unit="em")
1005
986
 
1006
- # Text Options Form
1007
- # =================
987
+ # Text Options
988
+ # ============
1008
989
 
1009
- self.formOptions = NSimpleLayout()
1010
- self.formOptions.addGroupLabel(self._build.getLabel("format.grpOptions"))
1011
- self.formOptions.setContentsMargins(0, 0, 0, 0)
990
+ self.addGroupLabel(self._build.getLabel("format.grpOptions"))
1012
991
 
1013
- self.justifyText = NSwitch(self, width=2*iPx, height=iPx)
1014
- self.stripUnicode = NSwitch(self, width=2*iPx, height=iPx)
1015
- self.replaceTabs = NSwitch(self, width=2*iPx, height=iPx)
992
+ self.justifyText = NSwitch(self, height=iPx)
993
+ self.stripUnicode = NSwitch(self, height=iPx)
994
+ self.replaceTabs = NSwitch(self, height=iPx)
1016
995
 
1017
- self.formOptions.addRow(self._build.getLabel("format.justifyText"), self.justifyText)
1018
- self.formOptions.addRow(self._build.getLabel("format.stripUnicode"), self.stripUnicode)
1019
- self.formOptions.addRow(self._build.getLabel("format.replaceTabs"), self.replaceTabs)
996
+ self.addRow(self._build.getLabel("format.justifyText"), self.justifyText)
997
+ self.addRow(self._build.getLabel("format.stripUnicode"), self.stripUnicode)
998
+ self.addRow(self._build.getLabel("format.replaceTabs"), self.replaceTabs)
1020
999
 
1021
- # Page Layout Form
1022
- # ================
1000
+ # Page Layout
1001
+ # ===========
1023
1002
 
1024
- self.formLayout = NSimpleLayout()
1025
- self.formLayout.addGroupLabel(self._build.getLabel("format.grpPage"))
1026
- self.formLayout.setContentsMargins(0, 0, 0, 0)
1003
+ self.addGroupLabel(self._build.getLabel("format.grpPage"))
1027
1004
 
1028
- self.pageUnit = QComboBox(self)
1005
+ self.pageUnit = NComboBox(self)
1029
1006
  for key, name in nwLabels.UNIT_NAME.items():
1030
1007
  self.pageUnit.addItem(trConst(name), key)
1031
1008
 
1032
- self.pageSize = QComboBox(self)
1009
+ self.pageSize = NComboBox(self)
1033
1010
  for key, name in nwLabels.PAPER_NAME.items():
1034
1011
  self.pageSize.addItem(trConst(name), key)
1035
1012
 
1036
- self.pageWidth = QDoubleSpinBox(self)
1013
+ self.pageWidth = NDoubleSpinBox(self)
1037
1014
  self.pageWidth.setFixedWidth(dbW)
1038
1015
  self.pageWidth.setMaximum(500.0)
1039
1016
  self.pageWidth.valueChanged.connect(self._pageSizeValueChanged)
1040
1017
 
1041
- self.pageHeight = QDoubleSpinBox(self)
1018
+ self.pageHeight = NDoubleSpinBox(self)
1042
1019
  self.pageHeight.setFixedWidth(dbW)
1043
1020
  self.pageHeight.setMaximum(500.0)
1044
1021
  self.pageHeight.valueChanged.connect(self._pageSizeValueChanged)
1045
1022
 
1046
- self.topMargin = QDoubleSpinBox(self)
1023
+ self.topMargin = NDoubleSpinBox(self)
1047
1024
  self.topMargin.setFixedWidth(dbW)
1048
1025
 
1049
- self.bottomMargin = QDoubleSpinBox(self)
1026
+ self.bottomMargin = NDoubleSpinBox(self)
1050
1027
  self.bottomMargin.setFixedWidth(dbW)
1051
1028
 
1052
- self.leftMargin = QDoubleSpinBox(self)
1029
+ self.leftMargin = NDoubleSpinBox(self)
1053
1030
  self.leftMargin.setFixedWidth(dbW)
1054
1031
 
1055
- self.rightMargin = QDoubleSpinBox(self)
1032
+ self.rightMargin = NDoubleSpinBox(self)
1056
1033
  self.rightMargin.setFixedWidth(dbW)
1057
1034
 
1058
- self.formLayout.addRow(self._build.getLabel("format.pageUnit"), self.pageUnit)
1059
- self.formLayout.addRow(self._build.getLabel("format.pageSize"), self.pageSize)
1060
- self.formLayout.addRow(self._build.getLabel("format.pageWidth"), self.pageWidth)
1061
- self.formLayout.addRow(self._build.getLabel("format.pageHeight"), self.pageHeight)
1062
- self.formLayout.addRow(self._build.getLabel("format.topMargin"), self.topMargin)
1063
- self.formLayout.addRow(self._build.getLabel("format.bottomMargin"), self.bottomMargin)
1064
- self.formLayout.addRow(self._build.getLabel("format.leftMargin"), self.leftMargin)
1065
- self.formLayout.addRow(self._build.getLabel("format.rightMargin"), self.rightMargin)
1066
-
1067
- # Assemble GUI
1068
- # ============
1035
+ self.addRow(self._build.getLabel("format.pageUnit"), self.pageUnit)
1036
+ self.addRow(self._build.getLabel("format.pageSize"), self.pageSize)
1037
+ self.addRow(self._build.getLabel("format.pageWidth"), self.pageWidth)
1038
+ self.addRow(self._build.getLabel("format.pageHeight"), self.pageHeight)
1039
+ self.addRow(self._build.getLabel("format.topMargin"), self.topMargin)
1040
+ self.addRow(self._build.getLabel("format.bottomMargin"), self.bottomMargin)
1041
+ self.addRow(self._build.getLabel("format.leftMargin"), self.leftMargin)
1042
+ self.addRow(self._build.getLabel("format.rightMargin"), self.rightMargin)
1069
1043
 
1070
- self.formLeft = QVBoxLayout()
1071
- self.formLeft.addLayout(self.formFormat)
1072
- self.formLeft.addLayout(self.formOptions)
1073
- self.formLeft.addStretch(1)
1074
- self.formLeft.setContentsMargins(0, 0, 0, 0)
1075
- self.formLeft.setSpacing(CONFIG.pxInt(8))
1076
-
1077
- self.formRight = QVBoxLayout()
1078
- self.formRight.addLayout(self.formLayout)
1079
- self.formRight.addStretch(1)
1080
- self.formRight.setContentsMargins(0, 0, 0, 0)
1081
- self.formRight.setSpacing(CONFIG.pxInt(8))
1082
-
1083
- self.outerBox = QHBoxLayout()
1084
- self.outerBox.addLayout(self.formLeft, 1)
1085
- self.outerBox.addLayout(self.formRight, 1)
1086
- self.outerBox.setContentsMargins(0, 0, 0, 0)
1087
- self.outerBox.setSpacing(CONFIG.pxInt(16))
1088
-
1089
- self.setLayout(self.outerBox)
1044
+ # Finalise
1045
+ self.finalise()
1090
1046
 
1091
1047
  return
1092
1048
 
@@ -1159,10 +1115,10 @@ class _FormatTab(QWidget):
1159
1115
  currFont = QFont()
1160
1116
  currFont.setFamily(self.textFont.text())
1161
1117
  currFont.setPointSize(self.textSize.value())
1162
- theFont, theStatus = QFontDialog.getFont(currFont, self)
1163
- if theStatus:
1164
- self.textFont.setText(theFont.family())
1165
- self.textSize.setValue(theFont.pointSize())
1118
+ newFont, status = QFontDialog.getFont(currFont, self)
1119
+ if status:
1120
+ self.textFont.setText(newFont.family())
1121
+ self.textSize.setValue(newFont.pointSize())
1166
1122
  return
1167
1123
 
1168
1124
  @pyqtSlot(int)
@@ -1250,7 +1206,7 @@ class _FormatTab(QWidget):
1250
1206
  # END Class _FormatTab
1251
1207
 
1252
1208
 
1253
- class _OutputTab(QWidget):
1209
+ class _OutputTab(NScrollableForm):
1254
1210
 
1255
1211
  def __init__(self, buildMain: GuiBuildSettings, build: BuildSettings) -> None:
1256
1212
  super().__init__(parent=buildMain)
@@ -1258,50 +1214,65 @@ class _OutputTab(QWidget):
1258
1214
  self._build = build
1259
1215
 
1260
1216
  iPx = SHARED.theme.baseIconSize
1217
+ spW = 6*SHARED.theme.textNWidth
1261
1218
 
1262
- # Left Form
1263
- # =========
1264
-
1265
- self.formLeft = NSimpleLayout()
1266
- self.formLeft.addGroupLabel(self._build.getLabel("odt"))
1267
-
1268
- self.odtAddColours = NSwitch(self, width=2*iPx, height=iPx)
1269
-
1270
- self.formLeft.addRow(self._build.getLabel("odt.addColours"), self.odtAddColours)
1271
-
1272
- # Right Form
1273
- # ==========
1219
+ # Open Document
1220
+ self.addGroupLabel(self._build.getLabel("odt"))
1274
1221
 
1275
- self.formRight = NSimpleLayout()
1276
- self.formRight.addGroupLabel(self._build.getLabel("html"))
1222
+ self.odtAddColours = NSwitch(self, height=iPx)
1223
+ self.addRow(self._build.getLabel("odt.addColours"), self.odtAddColours)
1277
1224
 
1278
- self.htmlAddStyles = NSwitch(self, width=2*iPx, height=iPx)
1225
+ self.odtPageHeader = QLineEdit(self)
1226
+ self.odtPageHeader.setMinimumWidth(CONFIG.pxInt(200))
1227
+ self.btnPageHeader = QToolButton(self)
1228
+ self.btnPageHeader.setIcon(SHARED.theme.getIcon("revert"))
1229
+ self.btnPageHeader.clicked.connect(self._resetPageHeader)
1230
+ self.addRow(
1231
+ self._build.getLabel("odt.pageHeader"), self.odtPageHeader,
1232
+ button=self.btnPageHeader, stretch=(1, 1)
1233
+ )
1279
1234
 
1280
- self.formRight.addRow(self._build.getLabel("html.addStyles"), self.htmlAddStyles)
1235
+ self.odtPageCountOffset = NSpinBox(self)
1236
+ self.odtPageCountOffset.setMinimum(0)
1237
+ self.odtPageCountOffset.setMaximum(999)
1238
+ self.odtPageCountOffset.setSingleStep(1)
1239
+ self.odtPageCountOffset.setMinimumWidth(spW)
1240
+ self.addRow(self._build.getLabel("odt.pageCountOffset"), self.odtPageCountOffset)
1281
1241
 
1282
- # Assemble GUI
1283
- # ============
1242
+ # HTML Document
1243
+ self.addGroupLabel(self._build.getLabel("html"))
1284
1244
 
1285
- self.outerBox = QHBoxLayout()
1286
- self.outerBox.addLayout(self.formLeft, 1)
1287
- self.outerBox.addLayout(self.formRight, 1)
1288
- self.outerBox.setContentsMargins(0, 0, 0, 0)
1289
- self.outerBox.setSpacing(CONFIG.pxInt(16))
1245
+ self.htmlAddStyles = NSwitch(self, height=iPx)
1246
+ self.addRow(self._build.getLabel("html.addStyles"), self.htmlAddStyles)
1290
1247
 
1291
- self.setLayout(self.outerBox)
1248
+ # Finalise
1249
+ self.finalise()
1292
1250
 
1293
1251
  return
1294
1252
 
1295
1253
  def loadContent(self) -> None:
1296
1254
  """Populate the widgets."""
1297
1255
  self.odtAddColours.setChecked(self._build.getBool("odt.addColours"))
1256
+ self.odtPageHeader.setText(self._build.getStr("odt.pageHeader"))
1257
+ self.odtPageCountOffset.setValue(self._build.getInt("odt.pageCountOffset"))
1298
1258
  self.htmlAddStyles.setChecked(self._build.getBool("html.addStyles"))
1299
1259
  return
1300
1260
 
1301
1261
  def saveContent(self) -> None:
1302
1262
  """Save choices back into build object."""
1303
1263
  self._build.setValue("odt.addColours", self.odtAddColours.isChecked())
1264
+ self._build.setValue("odt.pageHeader", self.odtPageHeader.text())
1265
+ self._build.setValue("odt.pageCountOffset", self.odtPageCountOffset.value())
1304
1266
  self._build.setValue("html.addStyles", self.htmlAddStyles.isChecked())
1305
1267
  return
1306
1268
 
1269
+ ##
1270
+ # Private Slots
1271
+ ##
1272
+
1273
+ def _resetPageHeader(self) -> None:
1274
+ """Reset the ODT header format to default."""
1275
+ self.odtPageHeader.setText(nwHeadFmt.ODT_AUTO)
1276
+ return
1277
+
1307
1278
  # END Class _OutputTab