From 7c1f3144bd3f55905e8d5647b9a838c152eb14bf Mon Sep 17 00:00:00 2001 From: "Veronica K. B. Olsen" <1619840+vkbo@users.noreply.github.com> Date: Mon, 11 May 2020 19:00:01 +0200 Subject: [PATCH] Reworked the title formatting functionality. All keywords can be used in all headings, and also added scene numbers. --- nw/assets/text/exportHelp_en.htm | 31 ++++++----- nw/core/tokenizer.py | 93 ++++++++++++++++++-------------- nw/gui/build.py | 12 ++--- sample/sampleNovel/nwProject.nwx | 10 ++-- 4 files changed, 82 insertions(+), 64 deletions(-) diff --git a/nw/assets/text/exportHelp_en.htm b/nw/assets/text/exportHelp_en.htm index df8eca2a..e921f05d 100644 --- a/nw/assets/text/exportHelp_en.htm +++ b/nw/assets/text/exportHelp_en.htm @@ -1,25 +1,30 @@
A brief guide to make the most out of the Build Project tool.
+A brief guide to make the most out of the Build Novel Project tool.
The format of the various title levels in the files under the Novel folder can be customised in - these settings. The actual title given in the headings of your files will replace all - occurrences of the keyword %title%. Any static text will be left as-is in the + these settings. The actual title given in the headings of your files will for instance replace + all occurrences of the keyword %title%. Any static text will be left as-is in the final title. An empty field means the title isn't written out at all.
The available formatting keywords are:
%title% – This is replaced with the text you put in your headings in your documents
-%num% – This is replaced with the chapter number of your chapter type - headings. These are generated automaticall starting from 1.
-%numword% – This is replaced with the chapter number of your chapter type - headings, but instead of an arabic number, the word for it is used instead, e.g. One, Two, - Fifteen, Twenty-Five, etc.
+%chnum% – This is replaced with the chapter number of your chapter type + headings. These are generated automaticall starting from 1, but ignoring chapter headings in + files with "Unnumbered" layout.
+%chnumword% – This is replaced with the chapter number, but instead of an + arabic number, the word for it is used, e.g. One, Two, Fifteen, Twenty-Five, etc.
+%scnum% – This is replaced with the scene number. The number is reset to one + for each new chapter, so it is the scene number within the current chapter.
+%scabsnum% – This is replaced with the absolute scene number. That is, the + number is counted from the first scene in the novel, and not reset for each chapter.
\\ – Two backslashes are replaced by a line break.
-Note: The Scene format is treated slightly differently than the other title formats. If a - scene format is a constant text, that is, contains no %title%, it will be treated - as a scene separator instead. Scene separators are centred, and not shown if the chapter starts - directly on the first scene. If the field is blank, a large space between the scenes is added - instead.
+Note: The Scene and Section formats are treated slightly differently than the other title + formats. If the format is a constant text, that is, contains no %keyword% tags, it + will be treated as a separator instead. Scene and Section separators are centred, and for + scenes, not shown if placed directly after the chapter heading. For instance, it you want the + classic three asterisk * * * separator between scenes, just put that into the + scene format box, and nothing else.
Novel Outline Mode: This option will build an outline version of the novel rather than the
diff --git a/nw/core/tokenizer.py b/nw/core/tokenizer.py
index 84fbb100..f9d64d45 100644
--- a/nw/core/tokenizer.py
+++ b/nw/core/tokenizer.py
@@ -104,6 +104,8 @@ class Tokenizer():
# Instance Variables
self.numChapter = 0 # Counter for chapter numbers
+ self.numChScene = 0 # Counter for scene number within chapter
+ self.numAbsScene = 0 # Counter for scene number within novel
self.firstScene = False # Flag to indicate that the first scene of the chapter
return
@@ -370,23 +372,53 @@ class Tokenizer():
tType = tToken[0]
tText = tToken[1]
+ # In case we see text before a scene, we reset the flag
if tType == self.T_TEXT:
self.firstScene = False
- elif tType == self.T_HEAD2: # Novel Chapter
- if not isUnNum:
- self.numChapter += 1
- tText = self._formatChapter(tText,isUnNum)
+ elif tType == self.T_HEAD1:
+ # Main Title
+ # ==========
+
+ tText = self._formatHeading(self.fmtTitle, tText)
self.theTokens[n] = (
tType,
tText,
None,
self.A_LEFT | self.A_PBB_R
)
- self.firstScene = True
- elif tType == self.T_HEAD3: # Novel Scene
- tTemp = self._formatScene(tText)
+ elif tType == self.T_HEAD2:
+ # Novel Chapter
+ # =============
+
+ # Numbered or Unnumbered
+ if isUnNum:
+ tText = self._formatHeading(self.fmtUnNum, tText)
+ else:
+ self.numChapter += 1
+ tText = self._formatHeading(self.fmtChapter, tText)
+
+ # Format the chapter header
+ self.theTokens[n] = (
+ tType,
+ tText,
+ None,
+ self.A_LEFT | self.A_PBB_R
+ )
+
+ # Set scene variables
+ self.firstScene = True
+ self.numChScene = 0
+
+ elif tType == self.T_HEAD3:
+ # Novel Scene
+ # ===========
+
+ self.numChScene += 1
+ self.numAbsScene += 1
+
+ tTemp = self._formatHeading(self.fmtScene, tText)
if tTemp == "" and self.hideScene:
self.theTokens[n] = (
self.T_EMPTY,
@@ -431,10 +463,15 @@ class Tokenizer():
None,
self.A_LEFT | self.A_PBA_AV
)
+
+ # Definitely no longer the first scene
self.firstScene = False
- elif tType == self.T_HEAD4: # Novel Section
- tTemp = self._formatSection(tText)
+ elif tType == self.T_HEAD4:
+ # Novel Section
+ # =============
+
+ tTemp = self._formatHeading(self.fmtSection, tText)
if tTemp == "" and self.hideSection:
self.theTokens[n] = (
self.T_EMPTY,
@@ -500,38 +537,14 @@ class Tokenizer():
# Internal Functions
##
- def _formatTitle(self, theText):
- """Replace tokens for headers level 1.
+ def _formatHeading(self, theTitle, theText):
+ """Replaces the %keyword% strings.
"""
- theTitle = self.fmtTitle
- theTitle = theTitle.replace("%title%", theText)
- return theTitle
-
- def _formatChapter(self, theText, noNum):
- """Replace tokens for headers level 2.
- """
- if noNum:
- theTitle = self.fmtUnNum
- theTitle = theTitle.replace("%title%", theText)
- else:
- theTitle = self.fmtChapter
- theTitle = theTitle.replace("%title%", theText)
- theTitle = theTitle.replace("%num%", str(self.numChapter))
- theTitle = theTitle.replace("%numword%", numberToWord(self.numChapter,"en"))
- return theTitle
-
- def _formatScene(self, theText):
- """Replace tokens for headers level 3.
- """
- theTitle = self.fmtScene
- theTitle = theTitle.replace("%title%", theText)
- return theTitle
-
- def _formatSection(self, theText):
- """Replace tokens for headers level 4.
- """
- theTitle = self.fmtSection
- theTitle = theTitle.replace("%title%", theText)
+ theTitle = theTitle.replace(r"%title%", theText)
+ theTitle = theTitle.replace(r"%chnum%", str(self.numChapter))
+ theTitle = theTitle.replace(r"%scnum%", str(self.numChScene))
+ theTitle = theTitle.replace(r"%scabsnum%", str(self.numAbsScene))
+ theTitle = theTitle.replace(r"%chnumword%", numberToWord(self.numChapter,"en"))
return theTitle
# END Class Tokenizer
diff --git a/nw/gui/build.py b/nw/gui/build.py
index 0cca7332..bac21b87 100644
--- a/nw/gui/build.py
+++ b/nw/gui/build.py
@@ -69,7 +69,7 @@ class GuiBuildNovel(QDialog):
self.htmlText = ""
- self.setWindowTitle("Build Project")
+ self.setWindowTitle("Build Novel Project")
self.setMinimumWidth(800)
self.setMinimumHeight(800)
@@ -315,11 +315,11 @@ class GuiBuildNovel(QDialog):
doBodyText = True
if outlineMode:
- fmtTitle = "%title%"
- fmtChapter = "Chapter: %title%"
- fmtUnnumbered = "Chapter: %title%"
- fmtScene = "Scene: %title%"
- fmtSection = "Section: %title%"
+ fmtTitle = r"%title%"
+ fmtChapter = r"Chapter %chnum%: %title%"
+ fmtUnnumbered = r"%title%"
+ fmtScene = r"Scene %chnum%.%scnum%: %title%"
+ fmtSection = r"Section: %title%"
doBodyText = False
incSynopsis = True
novelFiles = True
diff --git a/sample/sampleNovel/nwProject.nwx b/sample/sampleNovel/nwProject.nwx
index eb89f47c..97d54bc9 100644
--- a/sample/sampleNovel/nwProject.nwx
+++ b/sample/sampleNovel/nwProject.nwx
@@ -1,5 +1,5 @@
-