novelWriter 2.3rc1__py3-none-any.whl → 2.4b1__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 (100) hide show
  1. {novelWriter-2.3rc1.dist-info → novelWriter-2.4b1.dist-info}/METADATA +1 -1
  2. {novelWriter-2.3rc1.dist-info → novelWriter-2.4b1.dist-info}/RECORD +99 -85
  3. {novelWriter-2.3rc1.dist-info → novelWriter-2.4b1.dist-info}/WHEEL +1 -1
  4. novelWriter-2.4b1.dist-info/entry_points.txt +2 -0
  5. novelwriter/__init__.py +5 -5
  6. novelwriter/assets/i18n/nw_de_DE.qm +0 -0
  7. novelwriter/assets/i18n/nw_en_US.qm +0 -0
  8. novelwriter/assets/i18n/nw_es_419.qm +0 -0
  9. novelwriter/assets/i18n/nw_fr_FR.qm +0 -0
  10. novelwriter/assets/i18n/nw_it_IT.qm +0 -0
  11. novelwriter/assets/i18n/nw_ja_JP.qm +0 -0
  12. novelwriter/assets/i18n/nw_nb_NO.qm +0 -0
  13. novelwriter/assets/i18n/nw_nl_NL.qm +0 -0
  14. novelwriter/assets/i18n/project_nl_NL.json +11 -0
  15. novelwriter/assets/i18n/project_pt_BR.json +11 -0
  16. novelwriter/assets/icons/typicons_dark/icons.conf +4 -0
  17. novelwriter/assets/icons/typicons_dark/nw_tb-mark.svg +7 -0
  18. novelwriter/assets/icons/typicons_dark/typ_arrow-down.svg +4 -0
  19. novelwriter/assets/icons/typicons_dark/typ_arrow-right.svg +4 -0
  20. novelwriter/assets/icons/typicons_dark/typ_refresh-flipped.svg +1 -1
  21. novelwriter/assets/icons/typicons_dark/typ_refresh.svg +1 -1
  22. novelwriter/assets/icons/typicons_dark/typ_search-grey.svg +4 -0
  23. novelwriter/assets/icons/typicons_dark/typ_times.svg +1 -1
  24. novelwriter/assets/icons/typicons_light/icons.conf +4 -0
  25. novelwriter/assets/icons/typicons_light/nw_tb-mark.svg +7 -0
  26. novelwriter/assets/icons/typicons_light/typ_arrow-down.svg +4 -0
  27. novelwriter/assets/icons/typicons_light/typ_arrow-right.svg +4 -0
  28. novelwriter/assets/icons/typicons_light/typ_refresh-flipped.svg +1 -1
  29. novelwriter/assets/icons/typicons_light/typ_refresh.svg +1 -1
  30. novelwriter/assets/icons/typicons_light/typ_search-grey.svg +4 -0
  31. novelwriter/assets/icons/typicons_light/typ_times.svg +1 -1
  32. novelwriter/assets/manual.pdf +0 -0
  33. novelwriter/assets/sample.zip +0 -0
  34. novelwriter/assets/syntax/cyberpunk_night.conf +26 -0
  35. novelwriter/assets/syntax/default_dark.conf +1 -0
  36. novelwriter/assets/syntax/default_light.conf +1 -0
  37. novelwriter/assets/syntax/grey_dark.conf +1 -0
  38. novelwriter/assets/syntax/grey_light.conf +1 -0
  39. novelwriter/assets/syntax/light_owl.conf +1 -0
  40. novelwriter/assets/syntax/night_owl.conf +1 -0
  41. novelwriter/assets/syntax/solarized_dark.conf +1 -0
  42. novelwriter/assets/syntax/solarized_light.conf +1 -0
  43. novelwriter/assets/syntax/tango.conf +23 -0
  44. novelwriter/assets/syntax/tomorrow.conf +1 -0
  45. novelwriter/assets/syntax/tomorrow_night.conf +1 -0
  46. novelwriter/assets/syntax/tomorrow_night_blue.conf +1 -0
  47. novelwriter/assets/syntax/tomorrow_night_bright.conf +1 -0
  48. novelwriter/assets/syntax/tomorrow_night_eighties.conf +1 -0
  49. novelwriter/assets/text/credits_en.htm +25 -23
  50. novelwriter/assets/themes/cyberpunk_night.conf +29 -0
  51. novelwriter/common.py +1 -1
  52. novelwriter/config.py +35 -12
  53. novelwriter/constants.py +5 -6
  54. novelwriter/core/buildsettings.py +60 -40
  55. novelwriter/core/coretools.py +98 -13
  56. novelwriter/core/docbuild.py +74 -7
  57. novelwriter/core/document.py +24 -3
  58. novelwriter/core/index.py +31 -112
  59. novelwriter/core/project.py +11 -15
  60. novelwriter/core/projectxml.py +2 -1
  61. novelwriter/core/sessions.py +2 -2
  62. novelwriter/core/status.py +4 -4
  63. novelwriter/core/storage.py +16 -6
  64. novelwriter/core/tohtml.py +22 -25
  65. novelwriter/core/tokenizer.py +416 -236
  66. novelwriter/core/tomd.py +17 -8
  67. novelwriter/core/toodt.py +65 -7
  68. novelwriter/core/tree.py +8 -8
  69. novelwriter/dialogs/about.py +2 -2
  70. novelwriter/dialogs/docsplit.py +7 -8
  71. novelwriter/dialogs/preferences.py +3 -6
  72. novelwriter/dialogs/wordlist.py +1 -1
  73. novelwriter/enum.py +17 -14
  74. novelwriter/extensions/configlayout.py +22 -0
  75. novelwriter/extensions/modified.py +20 -2
  76. novelwriter/extensions/versioninfo.py +1 -1
  77. novelwriter/gui/doceditor.py +257 -279
  78. novelwriter/gui/dochighlight.py +29 -25
  79. novelwriter/gui/docviewer.py +139 -148
  80. novelwriter/gui/docviewerpanel.py +4 -24
  81. novelwriter/gui/editordocument.py +12 -1
  82. novelwriter/gui/itemdetails.py +6 -6
  83. novelwriter/gui/mainmenu.py +37 -17
  84. novelwriter/gui/noveltree.py +11 -19
  85. novelwriter/gui/outline.py +43 -20
  86. novelwriter/gui/projtree.py +88 -88
  87. novelwriter/gui/search.py +316 -0
  88. novelwriter/gui/sidebar.py +25 -30
  89. novelwriter/gui/theme.py +68 -8
  90. novelwriter/guimain.py +183 -178
  91. novelwriter/shared.py +26 -1
  92. novelwriter/text/__init__.py +3 -0
  93. novelwriter/text/counting.py +137 -0
  94. novelwriter/tools/manuscript.py +344 -55
  95. novelwriter/tools/manussettings.py +214 -71
  96. novelwriter/tools/noveldetails.py +1 -1
  97. novelwriter/tools/welcome.py +8 -9
  98. novelWriter-2.3rc1.dist-info/entry_points.txt +0 -5
  99. {novelWriter-2.3rc1.dist-info → novelWriter-2.4b1.dist-info}/LICENSE.md +0 -0
  100. {novelWriter-2.3rc1.dist-info → novelWriter-2.4b1.dist-info}/top_level.txt +0 -0
@@ -37,7 +37,7 @@ from PyQt5.QtWidgets import (
37
37
  )
38
38
 
39
39
  from novelwriter import CONFIG, SHARED
40
- from novelwriter.constants import nwHeadFmt, nwLabels, trConst
40
+ from novelwriter.constants import nwHeadFmt, nwKeyWords, nwLabels, trConst
41
41
  from novelwriter.core.buildsettings import BuildSettings, FilterMode
42
42
  from novelwriter.extensions.switch import NSwitch
43
43
  from novelwriter.extensions.modified import NComboBox, NDoubleSpinBox, NSpinBox
@@ -584,7 +584,8 @@ class _HeadingsTab(NScrollablePage):
584
584
  EDIT_CHAPTER = 2
585
585
  EDIT_UNNUM = 3
586
586
  EDIT_SCENE = 4
587
- EDIT_SECTION = 5
587
+ EDIT_HSCENE = 5
588
+ EDIT_SECTION = 6
588
589
 
589
590
  def __init__(self, buildMain: GuiBuildSettings, build: BuildSettings) -> None:
590
591
  super().__init__(parent=buildMain)
@@ -593,122 +594,123 @@ class _HeadingsTab(NScrollablePage):
593
594
  self._editing = 0
594
595
 
595
596
  iPx = SHARED.theme.baseIconSize
597
+ sSp = CONFIG.pxInt(16)
596
598
  vSp = CONFIG.pxInt(12)
597
599
  bSp = CONFIG.pxInt(6)
598
600
 
599
601
  # Format Boxes
600
602
  # ============
601
603
  self.formatBox = QGridLayout()
602
- self.formatBox.setHorizontalSpacing(vSp)
604
+ self.formatBox.setHorizontalSpacing(bSp)
603
605
 
604
606
  # Title Heading
605
- self.lblTitle = QLabel(self._build.getLabel("headings.fmtTitle"))
607
+ self.lblTitle = QLabel(self._build.getLabel("headings.fmtTitle"), self)
606
608
  self.fmtTitle = QLineEdit("", self)
607
609
  self.fmtTitle.setReadOnly(True)
608
610
  self.btnTitle = QToolButton(self)
609
611
  self.btnTitle.setIcon(SHARED.theme.getIcon("edit"))
610
612
  self.btnTitle.clicked.connect(lambda: self._editHeading(self.EDIT_TITLE))
613
+ self.hdeTitle = QLabel(self.tr("Hide"), self)
614
+ self.hdeTitle.setIndent(bSp)
615
+ self.swtTitle = NSwitch(self, height=iPx)
611
616
 
612
- wrapTitle = QHBoxLayout()
613
- wrapTitle.addWidget(self.fmtTitle)
614
- wrapTitle.addWidget(self.btnTitle)
615
- wrapTitle.setSpacing(bSp)
616
-
617
- self.formatBox.addWidget(self.lblTitle, 0, 0, Qt.AlignLeft)
618
- self.formatBox.addLayout(wrapTitle, 0, 1, Qt.AlignLeft)
617
+ self.formatBox.addWidget(self.lblTitle, 0, 0)
618
+ self.formatBox.addWidget(self.fmtTitle, 0, 1)
619
+ self.formatBox.addWidget(self.btnTitle, 0, 2)
620
+ self.formatBox.addWidget(self.hdeTitle, 0, 3)
621
+ self.formatBox.addWidget(self.swtTitle, 0, 4)
619
622
 
620
623
  # Chapter Heading
621
- self.lblChapter = QLabel(self._build.getLabel("headings.fmtChapter"))
624
+ self.lblChapter = QLabel(self._build.getLabel("headings.fmtChapter"), self)
622
625
  self.fmtChapter = QLineEdit("", self)
623
626
  self.fmtChapter.setReadOnly(True)
624
627
  self.btnChapter = QToolButton(self)
625
628
  self.btnChapter.setIcon(SHARED.theme.getIcon("edit"))
626
629
  self.btnChapter.clicked.connect(lambda: self._editHeading(self.EDIT_CHAPTER))
630
+ self.hdeChapter = QLabel(self.tr("Hide"), self)
631
+ self.hdeChapter.setIndent(bSp)
632
+ self.swtChapter = NSwitch(self, height=iPx)
627
633
 
628
- wrapChapter = QHBoxLayout()
629
- wrapChapter.addWidget(self.fmtChapter)
630
- wrapChapter.addWidget(self.btnChapter)
631
- wrapChapter.setSpacing(bSp)
632
-
633
- self.formatBox.addWidget(self.lblChapter, 1, 0, Qt.AlignLeft)
634
- self.formatBox.addLayout(wrapChapter, 1, 1, Qt.AlignLeft)
634
+ self.formatBox.addWidget(self.lblChapter, 1, 0)
635
+ self.formatBox.addWidget(self.fmtChapter, 1, 1)
636
+ self.formatBox.addWidget(self.btnChapter, 1, 2)
637
+ self.formatBox.addWidget(self.hdeChapter, 1, 3)
638
+ self.formatBox.addWidget(self.swtChapter, 1, 4)
635
639
 
636
640
  # Unnumbered Chapter Heading
637
- self.lblUnnumbered = QLabel(self._build.getLabel("headings.fmtUnnumbered"))
641
+ self.lblUnnumbered = QLabel(self._build.getLabel("headings.fmtUnnumbered"), self)
638
642
  self.fmtUnnumbered = QLineEdit("", self)
639
643
  self.fmtUnnumbered.setReadOnly(True)
640
644
  self.btnUnnumbered = QToolButton(self)
641
645
  self.btnUnnumbered.setIcon(SHARED.theme.getIcon("edit"))
642
646
  self.btnUnnumbered.clicked.connect(lambda: self._editHeading(self.EDIT_UNNUM))
647
+ self.hdeUnnumbered = QLabel(self.tr("Hide"), self)
648
+ self.hdeUnnumbered.setIndent(bSp)
649
+ self.swtUnnumbered = NSwitch(self, height=iPx)
643
650
 
644
- wrapUnnumbered = QHBoxLayout()
645
- wrapUnnumbered.addWidget(self.fmtUnnumbered)
646
- wrapUnnumbered.addWidget(self.btnUnnumbered)
647
- wrapUnnumbered.setSpacing(bSp)
648
-
649
- self.formatBox.addWidget(self.lblUnnumbered, 2, 0, Qt.AlignLeft)
650
- self.formatBox.addLayout(wrapUnnumbered, 2, 1, Qt.AlignLeft)
651
+ self.formatBox.addWidget(self.lblUnnumbered, 2, 0)
652
+ self.formatBox.addWidget(self.fmtUnnumbered, 2, 1)
653
+ self.formatBox.addWidget(self.btnUnnumbered, 2, 2)
654
+ self.formatBox.addWidget(self.hdeUnnumbered, 2, 3)
655
+ self.formatBox.addWidget(self.swtUnnumbered, 2, 4)
651
656
 
652
657
  # Scene Heading
653
- sceneHideTip = self._build.getLabel("headings.hideScene")
654
- self.lblScene = QLabel(self._build.getLabel("headings.fmtScene"))
658
+ self.lblScene = QLabel(self._build.getLabel("headings.fmtScene"), self)
655
659
  self.fmtScene = QLineEdit("", self)
656
660
  self.fmtScene.setReadOnly(True)
657
661
  self.btnScene = QToolButton(self)
658
662
  self.btnScene.setIcon(SHARED.theme.getIcon("edit"))
659
663
  self.btnScene.clicked.connect(lambda: self._editHeading(self.EDIT_SCENE))
660
- self.hdeScene = QLabel(self.tr("Hide"))
661
- self.hdeScene.setToolTip(sceneHideTip)
664
+ self.hdeScene = QLabel(self.tr("Hide"), self)
665
+ self.hdeScene.setIndent(bSp)
662
666
  self.swtScene = NSwitch(self, height=iPx)
663
- self.swtScene.setToolTip(sceneHideTip)
664
-
665
- wrapScene = QHBoxLayout()
666
- wrapScene.addWidget(self.fmtScene)
667
- wrapScene.addWidget(self.btnScene)
668
- wrapScene.setSpacing(bSp)
669
-
670
- wrapSceneHide = QHBoxLayout()
671
- wrapSceneHide.addWidget(self.hdeScene)
672
- wrapSceneHide.addWidget(self.swtScene)
673
- wrapSceneHide.setSpacing(bSp)
674
667
 
675
- self.formatBox.addWidget(self.lblScene, 3, 0, Qt.AlignLeft)
676
- self.formatBox.addLayout(wrapScene, 3, 1, Qt.AlignLeft)
677
- self.formatBox.addLayout(wrapSceneHide, 3, 2, Qt.AlignLeft)
668
+ self.formatBox.addWidget(self.lblScene, 3, 0)
669
+ self.formatBox.addWidget(self.fmtScene, 3, 1)
670
+ self.formatBox.addWidget(self.btnScene, 3, 2)
671
+ self.formatBox.addWidget(self.hdeScene, 3, 3)
672
+ self.formatBox.addWidget(self.swtScene, 3, 4)
673
+
674
+ # Alt Scene Heading
675
+ self.lblHScene = QLabel(self._build.getLabel("headings.fmtHardScene"), self)
676
+ self.fmtHScene = QLineEdit("", self)
677
+ self.fmtHScene.setReadOnly(True)
678
+ self.btnHScene = QToolButton(self)
679
+ self.btnHScene.setIcon(SHARED.theme.getIcon("edit"))
680
+ self.btnHScene.clicked.connect(lambda: self._editHeading(self.EDIT_HSCENE))
681
+ self.hdeHScene = QLabel(self.tr("Hide"), self)
682
+ self.hdeHScene.setIndent(bSp)
683
+ self.swtHScene = NSwitch(self, height=iPx)
684
+
685
+ self.formatBox.addWidget(self.lblHScene, 4, 0)
686
+ self.formatBox.addWidget(self.fmtHScene, 4, 1)
687
+ self.formatBox.addWidget(self.btnHScene, 4, 2)
688
+ self.formatBox.addWidget(self.hdeHScene, 4, 3)
689
+ self.formatBox.addWidget(self.swtHScene, 4, 4)
678
690
 
679
691
  # Section Heading
680
- sectionHideTip = self._build.getLabel("headings.hideSection")
681
- self.lblSection = QLabel(self._build.getLabel("headings.fmtSection"))
692
+ self.lblSection = QLabel(self._build.getLabel("headings.fmtSection"), self)
682
693
  self.fmtSection = QLineEdit("", self)
683
694
  self.fmtSection.setReadOnly(True)
684
695
  self.btnSection = QToolButton(self)
685
696
  self.btnSection.setIcon(SHARED.theme.getIcon("edit"))
686
697
  self.btnSection.clicked.connect(lambda: self._editHeading(self.EDIT_SECTION))
687
- self.hdeSection = QLabel(self.tr("Hide"))
688
- self.hdeSection.setToolTip(sectionHideTip)
698
+ self.hdeSection = QLabel(self.tr("Hide"), self)
699
+ self.hdeSection.setIndent(bSp)
689
700
  self.swtSection = NSwitch(self, height=iPx)
690
- self.swtSection.setToolTip(sectionHideTip)
691
701
 
692
- wrapSection = QHBoxLayout()
693
- wrapSection.addWidget(self.fmtSection)
694
- wrapSection.addWidget(self.btnSection)
695
- wrapSection.setSpacing(bSp)
696
-
697
- wrapSectionHide = QHBoxLayout()
698
- wrapSectionHide.addWidget(self.hdeSection)
699
- wrapSectionHide.addWidget(self.swtSection)
700
- wrapSectionHide.setSpacing(bSp)
701
-
702
- self.formatBox.addWidget(self.lblSection, 4, 0, Qt.AlignLeft)
703
- self.formatBox.addLayout(wrapSection, 4, 1, Qt.AlignLeft)
704
- self.formatBox.addLayout(wrapSectionHide, 4, 2, Qt.AlignLeft)
702
+ self.formatBox.addWidget(self.lblSection, 5, 0)
703
+ self.formatBox.addWidget(self.fmtSection, 5, 1)
704
+ self.formatBox.addWidget(self.btnSection, 5, 2)
705
+ self.formatBox.addWidget(self.hdeSection, 5, 3)
706
+ self.formatBox.addWidget(self.swtSection, 5, 4)
705
707
 
706
708
  # Edit Form
707
709
  # =========
708
710
 
709
711
  self.lblEditForm = QLabel(self.tr("Editing: {0}").format(self.tr("None")))
710
712
 
711
- self.editTextBox = QPlainTextEdit()
713
+ self.editTextBox = QPlainTextEdit(self)
712
714
  self.editTextBox.setFixedHeight(5*iPx)
713
715
  self.editTextBox.setEnabled(False)
714
716
 
@@ -735,10 +737,10 @@ class _HeadingsTab(NScrollablePage):
735
737
  self.aInsCharPOV.triggered.connect(lambda: self._insertIntoForm(nwHeadFmt.CHAR_POV))
736
738
  self.aInsCharFocus.triggered.connect(lambda: self._insertIntoForm(nwHeadFmt.CHAR_FOCUS))
737
739
 
738
- self.btnInsert = QPushButton(self.tr("Insert"))
740
+ self.btnInsert = QPushButton(self.tr("Insert"), self)
739
741
  self.btnInsert.setMenu(self.menuInsert)
740
742
 
741
- self.btnApply = QPushButton(self.tr("Apply"))
743
+ self.btnApply = QPushButton(self.tr("Apply"), self)
742
744
  self.btnApply.clicked.connect(self._saveFormat)
743
745
 
744
746
  self.formButtonBox = QHBoxLayout()
@@ -751,13 +753,72 @@ class _HeadingsTab(NScrollablePage):
751
753
  self.editFormBox.addWidget(self.editTextBox)
752
754
  self.editFormBox.addLayout(self.formButtonBox)
753
755
 
756
+ # Layout Matrix
757
+ # =============
758
+ self.layoutMatrix = QGridLayout()
759
+ self.layoutMatrix.setVerticalSpacing(vSp)
760
+ self.layoutMatrix.setHorizontalSpacing(vSp)
761
+
762
+ # Heading
763
+ self.layoutHeading = QLabel("<b>{0}</b>".format(self.tr("Additional Styling")), self)
764
+ self.layoutMatrix.addWidget(self.layoutHeading, 0, 0, 1, 5)
765
+
766
+ # Title Layout
767
+ self.mtxTitle = QLabel(self._build.getLabel("headings.fmtTitle"))
768
+ self.centerTitle = NSwitch(self, height=iPx)
769
+ self.breakTitle = NSwitch(self, height=iPx)
770
+ lblCenterT = QLabel(self.tr("Centre"))
771
+ lblCenterT.setIndent(sSp)
772
+ lblBreakT = QLabel(self.tr("Page Break"))
773
+ lblBreakT.setIndent(sSp)
774
+
775
+ self.layoutMatrix.addWidget(self.mtxTitle, 1, 0)
776
+ self.layoutMatrix.addWidget(lblCenterT, 1, 1)
777
+ self.layoutMatrix.addWidget(self.centerTitle, 1, 2)
778
+ self.layoutMatrix.addWidget(lblBreakT, 1, 3)
779
+ self.layoutMatrix.addWidget(self.breakTitle, 1, 4)
780
+
781
+ # Chapter Layout
782
+ self.mtxChapter = QLabel(self._build.getLabel("headings.fmtChapter"))
783
+ self.centerChapter = NSwitch(self, height=iPx)
784
+ self.breakChapter = NSwitch(self, height=iPx)
785
+ lblCenterC = QLabel(self.tr("Centre"))
786
+ lblCenterC.setIndent(sSp)
787
+ lblBreakC = QLabel(self.tr("Page Break"))
788
+ lblBreakC.setIndent(sSp)
789
+
790
+ self.layoutMatrix.addWidget(self.mtxChapter, 2, 0)
791
+ self.layoutMatrix.addWidget(lblCenterC, 2, 1)
792
+ self.layoutMatrix.addWidget(self.centerChapter, 2, 2)
793
+ self.layoutMatrix.addWidget(lblBreakC, 2, 3)
794
+ self.layoutMatrix.addWidget(self.breakChapter, 2, 4)
795
+
796
+ # Scene Layout
797
+ self.mtxScene = QLabel(self._build.getLabel("headings.fmtScene"))
798
+ self.centerScene = NSwitch(self, height=iPx)
799
+ self.breakScene = NSwitch(self, height=iPx)
800
+ lblCenterS = QLabel(self.tr("Centre"))
801
+ lblCenterS.setIndent(sSp)
802
+ lblBreakS = QLabel(self.tr("Page Break"))
803
+ lblBreakS.setIndent(sSp)
804
+
805
+ self.layoutMatrix.addWidget(self.mtxScene, 3, 0)
806
+ self.layoutMatrix.addWidget(lblCenterS, 3, 1)
807
+ self.layoutMatrix.addWidget(self.centerScene, 3, 2)
808
+ self.layoutMatrix.addWidget(lblBreakS, 3, 3)
809
+ self.layoutMatrix.addWidget(self.breakScene, 3, 4)
810
+
811
+ self.layoutMatrix.setColumnStretch(5, 1)
812
+
754
813
  # Assemble
755
814
  # ========
756
815
 
757
816
  self.outerBox = QVBoxLayout()
758
817
  self.outerBox.addLayout(self.formatBox)
759
- self.outerBox.addSpacing(CONFIG.pxInt(16))
818
+ self.outerBox.addSpacing(sSp)
760
819
  self.outerBox.addLayout(self.editFormBox)
820
+ self.outerBox.addSpacing(sSp)
821
+ self.outerBox.addLayout(self.layoutMatrix)
761
822
  self.outerBox.addStretch(1)
762
823
 
763
824
  self.setCentralLayout(self.outerBox)
@@ -770,15 +831,39 @@ class _HeadingsTab(NScrollablePage):
770
831
  self.fmtChapter.setText(self._build.getStr("headings.fmtChapter"))
771
832
  self.fmtUnnumbered.setText(self._build.getStr("headings.fmtUnnumbered"))
772
833
  self.fmtScene.setText(self._build.getStr("headings.fmtScene"))
834
+ self.fmtHScene.setText(self._build.getStr("headings.fmtHardScene"))
773
835
  self.fmtSection.setText(self._build.getStr("headings.fmtSection"))
836
+
837
+ self.swtTitle.setChecked(self._build.getBool("headings.hideTitle"))
838
+ self.swtChapter.setChecked(self._build.getBool("headings.hideChapter"))
839
+ self.swtUnnumbered.setChecked(self._build.getBool("headings.hideUnnumbered"))
774
840
  self.swtScene.setChecked(self._build.getBool("headings.hideScene"))
841
+ self.swtHScene.setChecked(self._build.getBool("headings.hideHardScene"))
775
842
  self.swtSection.setChecked(self._build.getBool("headings.hideSection"))
843
+
844
+ self.centerTitle.setChecked(self._build.getBool("headings.centerTitle"))
845
+ self.centerChapter.setChecked(self._build.getBool("headings.centerChapter"))
846
+ self.centerScene.setChecked(self._build.getBool("headings.centerScene"))
847
+ self.breakTitle.setChecked(self._build.getBool("headings.breakTitle"))
848
+ self.breakChapter.setChecked(self._build.getBool("headings.breakChapter"))
849
+ self.breakScene.setChecked(self._build.getBool("headings.breakScene"))
776
850
  return
777
851
 
778
852
  def saveContent(self) -> None:
779
853
  """Save choices back into build object."""
854
+ self._build.setValue("headings.hideTitle", self.swtTitle.isChecked())
855
+ self._build.setValue("headings.hideChapter", self.swtChapter.isChecked())
856
+ self._build.setValue("headings.hideUnnumbered", self.swtUnnumbered.isChecked())
780
857
  self._build.setValue("headings.hideScene", self.swtScene.isChecked())
858
+ self._build.setValue("headings.hideHardScene", self.swtHScene.isChecked())
781
859
  self._build.setValue("headings.hideSection", self.swtSection.isChecked())
860
+
861
+ self._build.setValue("headings.centerTitle", self.centerTitle.isChecked())
862
+ self._build.setValue("headings.centerChapter", self.centerChapter.isChecked())
863
+ self._build.setValue("headings.centerScene", self.centerScene.isChecked())
864
+ self._build.setValue("headings.breakTitle", self.breakTitle.isChecked())
865
+ self._build.setValue("headings.breakChapter", self.breakChapter.isChecked())
866
+ self._build.setValue("headings.breakScene", self.breakScene.isChecked())
782
867
  return
783
868
 
784
869
  ##
@@ -809,6 +894,9 @@ class _HeadingsTab(NScrollablePage):
809
894
  elif heading == self.EDIT_SCENE:
810
895
  text = self.fmtScene.text()
811
896
  label = self._build.getLabel("headings.fmtScene")
897
+ elif heading == self.EDIT_HSCENE:
898
+ text = self.fmtHScene.text()
899
+ label = self._build.getLabel("headings.fmtHardScene")
812
900
  elif heading == self.EDIT_SECTION:
813
901
  text = self.fmtSection.text()
814
902
  label = self._build.getLabel("headings.fmtSection")
@@ -844,6 +932,9 @@ class _HeadingsTab(NScrollablePage):
844
932
  elif heading == self.EDIT_SCENE:
845
933
  self.fmtScene.setText(text)
846
934
  self._build.setValue("headings.fmtScene", text)
935
+ elif heading == self.EDIT_HSCENE:
936
+ self.fmtHScene.setText(text)
937
+ self._build.setValue("headings.fmtHardScene", text)
847
938
  elif heading == self.EDIT_SECTION:
848
939
  self.fmtSection.setText(text)
849
940
  self._build.setValue("headings.fmtSection", text)
@@ -894,16 +985,32 @@ class _ContentTab(NScrollableForm):
894
985
  iPx = SHARED.theme.baseIconSize
895
986
 
896
987
  # Text Content
988
+ self.incBodyText = NSwitch(self, height=iPx)
897
989
  self.incSynopsis = NSwitch(self, height=iPx)
898
990
  self.incComments = NSwitch(self, height=iPx)
899
991
  self.incKeywords = NSwitch(self, height=iPx)
900
- self.incBodyText = NSwitch(self, height=iPx)
992
+
993
+ self.ignoredKeywords = QLineEdit(self)
994
+
995
+ self.mnKeywords = QMenu(self)
996
+ for keyword in nwKeyWords.VALID_KEYS:
997
+ self.mnKeywords.addAction(
998
+ trConst(nwLabels.KEY_NAME[keyword]),
999
+ lambda keyword=keyword: self._updateIgnoredKeywords(keyword)
1000
+ )
1001
+
1002
+ self.ignoredKeywordsButton = QToolButton(self)
1003
+ self.ignoredKeywordsButton.setIcon(SHARED.theme.getIcon("add"))
1004
+ self.ignoredKeywordsButton.setMenu(self.mnKeywords)
1005
+ self.ignoredKeywordsButton.setPopupMode(QToolButton.ToolButtonPopupMode.InstantPopup)
901
1006
 
902
1007
  self.addGroupLabel(self._build.getLabel("text.grpContent"))
1008
+ self.addRow(self._build.getLabel("text.includeBodyText"), self.incBodyText)
903
1009
  self.addRow(self._build.getLabel("text.includeSynopsis"), self.incSynopsis)
904
1010
  self.addRow(self._build.getLabel("text.includeComments"), self.incComments)
905
1011
  self.addRow(self._build.getLabel("text.includeKeywords"), self.incKeywords)
906
- self.addRow(self._build.getLabel("text.includeBodyText"), self.incBodyText)
1012
+ self.addRow(self._build.getLabel("text.ignoredKeywords"), self.ignoredKeywords,
1013
+ button=self.ignoredKeywordsButton, stretch=(1, 1))
907
1014
 
908
1015
  # Insert Content
909
1016
  self.addNoteHead = NSwitch(self, height=iPx)
@@ -918,22 +1025,39 @@ class _ContentTab(NScrollableForm):
918
1025
 
919
1026
  def loadContent(self) -> None:
920
1027
  """Populate the widgets."""
1028
+ self.incBodyText.setChecked(self._build.getBool("text.includeBodyText"))
921
1029
  self.incSynopsis.setChecked(self._build.getBool("text.includeSynopsis"))
922
1030
  self.incComments.setChecked(self._build.getBool("text.includeComments"))
923
1031
  self.incKeywords.setChecked(self._build.getBool("text.includeKeywords"))
924
- self.incBodyText.setChecked(self._build.getBool("text.includeBodyText"))
1032
+ self.ignoredKeywords.setText(self._build.getStr("text.ignoredKeywords"))
925
1033
  self.addNoteHead.setChecked(self._build.getBool("text.addNoteHeadings"))
1034
+ self._updateIgnoredKeywords()
926
1035
  return
927
1036
 
928
1037
  def saveContent(self) -> None:
929
1038
  """Save choices back into build object."""
1039
+ self._updateIgnoredKeywords()
1040
+ self._build.setValue("text.includeBodyText", self.incBodyText.isChecked())
930
1041
  self._build.setValue("text.includeSynopsis", self.incSynopsis.isChecked())
931
1042
  self._build.setValue("text.includeComments", self.incComments.isChecked())
932
1043
  self._build.setValue("text.includeKeywords", self.incKeywords.isChecked())
933
- self._build.setValue("text.includeBodyText", self.incBodyText.isChecked())
1044
+ self._build.setValue("text.ignoredKeywords", self.ignoredKeywords.text())
934
1045
  self._build.setValue("text.addNoteHeadings", self.addNoteHead.isChecked())
935
1046
  return
936
1047
 
1048
+ ##
1049
+ # Internal Functions
1050
+ ##
1051
+
1052
+ def _updateIgnoredKeywords(self, keyword: str | None = None) -> None:
1053
+ """Update the ignored keywords list."""
1054
+ current = [x.lower().strip() for x in self.ignoredKeywords.text().split(",")]
1055
+ if keyword:
1056
+ current.append(keyword)
1057
+ verified = set(x for x in current if x in nwKeyWords.VALID_KEYS)
1058
+ self.ignoredKeywords.setText(", ".join(verified))
1059
+ return
1060
+
937
1061
  # END Class _ContentTab
938
1062
 
939
1063
 
@@ -1239,12 +1363,24 @@ class _OutputTab(NScrollableForm):
1239
1363
  self.odtPageCountOffset.setMinimumWidth(spW)
1240
1364
  self.addRow(self._build.getLabel("odt.pageCountOffset"), self.odtPageCountOffset)
1241
1365
 
1366
+ self.odtFirstLineIndent = NSwitch(self, height=iPx)
1367
+ self.addRow(self._build.getLabel("odt.firstLineIndent"), self.odtFirstLineIndent)
1368
+
1242
1369
  # HTML Document
1243
1370
  self.addGroupLabel(self._build.getLabel("html"))
1244
1371
 
1245
1372
  self.htmlAddStyles = NSwitch(self, height=iPx)
1246
1373
  self.addRow(self._build.getLabel("html.addStyles"), self.htmlAddStyles)
1247
1374
 
1375
+ self.htmlPreserveTabs = NSwitch(self, height=iPx)
1376
+ self.addRow(self._build.getLabel("html.preserveTabs"), self.htmlPreserveTabs)
1377
+
1378
+ # Markdown Document
1379
+ self.addGroupLabel(self._build.getLabel("md"))
1380
+
1381
+ self.mdPreserveBreaks = NSwitch(self, height=iPx)
1382
+ self.addRow(self._build.getLabel("md.preserveBreaks"), self.mdPreserveBreaks)
1383
+
1248
1384
  # Finalise
1249
1385
  self.finalise()
1250
1386
 
@@ -1255,7 +1391,10 @@ class _OutputTab(NScrollableForm):
1255
1391
  self.odtAddColours.setChecked(self._build.getBool("odt.addColours"))
1256
1392
  self.odtPageHeader.setText(self._build.getStr("odt.pageHeader"))
1257
1393
  self.odtPageCountOffset.setValue(self._build.getInt("odt.pageCountOffset"))
1394
+ self.odtFirstLineIndent.setChecked(self._build.getBool("odt.firstLineIndent"))
1258
1395
  self.htmlAddStyles.setChecked(self._build.getBool("html.addStyles"))
1396
+ self.htmlPreserveTabs.setChecked(self._build.getBool("html.preserveTabs"))
1397
+ self.mdPreserveBreaks.setChecked(self._build.getBool("md.preserveBreaks"))
1259
1398
  return
1260
1399
 
1261
1400
  def saveContent(self) -> None:
@@ -1263,7 +1402,10 @@ class _OutputTab(NScrollableForm):
1263
1402
  self._build.setValue("odt.addColours", self.odtAddColours.isChecked())
1264
1403
  self._build.setValue("odt.pageHeader", self.odtPageHeader.text())
1265
1404
  self._build.setValue("odt.pageCountOffset", self.odtPageCountOffset.value())
1405
+ self._build.setValue("odt.firstLineIndent", self.odtFirstLineIndent.isChecked())
1266
1406
  self._build.setValue("html.addStyles", self.htmlAddStyles.isChecked())
1407
+ self._build.setValue("html.preserveTabs", self.htmlPreserveTabs.isChecked())
1408
+ self._build.setValue("md.preserveBreaks", self.mdPreserveBreaks.isChecked())
1267
1409
  return
1268
1410
 
1269
1411
  ##
@@ -1273,6 +1415,7 @@ class _OutputTab(NScrollableForm):
1273
1415
  def _resetPageHeader(self) -> None:
1274
1416
  """Reset the ODT header format to default."""
1275
1417
  self.odtPageHeader.setText(nwHeadFmt.ODT_AUTO)
1418
+ self.odtPageHeader.setCursorPosition(0)
1276
1419
  return
1277
1420
 
1278
1421
  # END Class _OutputTab
@@ -216,7 +216,7 @@ class _OverviewPage(NScrollablePage):
216
216
  self.projForm.addRow("<b>{0}</b>".format(self.tr("Editing Time")), self.projEditTime)
217
217
  self.projForm.addRow("<b>{0}</b>".format(self.tr("Word Count")), self.projWords)
218
218
  self.projForm.addRow("<b>\u2026 {0}</b>".format(self.tr("In Novels")), self.projNovels)
219
- self.projForm.addRow("<b>\u2026 {0}</b>".format(self.tr("In Notes ")), self.projNotes)
219
+ self.projForm.addRow("<b>\u2026 {0}</b>".format(self.tr("In Notes")), self.projNotes)
220
220
  self.projForm.setContentsMargins(mPx, 0, 0, 0)
221
221
  self.projForm.setHorizontalSpacing(hPx)
222
222
  self.projForm.setVerticalSpacing(vPx)
@@ -45,6 +45,7 @@ from novelwriter.enum import nwItemClass
45
45
  from novelwriter.common import formatInt, makeFileNameSafe
46
46
  from novelwriter.constants import nwFiles
47
47
  from novelwriter.core.coretools import ProjectBuilder
48
+ from novelwriter.extensions.configlayout import NWrappedWidgetBox
48
49
  from novelwriter.extensions.switch import NSwitch
49
50
  from novelwriter.extensions.modified import NSpinBox
50
51
  from novelwriter.extensions.versioninfo import VersionInfoWidget
@@ -455,7 +456,7 @@ class _ProjectListModel(QAbstractListModel):
455
456
  opened = self.tr("Last Opened")
456
457
  records = sorted(CONFIG.recentProjects.listEntries(), key=lambda x: x[3], reverse=True)
457
458
  for path, title, count, time in records:
458
- when = datetime.fromtimestamp(time).strftime("%x")
459
+ when = CONFIG.localDate(datetime.fromtimestamp(time))
459
460
  data.append((title, path, f"{opened}: {when}, {words}: {formatInt(count)}"))
460
461
  self._data = data
461
462
  return
@@ -630,20 +631,18 @@ class _NewProjectForm(QWidget):
630
631
  self.numChapters.setValue(5)
631
632
  self.numChapters.setToolTip(self.tr("Set to 0 to only add scenes"))
632
633
 
633
- self.chapterBox = QHBoxLayout()
634
- self.chapterBox.addWidget(QLabel(self.tr("Add")))
635
- self.chapterBox.addWidget(self.numChapters)
636
- self.chapterBox.addWidget(QLabel(self.tr("chapter documents")))
634
+ self.chapterBox = NWrappedWidgetBox(
635
+ self.tr("Add {0} chapter documents"), self.numChapters
636
+ )
637
637
  self.chapterBox.addStretch(1)
638
638
 
639
639
  self.numScenes = NSpinBox(self)
640
640
  self.numScenes.setRange(0, 200)
641
641
  self.numScenes.setValue(5)
642
642
 
643
- self.sceneBox = QHBoxLayout()
644
- self.sceneBox.addWidget(QLabel(self.tr("Add")))
645
- self.sceneBox.addWidget(self.numScenes)
646
- self.sceneBox.addWidget(QLabel(self.tr("scene documents (to each chapter)")))
643
+ self.sceneBox = NWrappedWidgetBox(
644
+ self.tr("Add {0} scene documents (to each chapter)"), self.numScenes
645
+ )
647
646
  self.sceneBox.addStretch(1)
648
647
 
649
648
  self.novelForm = QVBoxLayout()
@@ -1,5 +0,0 @@
1
- [console_script]
2
- novelwriter-cli = novelwriter:main
3
-
4
- [gui_scripts]
5
- novelwriter = novelwriter:main