novelWriter 2.5.3__py3-none-any.whl → 2.6b2__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 (83) hide show
  1. {novelWriter-2.5.3.dist-info → novelWriter-2.6b2.dist-info}/METADATA +1 -1
  2. {novelWriter-2.5.3.dist-info → novelWriter-2.6b2.dist-info}/RECORD +80 -60
  3. novelwriter/__init__.py +49 -10
  4. novelwriter/assets/i18n/project_en_GB.json +1 -0
  5. novelwriter/assets/icons/typicons_dark/icons.conf +8 -0
  6. novelwriter/assets/icons/typicons_dark/mixed_copy.svg +4 -0
  7. novelwriter/assets/icons/typicons_dark/mixed_margin-bottom.svg +6 -0
  8. novelwriter/assets/icons/typicons_dark/mixed_margin-left.svg +6 -0
  9. novelwriter/assets/icons/typicons_dark/mixed_margin-right.svg +6 -0
  10. novelwriter/assets/icons/typicons_dark/mixed_margin-top.svg +6 -0
  11. novelwriter/assets/icons/typicons_dark/mixed_size-height.svg +6 -0
  12. novelwriter/assets/icons/typicons_dark/mixed_size-width.svg +6 -0
  13. novelwriter/assets/icons/typicons_dark/nw_toolbar.svg +5 -0
  14. novelwriter/assets/icons/typicons_light/icons.conf +8 -0
  15. novelwriter/assets/icons/typicons_light/mixed_copy.svg +4 -0
  16. novelwriter/assets/icons/typicons_light/mixed_margin-bottom.svg +6 -0
  17. novelwriter/assets/icons/typicons_light/mixed_margin-left.svg +6 -0
  18. novelwriter/assets/icons/typicons_light/mixed_margin-right.svg +6 -0
  19. novelwriter/assets/icons/typicons_light/mixed_margin-top.svg +6 -0
  20. novelwriter/assets/icons/typicons_light/mixed_size-height.svg +6 -0
  21. novelwriter/assets/icons/typicons_light/mixed_size-width.svg +6 -0
  22. novelwriter/assets/icons/typicons_light/nw_toolbar.svg +5 -0
  23. novelwriter/assets/manual.pdf +0 -0
  24. novelwriter/assets/sample.zip +0 -0
  25. novelwriter/common.py +100 -2
  26. novelwriter/config.py +25 -15
  27. novelwriter/constants.py +168 -60
  28. novelwriter/core/buildsettings.py +66 -39
  29. novelwriter/core/coretools.py +145 -147
  30. novelwriter/core/docbuild.py +132 -170
  31. novelwriter/core/index.py +38 -37
  32. novelwriter/core/item.py +41 -8
  33. novelwriter/core/itemmodel.py +518 -0
  34. novelwriter/core/options.py +4 -1
  35. novelwriter/core/project.py +67 -89
  36. novelwriter/core/spellcheck.py +9 -14
  37. novelwriter/core/status.py +7 -5
  38. novelwriter/core/tree.py +268 -287
  39. novelwriter/dialogs/docmerge.py +7 -17
  40. novelwriter/dialogs/preferences.py +46 -33
  41. novelwriter/dialogs/projectsettings.py +5 -5
  42. novelwriter/enum.py +36 -23
  43. novelwriter/extensions/configlayout.py +27 -12
  44. novelwriter/extensions/modified.py +13 -1
  45. novelwriter/extensions/pagedsidebar.py +5 -5
  46. novelwriter/formats/shared.py +155 -0
  47. novelwriter/formats/todocx.py +1191 -0
  48. novelwriter/formats/tohtml.py +451 -0
  49. novelwriter/{core → formats}/tokenizer.py +487 -491
  50. novelwriter/formats/tomarkdown.py +217 -0
  51. novelwriter/{core → formats}/toodt.py +311 -432
  52. novelwriter/formats/toqdoc.py +484 -0
  53. novelwriter/formats/toraw.py +91 -0
  54. novelwriter/gui/doceditor.py +342 -284
  55. novelwriter/gui/dochighlight.py +96 -84
  56. novelwriter/gui/docviewer.py +88 -31
  57. novelwriter/gui/docviewerpanel.py +17 -25
  58. novelwriter/gui/editordocument.py +17 -2
  59. novelwriter/gui/itemdetails.py +25 -28
  60. novelwriter/gui/mainmenu.py +129 -63
  61. novelwriter/gui/noveltree.py +45 -47
  62. novelwriter/gui/outline.py +196 -249
  63. novelwriter/gui/projtree.py +594 -1241
  64. novelwriter/gui/search.py +9 -10
  65. novelwriter/gui/sidebar.py +7 -6
  66. novelwriter/gui/theme.py +10 -5
  67. novelwriter/guimain.py +100 -196
  68. novelwriter/shared.py +66 -27
  69. novelwriter/text/counting.py +2 -0
  70. novelwriter/text/patterns.py +168 -60
  71. novelwriter/tools/manusbuild.py +14 -12
  72. novelwriter/tools/manuscript.py +120 -78
  73. novelwriter/tools/manussettings.py +424 -291
  74. novelwriter/tools/welcome.py +4 -4
  75. novelwriter/tools/writingstats.py +3 -3
  76. novelwriter/types.py +23 -7
  77. novelwriter/core/tohtml.py +0 -530
  78. novelwriter/core/tomarkdown.py +0 -252
  79. novelwriter/core/toqdoc.py +0 -419
  80. {novelWriter-2.5.3.dist-info → novelWriter-2.6b2.dist-info}/LICENSE.md +0 -0
  81. {novelWriter-2.5.3.dist-info → novelWriter-2.6b2.dist-info}/WHEEL +0 -0
  82. {novelWriter-2.5.3.dist-info → novelWriter-2.6b2.dist-info}/entry_points.txt +0 -0
  83. {novelWriter-2.5.3.dist-info → novelWriter-2.6b2.dist-info}/top_level.txt +0 -0
@@ -31,14 +31,14 @@ from PyQt5.QtCore import QEvent, pyqtSignal, pyqtSlot
31
31
  from PyQt5.QtGui import QFont, QIcon, QSyntaxHighlighter, QTextCharFormat, QTextDocument
32
32
  from PyQt5.QtWidgets import (
33
33
  QAbstractButton, QAbstractItemView, QDialogButtonBox, QFrame, QGridLayout,
34
- QHBoxLayout, QHeaderView, QLabel, QLineEdit, QMenu, QPlainTextEdit,
35
- QPushButton, QSplitter, QStackedWidget, QTreeWidget, QTreeWidgetItem,
36
- QVBoxLayout, QWidget
34
+ QHBoxLayout, QLabel, QLineEdit, QMenu, QPlainTextEdit, QPushButton,
35
+ QSplitter, QStackedWidget, QTreeWidget, QTreeWidgetItem, QVBoxLayout,
36
+ QWidget
37
37
  )
38
38
 
39
39
  from novelwriter import CONFIG, SHARED
40
- from novelwriter.common import describeFont
41
- from novelwriter.constants import nwHeadFmt, nwKeyWords, nwLabels, trConst
40
+ from novelwriter.common import describeFont, fontMatcher, qtLambda
41
+ from novelwriter.constants import nwHeadFmt, nwKeyWords, nwLabels, nwStyles, trConst
42
42
  from novelwriter.core.buildsettings import BuildSettings, FilterMode
43
43
  from novelwriter.extensions.configlayout import (
44
44
  NColourLabel, NFixedPage, NScrollableForm, NScrollablePage
@@ -50,8 +50,9 @@ from novelwriter.extensions.pagedsidebar import NPagedSideBar
50
50
  from novelwriter.extensions.switch import NSwitch
51
51
  from novelwriter.extensions.switchbox import NSwitchBox
52
52
  from novelwriter.types import (
53
- QtAlignLeft, QtDialogApply, QtDialogClose, QtDialogSave, QtRoleAccept,
54
- QtRoleApply, QtRoleReject, QtUserRole
53
+ QtAlignCenter, QtAlignLeft, QtDialogApply, QtDialogClose, QtDialogSave,
54
+ QtHeaderFixed, QtHeaderStretch, QtRoleAccept, QtRoleApply, QtRoleReject,
55
+ QtUserRole
55
56
  )
56
57
 
57
58
  if TYPE_CHECKING: # pragma: no cover
@@ -67,11 +68,9 @@ class GuiBuildSettings(NToolDialog):
67
68
  editing JSON build definitions, wrapped as a BuildSettings object.
68
69
  """
69
70
 
70
- OPT_FILTERS = 1
71
- OPT_HEADINGS = 2
72
- OPT_CONTENT = 3
73
- OPT_FORMAT = 4
74
- OPT_OUTPUT = 5
71
+ OPT_FILTERS = 1
72
+ OPT_HEADINGS = 2
73
+ OPT_FORMATTING = 10
75
74
 
76
75
  newSettingsReady = pyqtSignal(BuildSettings)
77
76
 
@@ -86,7 +85,6 @@ class GuiBuildSettings(NToolDialog):
86
85
  self.setWindowTitle(self.tr("Manuscript Build Settings"))
87
86
  self.setMinimumSize(CONFIG.pxInt(700), CONFIG.pxInt(400))
88
87
 
89
- mPx = CONFIG.pxInt(150)
90
88
  wWin = CONFIG.pxInt(750)
91
89
  hWin = CONFIG.pxInt(550)
92
90
 
@@ -108,31 +106,24 @@ class GuiBuildSettings(NToolDialog):
108
106
 
109
107
  # SideBar
110
108
  self.sidebar = NPagedSideBar(self)
111
- self.sidebar.setMinimumWidth(mPx)
112
- self.sidebar.setMaximumWidth(mPx)
113
109
  self.sidebar.setLabelColor(SHARED.theme.helpText)
114
110
 
111
+ self.sidebar.addLabel(self.tr("General"))
115
112
  self.sidebar.addButton(self.tr("Selection"), self.OPT_FILTERS)
116
113
  self.sidebar.addButton(self.tr("Headings"), self.OPT_HEADINGS)
117
- self.sidebar.addButton(self.tr("Content"), self.OPT_CONTENT)
118
- self.sidebar.addButton(self.tr("Format"), self.OPT_FORMAT)
119
- self.sidebar.addButton(self.tr("Output"), self.OPT_OUTPUT)
114
+ self.sidebar.addLabel(self.tr("Formatting"))
120
115
 
121
116
  self.sidebar.buttonClicked.connect(self._stackPageSelected)
122
117
 
123
118
  # Content
124
119
  self.optTabSelect = _FilterTab(self, self._build)
125
120
  self.optTabHeadings = _HeadingsTab(self, self._build)
126
- self.optTabContent = _ContentTab(self, self._build)
127
- self.optTabFormat = _FormatTab(self, self._build)
128
- self.optTabOutput = _OutputTab(self, self._build)
121
+ self.optTabFormatting = _FormattingTab(self, self._build, self.sidebar)
129
122
 
130
123
  self.toolStack = QStackedWidget(self)
131
124
  self.toolStack.addWidget(self.optTabSelect)
132
125
  self.toolStack.addWidget(self.optTabHeadings)
133
- self.toolStack.addWidget(self.optTabFormat)
134
- self.toolStack.addWidget(self.optTabContent)
135
- self.toolStack.addWidget(self.optTabOutput)
126
+ self.toolStack.addWidget(self.optTabFormatting)
136
127
 
137
128
  # Buttons
138
129
  self.buttonBox = QDialogButtonBox(QtDialogApply | QtDialogSave | QtDialogClose, self)
@@ -174,9 +165,7 @@ class GuiBuildSettings(NToolDialog):
174
165
  self.editBuildName.setText(self._build.name)
175
166
  self.optTabSelect.loadContent()
176
167
  self.optTabHeadings.loadContent()
177
- self.optTabContent.loadContent()
178
- self.optTabFormat.loadContent()
179
- self.optTabOutput.loadContent()
168
+ self.optTabFormatting.loadContent()
180
169
  return
181
170
 
182
171
  ##
@@ -214,12 +203,9 @@ class GuiBuildSettings(NToolDialog):
214
203
  self.toolStack.setCurrentWidget(self.optTabSelect)
215
204
  elif pageId == self.OPT_HEADINGS:
216
205
  self.toolStack.setCurrentWidget(self.optTabHeadings)
217
- elif pageId == self.OPT_CONTENT:
218
- self.toolStack.setCurrentWidget(self.optTabContent)
219
- elif pageId == self.OPT_FORMAT:
220
- self.toolStack.setCurrentWidget(self.optTabFormat)
221
- elif pageId == self.OPT_OUTPUT:
222
- self.toolStack.setCurrentWidget(self.optTabOutput)
206
+ elif pageId >= self.OPT_FORMATTING:
207
+ self.toolStack.setCurrentWidget(self.optTabFormatting)
208
+ self.optTabFormatting.scrollToSection(pageId)
223
209
  return
224
210
 
225
211
  @pyqtSlot("QAbstractButton*")
@@ -272,9 +258,7 @@ class GuiBuildSettings(NToolDialog):
272
258
  """Assemble the build data and emit the signal."""
273
259
  self._build.setName(self.editBuildName.text())
274
260
  self.optTabHeadings.saveContent()
275
- self.optTabContent.saveContent()
276
- self.optTabFormat.saveContent()
277
- self.optTabOutput.saveContent()
261
+ self.optTabFormatting.saveContent()
278
262
  self.newSettingsReady.emit(self._build)
279
263
  self._build.resetChangedState()
280
264
  return
@@ -330,9 +314,9 @@ class _FilterTab(NFixedPage):
330
314
  treeHeader = self.optTree.header()
331
315
  treeHeader.setStretchLastSection(False)
332
316
  treeHeader.setMinimumSectionSize(iPx + cMg) # See Issue #1551
333
- treeHeader.setSectionResizeMode(self.C_NAME, QHeaderView.ResizeMode.Stretch)
334
- treeHeader.setSectionResizeMode(self.C_ACTIVE, QHeaderView.ResizeMode.Fixed)
335
- treeHeader.setSectionResizeMode(self.C_STATUS, QHeaderView.ResizeMode.Fixed)
317
+ treeHeader.setSectionResizeMode(self.C_NAME, QtHeaderStretch)
318
+ treeHeader.setSectionResizeMode(self.C_ACTIVE, QtHeaderFixed)
319
+ treeHeader.setSectionResizeMode(self.C_STATUS, QtHeaderFixed)
336
320
  treeHeader.resizeSection(self.C_ACTIVE, iPx + cMg)
337
321
  treeHeader.resizeSection(self.C_STATUS, iPx + cMg)
338
322
 
@@ -346,16 +330,16 @@ class _FilterTab(NFixedPage):
346
330
  self.includedButton = NIconToolButton(self, iSz)
347
331
  self.includedButton.setToolTip(self.tr("Always included"))
348
332
  self.includedButton.setIcon(self._statusFlags[self.F_INCLUDED])
349
- self.includedButton.clicked.connect(lambda: self._setSelectedMode(self.F_INCLUDED))
333
+ self.includedButton.clicked.connect(qtLambda(self._setSelectedMode, self.F_INCLUDED))
350
334
 
351
335
  self.excludedButton = NIconToolButton(self, iSz)
352
336
  self.excludedButton.setToolTip(self.tr("Always excluded"))
353
337
  self.excludedButton.setIcon(self._statusFlags[self.F_EXCLUDED])
354
- self.excludedButton.clicked.connect(lambda: self._setSelectedMode(self.F_EXCLUDED))
338
+ self.excludedButton.clicked.connect(qtLambda(self._setSelectedMode, self.F_EXCLUDED))
355
339
 
356
340
  self.resetButton = NIconToolButton(self, iSz, "revert")
357
341
  self.resetButton.setToolTip(self.tr("Reset to default"))
358
- self.resetButton.clicked.connect(lambda: self._setSelectedMode(self.F_FILTERED))
342
+ self.resetButton.clicked.connect(qtLambda(self._setSelectedMode, self.F_FILTERED))
359
343
 
360
344
  self.modeBox = QHBoxLayout()
361
345
  self.modeBox.addWidget(QLabel(self.tr("Mark selection as"), self))
@@ -435,8 +419,7 @@ class _FilterTab(NFixedPage):
435
419
  logger.debug("Building project tree")
436
420
  self._treeMap = {}
437
421
  self.optTree.clear()
438
- for nwItem in SHARED.project.iterProjectItems():
439
-
422
+ for nwItem in SHARED.project.tree:
440
423
  tHandle = nwItem.itemHandle
441
424
  pHandle = nwItem.itemParent
442
425
  rHandle = nwItem.itemRoot
@@ -445,28 +428,15 @@ class _FilterTab(NFixedPage):
445
428
  continue
446
429
 
447
430
  isFile = nwItem.isFileType()
448
- isActive = nwItem.isActive
449
-
450
431
  if nwItem.isInactiveClass() or not self._build.isRootAllowed(rHandle):
451
432
  continue
452
433
 
453
- hLevel = nwItem.mainHeading
454
- itemIcon = SHARED.theme.getItemIcon(
455
- nwItem.itemType, nwItem.itemClass, nwItem.itemLayout, hLevel
456
- )
457
-
458
- if isFile:
459
- iconName = "checked" if isActive else "unchecked"
460
- else:
461
- iconName = "noncheckable"
462
-
463
434
  trItem = QTreeWidgetItem()
464
- trItem.setIcon(self.C_NAME, itemIcon)
435
+ trItem.setIcon(self.C_NAME, nwItem.getMainIcon())
465
436
  trItem.setText(self.C_NAME, nwItem.itemName)
466
437
  trItem.setData(self.C_DATA, self.D_HANDLE, tHandle)
467
438
  trItem.setData(self.C_DATA, self.D_FILE, isFile)
468
- trItem.setIcon(self.C_ACTIVE, SHARED.theme.getIcon(iconName))
469
-
439
+ trItem.setIcon(self.C_ACTIVE, nwItem.getActiveStatus()[1])
470
440
  trItem.setTextAlignment(self.C_NAME, QtAlignLeft)
471
441
 
472
442
  if pHandle is None and nwItem.isRootType():
@@ -513,11 +483,8 @@ class _FilterTab(NFixedPage):
513
483
  self.filterOpt.addLabel(self.tr("Select Root Folders"))
514
484
  for tHandle, nwItem in SHARED.project.tree.iterRoots(None):
515
485
  if not nwItem.isInactiveClass():
516
- itemIcon = SHARED.theme.getItemIcon(
517
- nwItem.itemType, nwItem.itemClass, nwItem.itemLayout
518
- )
519
486
  self.filterOpt.addItem(
520
- itemIcon, nwItem.itemName, f"root:{tHandle}",
487
+ nwItem.getMainIcon(), nwItem.itemName, f"root:{tHandle}",
521
488
  default=self._build.isRootAllowed(tHandle)
522
489
  )
523
490
 
@@ -602,27 +569,27 @@ class _HeadingsTab(NScrollablePage):
602
569
  self.formatBox.setHorizontalSpacing(bSp)
603
570
 
604
571
  # Title Heading
605
- self.lblTitle = QLabel(self._build.getLabel("headings.fmtTitle"), self)
606
- self.fmtTitle = QLineEdit("", self)
607
- self.fmtTitle.setReadOnly(True)
608
- self.btnTitle = NIconToolButton(self, iSz, "edit")
609
- self.btnTitle.clicked.connect(lambda: self._editHeading(self.EDIT_TITLE))
610
- self.hdeTitle = QLabel(trHide, self)
611
- self.hdeTitle.setIndent(bSp)
612
- self.swtTitle = NSwitch(self, height=iPx)
613
-
614
- self.formatBox.addWidget(self.lblTitle, 0, 0)
615
- self.formatBox.addWidget(self.fmtTitle, 0, 1)
616
- self.formatBox.addWidget(self.btnTitle, 0, 2)
617
- self.formatBox.addWidget(self.hdeTitle, 0, 3)
618
- self.formatBox.addWidget(self.swtTitle, 0, 4)
572
+ self.lblPart = QLabel(self._build.getLabel("headings.fmtPart"), self)
573
+ self.fmtPart = QLineEdit("", self)
574
+ self.fmtPart.setReadOnly(True)
575
+ self.btnPart = NIconToolButton(self, iSz, "edit")
576
+ self.btnPart.clicked.connect(qtLambda(self._editHeading, self.EDIT_TITLE))
577
+ self.hdePart = QLabel(trHide, self)
578
+ self.hdePart.setIndent(bSp)
579
+ self.swtPart = NSwitch(self, height=iPx)
580
+
581
+ self.formatBox.addWidget(self.lblPart, 0, 0)
582
+ self.formatBox.addWidget(self.fmtPart, 0, 1)
583
+ self.formatBox.addWidget(self.btnPart, 0, 2)
584
+ self.formatBox.addWidget(self.hdePart, 0, 3)
585
+ self.formatBox.addWidget(self.swtPart, 0, 4)
619
586
 
620
587
  # Chapter Heading
621
588
  self.lblChapter = QLabel(self._build.getLabel("headings.fmtChapter"), self)
622
589
  self.fmtChapter = QLineEdit("", self)
623
590
  self.fmtChapter.setReadOnly(True)
624
591
  self.btnChapter = NIconToolButton(self, iSz, "edit")
625
- self.btnChapter.clicked.connect(lambda: self._editHeading(self.EDIT_CHAPTER))
592
+ self.btnChapter.clicked.connect(qtLambda(self._editHeading, self.EDIT_CHAPTER))
626
593
  self.hdeChapter = QLabel(trHide, self)
627
594
  self.hdeChapter.setIndent(bSp)
628
595
  self.swtChapter = NSwitch(self, height=iPx)
@@ -638,7 +605,7 @@ class _HeadingsTab(NScrollablePage):
638
605
  self.fmtUnnumbered = QLineEdit("", self)
639
606
  self.fmtUnnumbered.setReadOnly(True)
640
607
  self.btnUnnumbered = NIconToolButton(self, iSz, "edit")
641
- self.btnUnnumbered.clicked.connect(lambda: self._editHeading(self.EDIT_UNNUM))
608
+ self.btnUnnumbered.clicked.connect(qtLambda(self._editHeading, self.EDIT_UNNUM))
642
609
  self.hdeUnnumbered = QLabel(trHide, self)
643
610
  self.hdeUnnumbered.setIndent(bSp)
644
611
  self.swtUnnumbered = NSwitch(self, height=iPx)
@@ -654,7 +621,7 @@ class _HeadingsTab(NScrollablePage):
654
621
  self.fmtScene = QLineEdit("", self)
655
622
  self.fmtScene.setReadOnly(True)
656
623
  self.btnScene = NIconToolButton(self, iSz, "edit")
657
- self.btnScene.clicked.connect(lambda: self._editHeading(self.EDIT_SCENE))
624
+ self.btnScene.clicked.connect(qtLambda(self._editHeading, self.EDIT_SCENE))
658
625
  self.hdeScene = QLabel(trHide, self)
659
626
  self.hdeScene.setIndent(bSp)
660
627
  self.swtScene = NSwitch(self, height=iPx)
@@ -670,7 +637,7 @@ class _HeadingsTab(NScrollablePage):
670
637
  self.fmtAScene = QLineEdit("", self)
671
638
  self.fmtAScene.setReadOnly(True)
672
639
  self.btnAScene = NIconToolButton(self, iSz, "edit")
673
- self.btnAScene.clicked.connect(lambda: self._editHeading(self.EDIT_HSCENE))
640
+ self.btnAScene.clicked.connect(qtLambda(self._editHeading, self.EDIT_HSCENE))
674
641
  self.hdeAScene = QLabel(trHide, self)
675
642
  self.hdeAScene.setIndent(bSp)
676
643
  self.swtAScene = NSwitch(self, height=iPx)
@@ -686,7 +653,7 @@ class _HeadingsTab(NScrollablePage):
686
653
  self.fmtSection = QLineEdit("", self)
687
654
  self.fmtSection.setReadOnly(True)
688
655
  self.btnSection = NIconToolButton(self, iSz, "edit")
689
- self.btnSection.clicked.connect(lambda: self._editHeading(self.EDIT_SECTION))
656
+ self.btnSection.clicked.connect(qtLambda(self._editHeading, self.EDIT_SECTION))
690
657
  self.hdeSection = QLabel(trHide, self)
691
658
  self.hdeSection.setIndent(bSp)
692
659
  self.swtSection = NSwitch(self, height=iPx)
@@ -719,15 +686,15 @@ class _HeadingsTab(NScrollablePage):
719
686
  self.aInsCharPOV = self.menuInsert.addAction(self.tr("Point of View Character"))
720
687
  self.aInsCharFocus = self.menuInsert.addAction(self.tr("Focus Character"))
721
688
 
722
- self.aInsTitle.triggered.connect(lambda: self._insertIntoForm(nwHeadFmt.TITLE))
723
- self.aInsChNum.triggered.connect(lambda: self._insertIntoForm(nwHeadFmt.CH_NUM))
724
- self.aInsChWord.triggered.connect(lambda: self._insertIntoForm(nwHeadFmt.CH_WORD))
725
- self.aInsChRomU.triggered.connect(lambda: self._insertIntoForm(nwHeadFmt.CH_ROMU))
726
- self.aInsChRomL.triggered.connect(lambda: self._insertIntoForm(nwHeadFmt.CH_ROML))
727
- self.aInsScNum.triggered.connect(lambda: self._insertIntoForm(nwHeadFmt.SC_NUM))
728
- self.aInsScAbs.triggered.connect(lambda: self._insertIntoForm(nwHeadFmt.SC_ABS))
729
- self.aInsCharPOV.triggered.connect(lambda: self._insertIntoForm(nwHeadFmt.CHAR_POV))
730
- self.aInsCharFocus.triggered.connect(lambda: self._insertIntoForm(nwHeadFmt.CHAR_FOCUS))
689
+ self.aInsTitle.triggered.connect(qtLambda(self._insertIntoForm, nwHeadFmt.TITLE))
690
+ self.aInsChNum.triggered.connect(qtLambda(self._insertIntoForm, nwHeadFmt.CH_NUM))
691
+ self.aInsChWord.triggered.connect(qtLambda(self._insertIntoForm, nwHeadFmt.CH_WORD))
692
+ self.aInsChRomU.triggered.connect(qtLambda(self._insertIntoForm, nwHeadFmt.CH_ROMU))
693
+ self.aInsChRomL.triggered.connect(qtLambda(self._insertIntoForm, nwHeadFmt.CH_ROML))
694
+ self.aInsScNum.triggered.connect(qtLambda(self._insertIntoForm, nwHeadFmt.SC_NUM))
695
+ self.aInsScAbs.triggered.connect(qtLambda(self._insertIntoForm, nwHeadFmt.SC_ABS))
696
+ self.aInsCharPOV.triggered.connect(qtLambda(self._insertIntoForm, nwHeadFmt.CHAR_POV))
697
+ self.aInsCharFocus.triggered.connect(qtLambda(self._insertIntoForm, nwHeadFmt.CHAR_FOCUS))
731
698
 
732
699
  self.btnInsert = QPushButton(self.tr("Insert"), self)
733
700
  self.btnInsert.setMenu(self.menuInsert)
@@ -751,56 +718,46 @@ class _HeadingsTab(NScrollablePage):
751
718
  self.layoutMatrix.setVerticalSpacing(vSp)
752
719
  self.layoutMatrix.setHorizontalSpacing(vSp)
753
720
 
754
- # Heading
755
- self.layoutHeading = QLabel("<b>{0}</b>".format(self.tr("Additional Styling")), self)
756
- self.layoutMatrix.addWidget(self.layoutHeading, 0, 0, 1, 5)
721
+ self.layoutMatrix.addWidget(QLabel(self.tr("Centre"), self), 0, 1)
722
+ self.layoutMatrix.addWidget(QLabel(self.tr("Page Break"), self), 0, 2)
757
723
 
758
724
  # Title Layout
759
- self.mtxTitle = QLabel(self._build.getLabel("headings.fmtTitle"), self)
725
+ self.lblTitle = QLabel(self._build.getLabel("headings.styleTitle"), self)
760
726
  self.centerTitle = NSwitch(self, height=iPx)
761
727
  self.breakTitle = NSwitch(self, height=iPx)
762
- lblCenterT = QLabel(self.tr("Centre"), self)
763
- lblCenterT.setIndent(sSp)
764
- lblBreakT = QLabel(self.tr("Page Break"), self)
765
- lblBreakT.setIndent(sSp)
766
728
 
767
- self.layoutMatrix.addWidget(self.mtxTitle, 1, 0)
768
- self.layoutMatrix.addWidget(lblCenterT, 1, 1)
769
- self.layoutMatrix.addWidget(self.centerTitle, 1, 2)
770
- self.layoutMatrix.addWidget(lblBreakT, 1, 3)
771
- self.layoutMatrix.addWidget(self.breakTitle, 1, 4)
729
+ self.layoutMatrix.addWidget(self.lblTitle, 1, 0)
730
+ self.layoutMatrix.addWidget(self.centerTitle, 1, 1, QtAlignCenter)
731
+ self.layoutMatrix.addWidget(self.breakTitle, 1, 2, QtAlignCenter)
732
+
733
+ # Partition Layout
734
+ self.lblPart = QLabel(self._build.getLabel("headings.stylePart"), self)
735
+ self.centerPart = NSwitch(self, height=iPx)
736
+ self.breakPart = NSwitch(self, height=iPx)
737
+
738
+ self.layoutMatrix.addWidget(self.lblPart, 2, 0)
739
+ self.layoutMatrix.addWidget(self.centerPart, 2, 1, QtAlignCenter)
740
+ self.layoutMatrix.addWidget(self.breakPart, 2, 2, QtAlignCenter)
772
741
 
773
742
  # Chapter Layout
774
- self.mtxChapter = QLabel(self._build.getLabel("headings.fmtChapter"), self)
743
+ self.lblChapter = QLabel(self._build.getLabel("headings.styleChapter"), self)
775
744
  self.centerChapter = NSwitch(self, height=iPx)
776
745
  self.breakChapter = NSwitch(self, height=iPx)
777
- lblCenterC = QLabel(self.tr("Centre"), self)
778
- lblCenterC.setIndent(sSp)
779
- lblBreakC = QLabel(self.tr("Page Break"), self)
780
- lblBreakC.setIndent(sSp)
781
746
 
782
- self.layoutMatrix.addWidget(self.mtxChapter, 2, 0)
783
- self.layoutMatrix.addWidget(lblCenterC, 2, 1)
784
- self.layoutMatrix.addWidget(self.centerChapter, 2, 2)
785
- self.layoutMatrix.addWidget(lblBreakC, 2, 3)
786
- self.layoutMatrix.addWidget(self.breakChapter, 2, 4)
747
+ self.layoutMatrix.addWidget(self.lblChapter, 3, 0)
748
+ self.layoutMatrix.addWidget(self.centerChapter, 3, 1, QtAlignCenter)
749
+ self.layoutMatrix.addWidget(self.breakChapter, 3, 2, QtAlignCenter)
787
750
 
788
751
  # Scene Layout
789
- self.mtxScene = QLabel(self._build.getLabel("headings.fmtScene"), self)
752
+ self.lblScene = QLabel(self._build.getLabel("headings.styleScene"), self)
790
753
  self.centerScene = NSwitch(self, height=iPx)
791
754
  self.breakScene = NSwitch(self, height=iPx)
792
- lblCenterS = QLabel(self.tr("Centre"), self)
793
- lblCenterS.setIndent(sSp)
794
- lblBreakS = QLabel(self.tr("Page Break"), self)
795
- lblBreakS.setIndent(sSp)
796
755
 
797
- self.layoutMatrix.addWidget(self.mtxScene, 3, 0)
798
- self.layoutMatrix.addWidget(lblCenterS, 3, 1)
799
- self.layoutMatrix.addWidget(self.centerScene, 3, 2)
800
- self.layoutMatrix.addWidget(lblBreakS, 3, 3)
801
- self.layoutMatrix.addWidget(self.breakScene, 3, 4)
756
+ self.layoutMatrix.addWidget(self.lblScene, 4, 0)
757
+ self.layoutMatrix.addWidget(self.centerScene, 4, 1, QtAlignCenter)
758
+ self.layoutMatrix.addWidget(self.breakScene, 4, 2, QtAlignCenter)
802
759
 
803
- self.layoutMatrix.setColumnStretch(5, 1)
760
+ self.layoutMatrix.setColumnStretch(3, 1)
804
761
 
805
762
  # Assemble
806
763
  # ========
@@ -819,14 +776,14 @@ class _HeadingsTab(NScrollablePage):
819
776
 
820
777
  def loadContent(self) -> None:
821
778
  """Populate the widgets."""
822
- self.fmtTitle.setText(self._build.getStr("headings.fmtTitle"))
779
+ self.fmtPart.setText(self._build.getStr("headings.fmtPart"))
823
780
  self.fmtChapter.setText(self._build.getStr("headings.fmtChapter"))
824
781
  self.fmtUnnumbered.setText(self._build.getStr("headings.fmtUnnumbered"))
825
782
  self.fmtScene.setText(self._build.getStr("headings.fmtScene"))
826
783
  self.fmtAScene.setText(self._build.getStr("headings.fmtAltScene"))
827
784
  self.fmtSection.setText(self._build.getStr("headings.fmtSection"))
828
785
 
829
- self.swtTitle.setChecked(self._build.getBool("headings.hideTitle"))
786
+ self.swtPart.setChecked(self._build.getBool("headings.hidePart"))
830
787
  self.swtChapter.setChecked(self._build.getBool("headings.hideChapter"))
831
788
  self.swtUnnumbered.setChecked(self._build.getBool("headings.hideUnnumbered"))
832
789
  self.swtScene.setChecked(self._build.getBool("headings.hideScene"))
@@ -834,16 +791,19 @@ class _HeadingsTab(NScrollablePage):
834
791
  self.swtSection.setChecked(self._build.getBool("headings.hideSection"))
835
792
 
836
793
  self.centerTitle.setChecked(self._build.getBool("headings.centerTitle"))
794
+ self.centerPart.setChecked(self._build.getBool("headings.centerPart"))
837
795
  self.centerChapter.setChecked(self._build.getBool("headings.centerChapter"))
838
796
  self.centerScene.setChecked(self._build.getBool("headings.centerScene"))
797
+
839
798
  self.breakTitle.setChecked(self._build.getBool("headings.breakTitle"))
799
+ self.breakPart.setChecked(self._build.getBool("headings.breakPart"))
840
800
  self.breakChapter.setChecked(self._build.getBool("headings.breakChapter"))
841
801
  self.breakScene.setChecked(self._build.getBool("headings.breakScene"))
842
802
  return
843
803
 
844
804
  def saveContent(self) -> None:
845
805
  """Save choices back into build object."""
846
- self._build.setValue("headings.hideTitle", self.swtTitle.isChecked())
806
+ self._build.setValue("headings.hidePart", self.swtPart.isChecked())
847
807
  self._build.setValue("headings.hideChapter", self.swtChapter.isChecked())
848
808
  self._build.setValue("headings.hideUnnumbered", self.swtUnnumbered.isChecked())
849
809
  self._build.setValue("headings.hideScene", self.swtScene.isChecked())
@@ -851,9 +811,12 @@ class _HeadingsTab(NScrollablePage):
851
811
  self._build.setValue("headings.hideSection", self.swtSection.isChecked())
852
812
 
853
813
  self._build.setValue("headings.centerTitle", self.centerTitle.isChecked())
814
+ self._build.setValue("headings.centerPart", self.centerPart.isChecked())
854
815
  self._build.setValue("headings.centerChapter", self.centerChapter.isChecked())
855
816
  self._build.setValue("headings.centerScene", self.centerScene.isChecked())
817
+
856
818
  self._build.setValue("headings.breakTitle", self.breakTitle.isChecked())
819
+ self._build.setValue("headings.breakPart", self.breakPart.isChecked())
857
820
  self._build.setValue("headings.breakChapter", self.breakChapter.isChecked())
858
821
  self._build.setValue("headings.breakScene", self.breakScene.isChecked())
859
822
  return
@@ -875,8 +838,8 @@ class _HeadingsTab(NScrollablePage):
875
838
  self._editing = heading
876
839
  self.editTextBox.setEnabled(True)
877
840
  if heading == self.EDIT_TITLE:
878
- text = self.fmtTitle.text()
879
- label = self._build.getLabel("headings.fmtTitle")
841
+ text = self.fmtPart.text()
842
+ label = self._build.getLabel("headings.fmtPart")
880
843
  elif heading == self.EDIT_CHAPTER:
881
844
  text = self.fmtChapter.text()
882
845
  label = self._build.getLabel("headings.fmtChapter")
@@ -913,8 +876,8 @@ class _HeadingsTab(NScrollablePage):
913
876
  heading = self._editing
914
877
  text = self.editTextBox.toPlainText().strip().replace("\n", nwHeadFmt.BR)
915
878
  if heading == self.EDIT_TITLE:
916
- self.fmtTitle.setText(text)
917
- self._build.setValue("headings.fmtTitle", text)
879
+ self.fmtPart.setText(text)
880
+ self._build.setValue("headings.fmtPart", text)
918
881
  elif heading == self.EDIT_CHAPTER:
919
882
  self.fmtChapter.setText(text)
920
883
  self._build.setValue("headings.fmtChapter", text)
@@ -963,22 +926,48 @@ class _HeadingSyntaxHighlighter(QSyntaxHighlighter):
963
926
  return
964
927
 
965
928
 
966
- class _ContentTab(NScrollableForm):
929
+ class _FormattingTab(NScrollableForm):
967
930
 
968
- def __init__(self, parent: QWidget, build: BuildSettings) -> None:
931
+ def __init__(self, parent: QWidget, build: BuildSettings, sidebar: NPagedSideBar) -> None:
969
932
  super().__init__(parent=parent)
970
933
 
971
934
  self._build = build
935
+ self._sidebar = sidebar
936
+
937
+ self.setHelpTextStyle(SHARED.theme.helpText)
938
+ self.buildForm()
939
+
940
+ return
941
+
942
+ def buildForm(self) -> None:
943
+ """Build the formatting form."""
944
+ section = 10
972
945
 
973
946
  iPx = SHARED.theme.baseIconHeight
974
947
  iSz = SHARED.theme.baseIconSize
948
+ spW = 6*SHARED.theme.textNWidth
949
+ dbW = 8*SHARED.theme.textNWidth
975
950
 
976
951
  # Text Content
952
+ # ============
953
+
954
+ title = self._build.getLabel("text.grpContent")
955
+ section += 1
956
+ self._sidebar.addButton(title, section)
957
+ self.addGroupLabel(title, section)
958
+
959
+ # Text Inclusion
977
960
  self.incBodyText = NSwitch(self, height=iPx)
978
961
  self.incSynopsis = NSwitch(self, height=iPx)
979
962
  self.incComments = NSwitch(self, height=iPx)
980
963
  self.incKeywords = NSwitch(self, height=iPx)
981
964
 
965
+ self.addRow(self._build.getLabel("text.includeBodyText"), self.incBodyText)
966
+ self.addRow(self._build.getLabel("text.includeSynopsis"), self.incSynopsis)
967
+ self.addRow(self._build.getLabel("text.includeComments"), self.incComments)
968
+ self.addRow(self._build.getLabel("text.includeKeywords"), self.incKeywords)
969
+
970
+ # Ignored Keywords
982
971
  self.ignoredKeywords = QLineEdit(self)
983
972
 
984
973
  self.mnKeywords = QMenu(self)
@@ -990,80 +979,23 @@ class _ContentTab(NScrollableForm):
990
979
 
991
980
  self.ignoredKeywordsButton = NIconToolButton(self, iSz, "add")
992
981
  self.ignoredKeywordsButton.setMenu(self.mnKeywords)
982
+ self.addRow(
983
+ self._build.getLabel("text.ignoredKeywords"), self.ignoredKeywords,
984
+ button=self.ignoredKeywordsButton, stretch=(1, 1)
985
+ )
993
986
 
994
- self.addGroupLabel(self._build.getLabel("text.grpContent"))
995
- self.addRow(self._build.getLabel("text.includeBodyText"), self.incBodyText)
996
- self.addRow(self._build.getLabel("text.includeSynopsis"), self.incSynopsis)
997
- self.addRow(self._build.getLabel("text.includeComments"), self.incComments)
998
- self.addRow(self._build.getLabel("text.includeKeywords"), self.incKeywords)
999
- self.addRow(self._build.getLabel("text.ignoredKeywords"), self.ignoredKeywords,
1000
- button=self.ignoredKeywordsButton, stretch=(1, 1))
1001
-
1002
- # Insert Content
987
+ # Note Headings
1003
988
  self.addNoteHead = NSwitch(self, height=iPx)
1004
989
 
1005
- self.addGroupLabel(self._build.getLabel("text.grpInsert"))
1006
990
  self.addRow(self._build.getLabel("text.addNoteHeadings"), self.addNoteHead)
1007
991
 
1008
- # Finalise
1009
- self.finalise()
1010
-
1011
- return
1012
-
1013
- def loadContent(self) -> None:
1014
- """Populate the widgets."""
1015
- self.incBodyText.setChecked(self._build.getBool("text.includeBodyText"))
1016
- self.incSynopsis.setChecked(self._build.getBool("text.includeSynopsis"))
1017
- self.incComments.setChecked(self._build.getBool("text.includeComments"))
1018
- self.incKeywords.setChecked(self._build.getBool("text.includeKeywords"))
1019
- self.ignoredKeywords.setText(self._build.getStr("text.ignoredKeywords"))
1020
- self.addNoteHead.setChecked(self._build.getBool("text.addNoteHeadings"))
1021
- self._updateIgnoredKeywords()
1022
- return
1023
-
1024
- def saveContent(self) -> None:
1025
- """Save choices back into build object."""
1026
- self._updateIgnoredKeywords()
1027
- self._build.setValue("text.includeBodyText", self.incBodyText.isChecked())
1028
- self._build.setValue("text.includeSynopsis", self.incSynopsis.isChecked())
1029
- self._build.setValue("text.includeComments", self.incComments.isChecked())
1030
- self._build.setValue("text.includeKeywords", self.incKeywords.isChecked())
1031
- self._build.setValue("text.ignoredKeywords", self.ignoredKeywords.text())
1032
- self._build.setValue("text.addNoteHeadings", self.addNoteHead.isChecked())
1033
- return
1034
-
1035
- ##
1036
- # Internal Functions
1037
- ##
1038
-
1039
- def _updateIgnoredKeywords(self, keyword: str | None = None) -> None:
1040
- """Update the ignored keywords list."""
1041
- current = [x.lower().strip() for x in self.ignoredKeywords.text().split(",")]
1042
- if keyword:
1043
- current.append(keyword)
1044
- verified = set(x for x in current if x in nwKeyWords.VALID_KEYS)
1045
- self.ignoredKeywords.setText(", ".join(verified))
1046
- return
1047
-
1048
-
1049
- class _FormatTab(NScrollableForm):
1050
-
1051
- def __init__(self, parent: QWidget, build: BuildSettings) -> None:
1052
- super().__init__(parent=parent)
1053
-
1054
- self._build = build
1055
- self._unitScale = 1.0
1056
- self._textFont = QFont(CONFIG.textFont)
1057
-
1058
- iPx = SHARED.theme.baseIconHeight
1059
- iSz = SHARED.theme.baseIconSize
1060
- spW = 6*SHARED.theme.textNWidth
1061
- dbW = 8*SHARED.theme.textNWidth
1062
-
1063
992
  # Text Format
1064
993
  # ===========
1065
994
 
1066
- self.addGroupLabel(self._build.getLabel("format.grpFormat"))
995
+ title = self._build.getLabel("format.grpFormat")
996
+ section += 1
997
+ self._sidebar.addButton(title, section)
998
+ self.addGroupLabel(title, section)
1067
999
 
1068
1000
  # Text Font
1069
1001
  self.textFont = QLineEdit(self)
@@ -1085,10 +1017,6 @@ class _FormatTab(NScrollableForm):
1085
1017
  self.addRow(self._build.getLabel("format.lineHeight"), self.lineHeight, unit="em")
1086
1018
 
1087
1019
  # Text Options
1088
- # ============
1089
-
1090
- self.addGroupLabel(self._build.getLabel("format.grpOptions"))
1091
-
1092
1020
  self.justifyText = NSwitch(self, height=iPx)
1093
1021
  self.stripUnicode = NSwitch(self, height=iPx)
1094
1022
  self.replaceTabs = NSwitch(self, height=iPx)
@@ -1104,7 +1032,10 @@ class _FormatTab(NScrollableForm):
1104
1032
  # First Line Indent
1105
1033
  # =================
1106
1034
 
1107
- self.addGroupLabel(self._build.getLabel("format.grpParIndent"))
1035
+ title = self._build.getLabel("format.grpParIndent")
1036
+ section += 1
1037
+ self._sidebar.addButton(title, section)
1038
+ self.addGroupLabel(title, section)
1108
1039
 
1109
1040
  self.firstIndent = NSwitch(self, height=iPx)
1110
1041
  self.indentFirstPar = NSwitch(self, height=iPx)
@@ -1120,29 +1051,146 @@ class _FormatTab(NScrollableForm):
1120
1051
  self.addRow(self._build.getLabel("format.firstIndentWidth"), self.indentWidth, unit="em")
1121
1052
  self.addRow(self._build.getLabel("format.indentFirstPar"), self.indentFirstPar)
1122
1053
 
1054
+ # Text Margins
1055
+ # ============
1056
+
1057
+ title = self._build.getLabel("format.grpMargins")
1058
+ section += 1
1059
+ self._sidebar.addButton(title, section)
1060
+ self.addGroupLabel(title, section)
1061
+
1062
+ pixT = SHARED.theme.getPixmap("margin_top", (iPx, iPx))
1063
+ pixB = SHARED.theme.getPixmap("margin_bottom", (iPx, iPx))
1064
+ pixL = SHARED.theme.getPixmap("margin_left", (iPx, iPx))
1065
+ pixR = SHARED.theme.getPixmap("margin_right", (iPx, iPx))
1066
+ pixH = SHARED.theme.getPixmap("size_height", (iPx, iPx))
1067
+ pixW = SHARED.theme.getPixmap("size_width", (iPx, iPx))
1068
+
1069
+ # Title
1070
+ self.titleMarginT = NDoubleSpinBox(self)
1071
+ self.titleMarginT.setFixedWidth(dbW)
1072
+
1073
+ self.titleMarginB = NDoubleSpinBox(self)
1074
+ self.titleMarginB.setFixedWidth(dbW)
1075
+
1076
+ self.addRow(
1077
+ trConst(nwStyles.T_LABEL["H0"]),
1078
+ [pixT, self.titleMarginT, 6, pixB, self.titleMarginB],
1079
+ unit="em",
1080
+ )
1081
+
1082
+ # Heading 1
1083
+ self.h1MarginT = NDoubleSpinBox(self)
1084
+ self.h1MarginT.setFixedWidth(dbW)
1085
+
1086
+ self.h1MarginB = NDoubleSpinBox(self)
1087
+ self.h1MarginB.setFixedWidth(dbW)
1088
+
1089
+ self.addRow(
1090
+ trConst(nwStyles.T_LABEL["H1"]),
1091
+ [pixT, self.h1MarginT, 6, pixB, self.h1MarginB],
1092
+ unit="em",
1093
+ )
1094
+
1095
+ # Heading 2
1096
+ self.h2MarginT = NDoubleSpinBox(self)
1097
+ self.h2MarginT.setFixedWidth(dbW)
1098
+
1099
+ self.h2MarginB = NDoubleSpinBox(self)
1100
+ self.h2MarginB.setFixedWidth(dbW)
1101
+
1102
+ self.addRow(
1103
+ trConst(nwStyles.T_LABEL["H2"]),
1104
+ [pixT, self.h2MarginT, 6, pixB, self.h2MarginB],
1105
+ unit="em",
1106
+ )
1107
+
1108
+ # Heading 3
1109
+ self.h3MarginT = NDoubleSpinBox(self)
1110
+ self.h3MarginT.setFixedWidth(dbW)
1111
+
1112
+ self.h3MarginB = NDoubleSpinBox(self)
1113
+ self.h3MarginB.setFixedWidth(dbW)
1114
+
1115
+ self.addRow(
1116
+ trConst(nwStyles.T_LABEL["H3"]),
1117
+ [pixT, self.h3MarginT, 6, pixB, self.h3MarginB],
1118
+ unit="em",
1119
+ )
1120
+
1121
+ # Heading 4
1122
+ self.h4MarginT = NDoubleSpinBox(self)
1123
+ self.h4MarginT.setFixedWidth(dbW)
1124
+
1125
+ self.h4MarginB = NDoubleSpinBox(self)
1126
+ self.h4MarginB.setFixedWidth(dbW)
1127
+
1128
+ self.addRow(
1129
+ trConst(nwStyles.T_LABEL["H4"]),
1130
+ [pixT, self.h4MarginT, 6, pixB, self.h4MarginB],
1131
+ unit="em",
1132
+ )
1133
+
1134
+ # Text
1135
+ self.textMarginT = NDoubleSpinBox(self)
1136
+ self.textMarginT.setFixedWidth(dbW)
1137
+
1138
+ self.textMarginB = NDoubleSpinBox(self)
1139
+ self.textMarginB.setFixedWidth(dbW)
1140
+
1141
+ self.addRow(
1142
+ trConst(nwStyles.T_LABEL["TT"]),
1143
+ [pixT, self.textMarginT, 6, pixB, self.textMarginB],
1144
+ unit="em",
1145
+ )
1146
+
1147
+ # Separator
1148
+ self.sepMarginT = NDoubleSpinBox(self)
1149
+ self.sepMarginT.setFixedWidth(dbW)
1150
+
1151
+ self.sepMarginB = NDoubleSpinBox(self)
1152
+ self.sepMarginB.setFixedWidth(dbW)
1153
+
1154
+ self.addRow(
1155
+ trConst(nwStyles.T_LABEL["SP"]),
1156
+ [pixT, self.sepMarginT, 6, pixB, self.sepMarginB],
1157
+ unit="em",
1158
+ )
1159
+
1123
1160
  # Page Layout
1124
1161
  # ===========
1125
1162
 
1126
- self.addGroupLabel(self._build.getLabel("format.grpPage"))
1163
+ title = self._build.getLabel("format.grpPage")
1164
+ section += 1
1165
+ self._sidebar.addButton(title, section)
1166
+ self.addGroupLabel(title, section)
1127
1167
 
1168
+ # Unit
1128
1169
  self.pageUnit = NComboBox(self)
1129
1170
  for key, name in nwLabels.UNIT_NAME.items():
1130
1171
  self.pageUnit.addItem(trConst(name), key)
1131
1172
 
1173
+ self.addRow(self._build.getLabel("format.pageUnit"), self.pageUnit)
1174
+
1175
+ # Page Size
1132
1176
  self.pageSize = NComboBox(self)
1133
1177
  for key, name in nwLabels.PAPER_NAME.items():
1134
1178
  self.pageSize.addItem(trConst(name), key)
1135
1179
 
1136
- self.pageWidth = NDoubleSpinBox(self)
1180
+ self.pageWidth = NDoubleSpinBox(self, max=500.0)
1137
1181
  self.pageWidth.setFixedWidth(dbW)
1138
- self.pageWidth.setMaximum(500.0)
1139
1182
  self.pageWidth.valueChanged.connect(self._pageSizeValueChanged)
1140
1183
 
1141
- self.pageHeight = NDoubleSpinBox(self)
1184
+ self.pageHeight = NDoubleSpinBox(self, max=500.0)
1142
1185
  self.pageHeight.setFixedWidth(dbW)
1143
- self.pageHeight.setMaximum(500.0)
1144
1186
  self.pageHeight.valueChanged.connect(self._pageSizeValueChanged)
1145
1187
 
1188
+ self.addRow(
1189
+ self._build.getLabel("format.pageSize"),
1190
+ [self.pageSize, 6, pixW, self.pageWidth, 6, pixH, self.pageHeight],
1191
+ )
1192
+
1193
+ # Page Margins
1146
1194
  self.topMargin = NDoubleSpinBox(self)
1147
1195
  self.topMargin.setFixedWidth(dbW)
1148
1196
 
@@ -1155,14 +1203,62 @@ class _FormatTab(NScrollableForm):
1155
1203
  self.rightMargin = NDoubleSpinBox(self)
1156
1204
  self.rightMargin.setFixedWidth(dbW)
1157
1205
 
1158
- self.addRow(self._build.getLabel("format.pageUnit"), self.pageUnit)
1159
- self.addRow(self._build.getLabel("format.pageSize"), self.pageSize)
1160
- self.addRow(self._build.getLabel("format.pageWidth"), self.pageWidth)
1161
- self.addRow(self._build.getLabel("format.pageHeight"), self.pageHeight)
1162
- self.addRow(self._build.getLabel("format.topMargin"), self.topMargin)
1163
- self.addRow(self._build.getLabel("format.bottomMargin"), self.bottomMargin)
1164
- self.addRow(self._build.getLabel("format.leftMargin"), self.leftMargin)
1165
- self.addRow(self._build.getLabel("format.rightMargin"), self.rightMargin)
1206
+ self.addRow(
1207
+ self._build.getLabel("format.pageMargins"),
1208
+ [pixT, self.topMargin, 6, pixB, self.bottomMargin],
1209
+ )
1210
+ self.addRow(
1211
+ "",
1212
+ [pixL, self.leftMargin, 6, pixR, self.rightMargin],
1213
+ )
1214
+
1215
+ # Open Document
1216
+ # =============
1217
+
1218
+ title = self._build.getLabel("doc")
1219
+ section += 1
1220
+ self._sidebar.addButton(title, section)
1221
+ self.addGroupLabel(title, section)
1222
+
1223
+ # Header
1224
+ self.odtPageHeader = QLineEdit(self)
1225
+ self.odtPageHeader.setMinimumWidth(CONFIG.pxInt(200))
1226
+ self.btnPageHeader = NIconToolButton(self, iSz, "revert")
1227
+ self.btnPageHeader.clicked.connect(self._resetPageHeader)
1228
+ self.addRow(
1229
+ self._build.getLabel("doc.pageHeader"), self.odtPageHeader,
1230
+ button=self.btnPageHeader, stretch=(1, 1)
1231
+ )
1232
+
1233
+ self.odtPageCountOffset = NSpinBox(self)
1234
+ self.odtPageCountOffset.setMinimum(0)
1235
+ self.odtPageCountOffset.setMaximum(999)
1236
+ self.odtPageCountOffset.setSingleStep(1)
1237
+ self.odtPageCountOffset.setMinimumWidth(spW)
1238
+ self.addRow(self._build.getLabel("doc.pageCountOffset"), self.odtPageCountOffset)
1239
+
1240
+ # Headings
1241
+ self.colorHeadings = NSwitch(self, height=iPx)
1242
+ self.scaleHeadings = NSwitch(self, height=iPx)
1243
+ self.boldHeadings = NSwitch(self, height=iPx)
1244
+
1245
+ self.addRow(self._build.getLabel("doc.colorHeadings"), self.colorHeadings)
1246
+ self.addRow(self._build.getLabel("doc.scaleHeadings"), self.scaleHeadings)
1247
+ self.addRow(self._build.getLabel("doc.boldHeadings"), self.boldHeadings)
1248
+
1249
+ # HTML Document
1250
+ # =============
1251
+
1252
+ title = self._build.getLabel("html")
1253
+ section += 1
1254
+ self._sidebar.addButton(title, section)
1255
+ self.addGroupLabel(title, section)
1256
+
1257
+ self.htmlAddStyles = NSwitch(self, height=iPx)
1258
+ self.addRow(self._build.getLabel("html.addStyles"), self.htmlAddStyles)
1259
+
1260
+ self.htmlPreserveTabs = NSwitch(self, height=iPx)
1261
+ self.addRow(self._build.getLabel("html.preserveTabs"), self.htmlPreserveTabs)
1166
1262
 
1167
1263
  # Finalise
1168
1264
  self.finalise()
@@ -1171,8 +1267,23 @@ class _FormatTab(NScrollableForm):
1171
1267
 
1172
1268
  def loadContent(self) -> None:
1173
1269
  """Populate the widgets."""
1174
- self._textFont = QFont()
1175
- self._textFont.fromString(self._build.getStr("format.textFont"))
1270
+ # Text Content
1271
+ # ============
1272
+
1273
+ self.incBodyText.setChecked(self._build.getBool("text.includeBodyText"))
1274
+ self.incSynopsis.setChecked(self._build.getBool("text.includeSynopsis"))
1275
+ self.incComments.setChecked(self._build.getBool("text.includeComments"))
1276
+ self.incKeywords.setChecked(self._build.getBool("text.includeKeywords"))
1277
+ self.ignoredKeywords.setText(self._build.getStr("text.ignoredKeywords"))
1278
+ self.addNoteHead.setChecked(self._build.getBool("text.addNoteHeadings"))
1279
+ self._updateIgnoredKeywords()
1280
+
1281
+ # Text Format
1282
+ # ===========
1283
+
1284
+ font = QFont()
1285
+ font.fromString(self._build.getStr("format.textFont"))
1286
+ self._textFont = fontMatcher(font)
1176
1287
 
1177
1288
  self.textFont.setText(describeFont(self._textFont))
1178
1289
  self.textFont.setCursorPosition(0)
@@ -1184,10 +1295,34 @@ class _FormatTab(NScrollableForm):
1184
1295
  self.keepBreaks.setChecked(self._build.getBool("format.keepBreaks"))
1185
1296
  self.showDialogue.setChecked(self._build.getBool("format.showDialogue"))
1186
1297
 
1298
+ # First Line Indent
1299
+ # =================
1300
+
1187
1301
  self.firstIndent.setChecked(self._build.getBool("format.firstLineIndent"))
1188
1302
  self.indentWidth.setValue(self._build.getFloat("format.firstIndentWidth"))
1189
1303
  self.indentFirstPar.setChecked(self._build.getBool("format.indentFirstPar"))
1190
1304
 
1305
+ # Text Margins
1306
+ # ============
1307
+
1308
+ self.titleMarginT.setValue(self._build.getFloat("format.titleMarginT"))
1309
+ self.titleMarginB.setValue(self._build.getFloat("format.titleMarginB"))
1310
+ self.h1MarginT.setValue(self._build.getFloat("format.h1MarginT"))
1311
+ self.h1MarginB.setValue(self._build.getFloat("format.h1MarginB"))
1312
+ self.h2MarginT.setValue(self._build.getFloat("format.h2MarginT"))
1313
+ self.h2MarginB.setValue(self._build.getFloat("format.h2MarginB"))
1314
+ self.h3MarginT.setValue(self._build.getFloat("format.h3MarginT"))
1315
+ self.h3MarginB.setValue(self._build.getFloat("format.h3MarginB"))
1316
+ self.h4MarginT.setValue(self._build.getFloat("format.h4MarginT"))
1317
+ self.h4MarginB.setValue(self._build.getFloat("format.h4MarginB"))
1318
+ self.textMarginT.setValue(self._build.getFloat("format.textMarginT"))
1319
+ self.textMarginB.setValue(self._build.getFloat("format.textMarginB"))
1320
+ self.sepMarginT.setValue(self._build.getFloat("format.sepMarginT"))
1321
+ self.sepMarginB.setValue(self._build.getFloat("format.sepMarginB"))
1322
+
1323
+ # Page Layout
1324
+ # ===========
1325
+
1191
1326
  pageUnit = self._build.getStr("format.pageUnit")
1192
1327
  index = self.pageUnit.findData(pageUnit)
1193
1328
  if index >= 0:
@@ -1211,10 +1346,36 @@ class _FormatTab(NScrollableForm):
1211
1346
  self.pageUnit.currentIndexChanged.connect(self._changeUnit)
1212
1347
  self.pageSize.currentIndexChanged.connect(self._changePageSize)
1213
1348
 
1349
+ # Document
1350
+ # ========
1351
+
1352
+ self.colorHeadings.setChecked(self._build.getBool("doc.colorHeadings"))
1353
+ self.scaleHeadings.setChecked(self._build.getBool("doc.scaleHeadings"))
1354
+ self.boldHeadings.setChecked(self._build.getBool("doc.boldHeadings"))
1355
+ self.odtPageHeader.setText(self._build.getStr("doc.pageHeader"))
1356
+ self.odtPageCountOffset.setValue(self._build.getInt("doc.pageCountOffset"))
1357
+ self.odtPageHeader.setCursorPosition(0)
1358
+
1359
+ # HTML Document
1360
+ # =============
1361
+
1362
+ self.htmlAddStyles.setChecked(self._build.getBool("html.addStyles"))
1363
+ self.htmlPreserveTabs.setChecked(self._build.getBool("html.preserveTabs"))
1364
+
1214
1365
  return
1215
1366
 
1216
1367
  def saveContent(self) -> None:
1217
1368
  """Save choices back into build object."""
1369
+ # Text Content
1370
+ self._updateIgnoredKeywords()
1371
+ self._build.setValue("text.includeBodyText", self.incBodyText.isChecked())
1372
+ self._build.setValue("text.includeSynopsis", self.incSynopsis.isChecked())
1373
+ self._build.setValue("text.includeComments", self.incComments.isChecked())
1374
+ self._build.setValue("text.includeKeywords", self.incKeywords.isChecked())
1375
+ self._build.setValue("text.ignoredKeywords", self.ignoredKeywords.text())
1376
+ self._build.setValue("text.addNoteHeadings", self.addNoteHead.isChecked())
1377
+
1378
+ # Text Format
1218
1379
  self._build.setValue("format.textFont", self._textFont.toString())
1219
1380
  self._build.setValue("format.lineHeight", self.lineHeight.value())
1220
1381
 
@@ -1224,10 +1385,28 @@ class _FormatTab(NScrollableForm):
1224
1385
  self._build.setValue("format.keepBreaks", self.keepBreaks.isChecked())
1225
1386
  self._build.setValue("format.showDialogue", self.showDialogue.isChecked())
1226
1387
 
1388
+ # First Line Indent
1227
1389
  self._build.setValue("format.firstLineIndent", self.firstIndent.isChecked())
1228
1390
  self._build.setValue("format.firstIndentWidth", self.indentWidth.value())
1229
1391
  self._build.setValue("format.indentFirstPar", self.indentFirstPar.isChecked())
1230
1392
 
1393
+ # Text Margins
1394
+ self._build.setValue("format.titleMarginT", self.titleMarginT.value())
1395
+ self._build.setValue("format.titleMarginB", self.titleMarginB.value())
1396
+ self._build.setValue("format.h1MarginT", self.h1MarginT.value())
1397
+ self._build.setValue("format.h1MarginB", self.h1MarginB.value())
1398
+ self._build.setValue("format.h2MarginT", self.h2MarginT.value())
1399
+ self._build.setValue("format.h2MarginB", self.h2MarginB.value())
1400
+ self._build.setValue("format.h3MarginT", self.h3MarginT.value())
1401
+ self._build.setValue("format.h3MarginB", self.h3MarginB.value())
1402
+ self._build.setValue("format.h4MarginT", self.h4MarginT.value())
1403
+ self._build.setValue("format.h4MarginB", self.h4MarginB.value())
1404
+ self._build.setValue("format.textMarginT", self.textMarginT.value())
1405
+ self._build.setValue("format.textMarginB", self.textMarginB.value())
1406
+ self._build.setValue("format.sepMarginT", self.sepMarginT.value())
1407
+ self._build.setValue("format.sepMarginB", self.sepMarginB.value())
1408
+
1409
+ # Page Layout
1231
1410
  self._build.setValue("format.pageUnit", str(self.pageUnit.currentData()))
1232
1411
  self._build.setValue("format.pageSize", str(self.pageSize.currentData()))
1233
1412
  self._build.setValue("format.pageWidth", self.pageWidth.value())
@@ -1236,6 +1415,18 @@ class _FormatTab(NScrollableForm):
1236
1415
  self._build.setValue("format.bottomMargin", self.bottomMargin.value())
1237
1416
  self._build.setValue("format.leftMargin", self.leftMargin.value())
1238
1417
  self._build.setValue("format.rightMargin", self.rightMargin.value())
1418
+
1419
+ # Documents
1420
+ self._build.setValue("doc.colorHeadings", self.colorHeadings.isChecked())
1421
+ self._build.setValue("doc.scaleHeadings", self.scaleHeadings.isChecked())
1422
+ self._build.setValue("doc.boldHeadings", self.boldHeadings.isChecked())
1423
+ self._build.setValue("doc.pageHeader", self.odtPageHeader.text())
1424
+ self._build.setValue("doc.pageCountOffset", self.odtPageCountOffset.value())
1425
+
1426
+ # HTML Document
1427
+ self._build.setValue("html.addStyles", self.htmlAddStyles.isChecked())
1428
+ self._build.setValue("html.preserveTabs", self.htmlPreserveTabs.isChecked())
1429
+
1239
1430
  return
1240
1431
 
1241
1432
  ##
@@ -1247,9 +1438,9 @@ class _FormatTab(NScrollableForm):
1247
1438
  """Open the QFontDialog and set a font for the font style."""
1248
1439
  font, status = SHARED.getFont(self._textFont, CONFIG.nativeFont)
1249
1440
  if status:
1250
- self.textFont.setText(describeFont(font))
1441
+ self._textFont = fontMatcher(font)
1442
+ self.textFont.setText(describeFont(self._textFont))
1251
1443
  self.textFont.setCursorPosition(0)
1252
- self._textFont = font
1253
1444
  return
1254
1445
 
1255
1446
  @pyqtSlot(int)
@@ -1334,79 +1525,21 @@ class _FormatTab(NScrollableForm):
1334
1525
  self.pageSize.setCurrentIndex(index)
1335
1526
  return
1336
1527
 
1337
-
1338
- class _OutputTab(NScrollableForm):
1339
-
1340
- def __init__(self, parent: QWidget, build: BuildSettings) -> None:
1341
- super().__init__(parent=parent)
1342
-
1343
- self._build = build
1344
-
1345
- iPx = SHARED.theme.baseIconHeight
1346
- iSz = SHARED.theme.baseIconSize
1347
- spW = 6*SHARED.theme.textNWidth
1348
-
1349
- # Open Document
1350
- self.addGroupLabel(self._build.getLabel("odt"))
1351
-
1352
- self.odtAddColours = NSwitch(self, height=iPx)
1353
- self.addRow(self._build.getLabel("odt.addColours"), self.odtAddColours)
1354
-
1355
- self.odtPageHeader = QLineEdit(self)
1356
- self.odtPageHeader.setMinimumWidth(CONFIG.pxInt(200))
1357
- self.btnPageHeader = NIconToolButton(self, iSz, "revert")
1358
- self.btnPageHeader.clicked.connect(self._resetPageHeader)
1359
- self.addRow(
1360
- self._build.getLabel("odt.pageHeader"), self.odtPageHeader,
1361
- button=self.btnPageHeader, stretch=(1, 1)
1362
- )
1363
-
1364
- self.odtPageCountOffset = NSpinBox(self)
1365
- self.odtPageCountOffset.setMinimum(0)
1366
- self.odtPageCountOffset.setMaximum(999)
1367
- self.odtPageCountOffset.setSingleStep(1)
1368
- self.odtPageCountOffset.setMinimumWidth(spW)
1369
- self.addRow(self._build.getLabel("odt.pageCountOffset"), self.odtPageCountOffset)
1370
-
1371
- # HTML Document
1372
- self.addGroupLabel(self._build.getLabel("html"))
1373
-
1374
- self.htmlAddStyles = NSwitch(self, height=iPx)
1375
- self.addRow(self._build.getLabel("html.addStyles"), self.htmlAddStyles)
1376
-
1377
- self.htmlPreserveTabs = NSwitch(self, height=iPx)
1378
- self.addRow(self._build.getLabel("html.preserveTabs"), self.htmlPreserveTabs)
1379
-
1380
- # Finalise
1381
- self.finalise()
1382
-
1383
- return
1384
-
1385
- def loadContent(self) -> None:
1386
- """Populate the widgets."""
1387
- self.odtAddColours.setChecked(self._build.getBool("odt.addColours"))
1388
- self.odtPageHeader.setText(self._build.getStr("odt.pageHeader"))
1389
- self.odtPageCountOffset.setValue(self._build.getInt("odt.pageCountOffset"))
1390
- self.htmlAddStyles.setChecked(self._build.getBool("html.addStyles"))
1391
- self.htmlPreserveTabs.setChecked(self._build.getBool("html.preserveTabs"))
1528
+ def _resetPageHeader(self) -> None:
1529
+ """Reset the ODT header format to default."""
1530
+ self.odtPageHeader.setText(nwHeadFmt.DOC_AUTO)
1392
1531
  self.odtPageHeader.setCursorPosition(0)
1393
1532
  return
1394
1533
 
1395
- def saveContent(self) -> None:
1396
- """Save choices back into build object."""
1397
- self._build.setValue("odt.addColours", self.odtAddColours.isChecked())
1398
- self._build.setValue("odt.pageHeader", self.odtPageHeader.text())
1399
- self._build.setValue("odt.pageCountOffset", self.odtPageCountOffset.value())
1400
- self._build.setValue("html.addStyles", self.htmlAddStyles.isChecked())
1401
- self._build.setValue("html.preserveTabs", self.htmlPreserveTabs.isChecked())
1402
- return
1403
-
1404
1534
  ##
1405
- # Private Slots
1535
+ # Internal Functions
1406
1536
  ##
1407
1537
 
1408
- def _resetPageHeader(self) -> None:
1409
- """Reset the ODT header format to default."""
1410
- self.odtPageHeader.setText(nwHeadFmt.ODT_AUTO)
1411
- self.odtPageHeader.setCursorPosition(0)
1538
+ def _updateIgnoredKeywords(self, keyword: str | None = None) -> None:
1539
+ """Update the ignored keywords list."""
1540
+ current = [x.lower().strip() for x in self.ignoredKeywords.text().split(",")]
1541
+ if keyword:
1542
+ current.append(keyword)
1543
+ verified = set(x for x in current if x in nwKeyWords.VALID_KEYS)
1544
+ self.ignoredKeywords.setText(", ".join(verified))
1412
1545
  return