Add highlight text shortcode (#1715)

This commit is contained in:
Veronica Berglyd Olsen
2024-02-26 22:43:52 +01:00
committed by GitHub
38 changed files with 313 additions and 148 deletions
+3 -1
View File
@@ -58,9 +58,11 @@ Some of the assets bundled with novelWriter were adapted from the following sour
## Fonts
The font used for the main novelWriter logo, mimetype and text banners is:
The font used for the main novelWriter logo, mimetype and text banners is Pridi. Other fonts are
used on buttons and icons.
* Pridi by Cadson Demak (Open Font License, Version 1.1)
* Source Sans Pro by Paul D. Hunt (SIL Open Font License)
## Special Mentions
+11 -6
View File
@@ -179,15 +179,20 @@ A syntax theme ``.conf`` file consists of the following settings:
errorline = 0, 0, 0
replacetag = 0, 0, 0
modifier = 0, 0, 0
texthighlight = 255, 255, 255, 128
In the Main section, you must define at least the ``name`` setting. The Syntax colour values are
RGB numbers of the format ``r, g, b`` where each is an integer from to 255. Omitted values default
to black, except ``background`` which defaults to white,
RGB(A) numbers of the format ``r, g, b, a`` where each is an integer from to 255. The fourth value
is the alpha channel, which can be omitted.
Omitted syntax colours default to black, except ``background`` which defaults to white, and
``texthighlight`` which defaults to grey.
.. versionadded:: 2.2
The `shortcode` syntax colour entry was added, so you need to update your custom themes if you
made any before version 2.2.
The `shortcode` syntax colour entry was added.
.. versionadded:: 2.3
The `optional` syntax colour entry was added, so you need to update your custom themes if you
made any before version 2.3.
The `optional` syntax colour entry was added.
.. versionadded:: 2.4
The `texthighlight` syntax colour entry was added.
@@ -53,6 +53,7 @@ fmt_bold = nw_tb-bold.svg
fmt_bold-md = nw_tb-bold-md.svg
fmt_italic = nw_tb-italic.svg
fmt_italic-md = nw_tb-italic-md.svg
fmt_mark = nw_tb-mark.svg
fmt_strike = nw_tb-strike.svg
fmt_strike-md = nw_tb-strike-md.svg
fmt_subscript = nw_tb-subscript.svg
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="24" height="24" version="1.1" viewBox="0 0 6.35 6.35" xmlns="http://www.w3.org/2000/svg">
<rect x=".26458" y=".79375" width="5.8208" height="4.7625" fill="#ffff84" fill-opacity=".8" stroke-linecap="round" stroke-width=".1354"/>
<path d="m1.3229 5.2917v-4.2333h0.98087l0.6397 1.8829q0.060924 0.18829 0.11576 0.38957 0.054831 0.19479 0.11576 0.38957h0.024369q0.060924-0.19479 0.10966-0.38957 0.054831-0.20128 0.11576-0.38957l0.62752-1.8829h0.97478v4.2333h-0.81638v-1.5518q0-0.15583 0.012185-0.34412 0.012185-0.18829 0.030462-0.37658 0.018277-0.19479 0.036554-0.37658 0.018277-0.18829 0.036554-0.34412h-0.02437l-0.3229 1.0064-0.56659 1.6167h-0.49348l-0.56659-1.6167-0.3168-1.0064h-0.024369q0.018277 0.15583 0.036554 0.34412 0.018277 0.1818 0.036554 0.37658 0.018277 0.18829 0.030462 0.37658 0.012185 0.18829 0.012185 0.34412v1.5518z" fill="#808080" stroke-linecap="round" stroke-width=".11793"/>
<path d="m4.9555 5.5562v-0.43195h0.54619v-3.8986h-0.54619v-0.43195h1.1299v4.7624z" fill="#69c" stroke-width="1.1186"/>
<path d="m0.26458 5.5562v-4.7624h1.1299v0.43195h-0.54083v3.8986h0.54083v0.43195z" fill="#69c" stroke-width="1.1186"/>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

@@ -53,6 +53,7 @@ fmt_bold = nw_tb-bold.svg
fmt_bold-md = nw_tb-bold-md.svg
fmt_italic = nw_tb-italic.svg
fmt_italic-md = nw_tb-italic-md.svg
fmt_mark = nw_tb-mark.svg
fmt_strike = nw_tb-strike.svg
fmt_strike-md = nw_tb-strike-md.svg
fmt_subscript = nw_tb-subscript.svg
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="24" height="24" version="1.1" viewBox="0 0 6.35 6.35" xmlns="http://www.w3.org/2000/svg">
<rect x=".26458" y=".79375" width="5.8208" height="4.7625" fill="#ad8700" fill-opacity=".8" stroke-linecap="round" stroke-width=".1354"/>
<path d="m1.3229 5.2917v-4.2333h0.98087l0.6397 1.8829q0.060924 0.18829 0.11576 0.38957 0.054831 0.19479 0.11576 0.38957h0.024369q0.060924-0.19479 0.10966-0.38957 0.054831-0.20128 0.11576-0.38957l0.62752-1.8829h0.97478v4.2333h-0.81638v-1.5518q0-0.15583 0.012185-0.34412 0.012185-0.18829 0.030462-0.37658 0.018277-0.19479 0.036554-0.37658 0.018277-0.18829 0.036554-0.34412h-0.02437l-0.3229 1.0064-0.56659 1.6167h-0.49348l-0.56659-1.6167-0.3168-1.0064h-0.024369q0.018277 0.15583 0.036554 0.34412 0.018277 0.1818 0.036554 0.37658 0.018277 0.18829 0.030462 0.37658 0.012185 0.18829 0.012185 0.34412v1.5518z" fill-opacity=".78039" stroke-linecap="round" stroke-width=".11793"/>
<path d="m4.9555 5.5562v-0.43195h0.54619v-3.8986h-0.54619v-0.43195h1.1299v4.7624z" fill="#4271ae" stroke-width="1.1186"/>
<path d="m0.26458 5.5562v-4.7624h1.1299v0.43195h-0.54083v3.8986h0.54083v0.43195z" fill="#4271ae" stroke-width="1.1186"/>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

@@ -25,3 +25,4 @@ spellcheckline = 200, 46, 0
errorline = 46, 200, 0
replacetag = 0, 184, 46
modifier = 200, 120, 0
texthighlight = 136, 200, 0, 96
@@ -25,3 +25,4 @@ spellcheckline = 200, 0, 0
errorline = 0, 150, 0
replacetag = 0, 150, 0
modifier = 150, 110, 30
texthighlight = 150, 150, 0, 96
+1
View File
@@ -25,3 +25,4 @@ spellcheckline = 200, 46, 0
errorline = 46, 200, 0
replacetag = 225, 225, 225
modifier = 225, 225, 225
texthighlight = 255, 255, 255, 64
@@ -25,3 +25,4 @@ spellcheckline = 200, 0, 0
errorline = 0, 150, 0
replacetag = 0, 0, 0
modifier = 0, 0, 0
texthighlight = 0, 0, 0, 64
+1
View File
@@ -45,3 +45,4 @@ spellcheckline = 222, 61, 58
errorline = 8, 145, 106
replacetag = 42, 162, 152
modifier = 224, 175, 5
texthighlight = 218, 170, 1, 96
+1
View File
@@ -45,3 +45,4 @@ spellcheckline = 247, 140, 108
errorline = 173, 219, 103
replacetag = 127, 219, 202
modifier = 236, 196, 141
texthighlight = 255, 235, 149, 96
@@ -25,3 +25,4 @@ spellcheckline = 203, 75, 22
errorline = 220, 50, 47
replacetag = 133, 153, 0
modifier = 181, 137, 0
texthighlight = 181, 137, 0, 96
@@ -25,3 +25,4 @@ spellcheckline = 203, 75, 22
errorline = 220, 50, 47
replacetag = 133, 153, 0
modifier = 181, 137, 0
texthighlight = 181, 137, 0, 96
+1
View File
@@ -45,3 +45,4 @@ spellcheckline = 240, 40, 41
errorline = 113, 140, 0
replacetag = 62, 153, 159
modifier = 245, 135, 31
texthighlight = 234, 183, 0, 96
@@ -45,3 +45,4 @@ spellcheckline = 204, 102, 102
errorline = 181, 189, 104
replacetag = 138, 190, 183
modifier = 222, 147, 95
texthighlight = 240, 198, 116, 96
@@ -45,3 +45,4 @@ spellcheckline = 255, 157, 164
errorline = 209, 241, 169
replacetag = 153, 255, 255
modifier = 255, 197, 143
texthighlight = 255, 238, 173, 96
@@ -45,3 +45,4 @@ spellcheckline = 213, 78, 83
errorline = 185, 202, 74
replacetag = 112, 192, 177
modifier = 231, 140, 69
texthighlight = 231, 197, 71, 128
@@ -45,3 +45,4 @@ spellcheckline = 242, 119, 122
errorline = 153, 204, 153
replacetag = 102, 204, 204
modifier = 249, 145, 57
texthighlight = 255, 204, 102, 96
+25 -23
View File
@@ -8,9 +8,9 @@
<h3>Contributors</h3>
<p>
<b>Concept:</b> Marian Lückhof (<a href="https://github.com/Number042">@Number042</a>)<br>
<b>Internationalisation:</b> Bruno Meneguello (<a href="https://github.com/bkmeneguello">@bkmeneguello</a>)<br>
<b>Setup and Packaging:</b> Rachel Powers (<a href="https://github.com/Ryex">@Ryex</a>)
&nbsp;&bull;&nbsp;<b>Concept:</b> Marian Lückhof (<a href="https://github.com/Number042">@Number042</a>)<br>
&nbsp;&bull;&nbsp;<b>Internationalisation:</b> Bruno Meneguello (<a href="https://github.com/bkmeneguello">@bkmeneguello</a>)<br>
&nbsp;&bull;&nbsp;<b>Setup and Packaging:</b> Rachel Powers (<a href="https://github.com/Ryex">@Ryex</a>)
</p>
<p>For other contributions, see the project's
<a href="https://github.com/vkbo/novelWriter/graphs/contributors">Contributors</a> page.</p>
@@ -24,20 +24,20 @@
<p>The default language is English (UK) with English (US) as an option. These are the original
translators for the languages currently available:</p>
<p>
<b>Dutch:</b> Martijn van der Kleijn (<a href="https://github.com/mvdkleijn">@mvdkleijn</a>)<br>
<b>French:</b> Jan Lüdke (<a href="https://github.com/jyhelle">@jyhelle</a>)<br>
<b>German:</b> Myian (<a href="https://github.com/heymyian">@heymyian</a>)<br>
<b>Italian:</b> Riccardo Mangili<br>
<b>Japanese:</b> hebekeg (<a href="https://github.com/hebekeg">@hebekeg</a>)<br>
<b>Latin American Spanish:</b> Tommy Marplatt (<a href="https://github.com/tmarplatt">@tmarplatt</a>)<br>
<b>Norwegian:</b> Veronica Berglyd Olsen (<a href="https://github.com/vkbo">@vkbo</a>)<br>
<b>Portuguese:</b> Bruno Meneguello (<a href="https://github.com/bkmeneguello">@bkmeneguello</a>)<br>
<b>Simplified Chinese:</b> Qianzhi Long (<a href="https://github.com/longqzh">@longqzh</a>)
&nbsp;&bull;&nbsp;<b>Dutch:</b> Martijn van der Kleijn (<a href="https://github.com/mvdkleijn">@mvdkleijn</a>)<br>
&nbsp;&bull;&nbsp;<b>French:</b> Jan Lüdke (<a href="https://github.com/jyhelle">@jyhelle</a>)<br>
&nbsp;&bull;&nbsp;<b>German:</b> Myian (<a href="https://github.com/heymyian">@heymyian</a>)<br>
&nbsp;&bull;&nbsp;<b>Italian:</b> Riccardo Mangili<br>
&nbsp;&bull;&nbsp;<b>Japanese:</b> hebekeg (<a href="https://github.com/hebekeg">@hebekeg</a>)<br>
&nbsp;&bull;&nbsp;<b>Latin American Spanish:</b> Tommy Marplatt (<a href="https://github.com/tmarplatt">@tmarplatt</a>)<br>
&nbsp;&bull;&nbsp;<b>Norwegian:</b> Veronica Berglyd Olsen (<a href="https://github.com/vkbo">@vkbo</a>)<br>
&nbsp;&bull;&nbsp;<b>Portuguese:</b> Bruno Meneguello (<a href="https://github.com/bkmeneguello">@bkmeneguello</a>)<br>
&nbsp;&bull;&nbsp;<b>Simplified Chinese:</b> Qianzhi Long (<a href="https://github.com/longqzh">@longqzh</a>)
</p>
<p>Additional larger translation contributions:</p>
<p>
<b>French:</b> Albert Aribaud (<a href="https://github.com/aaribaud">@aaribaud</a>)
&nbsp;&bull;&nbsp;<b>French:</b> Albert Aribaud (<a href="https://github.com/aaribaud">@aaribaud</a>)
</p>
<p>Translations are managed on <a href="https://crowdin.com/project/novelwriter">Crowdin</a>, and
@@ -47,27 +47,29 @@ more contributions are listed on the project's <a href="https://crowdin.com/proj
<p>The following libraries are dependencies of novelWriter:</p>
<p>
<a href="https://www.qt.io">Qt5</a> by Qt Company<br>
<a href="https://www.riverbankcomputing.com/software/pyqt">PyQt5</a> by Riverbank Computing<br>
<a href="https://abiword.github.io/enchant">Enchant</a> by Dom Lachowicz<br>
<a href="https://pyenchant.github.io/pyenchant">PyEnchant</a> by Dimitri Merejkowsky
&nbsp;&bull;&nbsp;<a href="https://www.qt.io">Qt5</a> by Qt Company<br>
&nbsp;&bull;&nbsp;<a href="https://www.riverbankcomputing.com/software/pyqt">PyQt5</a> by Riverbank Computing<br>
&nbsp;&bull;&nbsp;<a href="https://abiword.github.io/enchant">Enchant</a> by Dom Lachowicz<br>
&nbsp;&bull;&nbsp;<a href="https://pyenchant.github.io/pyenchant">PyEnchant</a> by Dimitri Merejkowsky
</p>
<h3>Assets</h3>
<p>Some of the assets bundled with novelWriter were adapted from the following sources:</p>
<p>
<a href="https://github.com/stephenhutchings/typicons.font">Typicons</a> icons by Stephen Hutchings (CC BY-SA 4.0)<br>
<a href="https://github.com/chriskempson/base16">Tomorrow</a> syntax themes by Chris Kempson (MIT License)<br>
<a href="https://github.com/sdras/night-owl-vscode-theme">Owl</a> syntax themes by Sarah Drasner (MIT License)<br>
<a href="https://github.com/altercation/solarized">Solarized</a> themes by Ethan Schoonover (MIT License)
&nbsp;&bull;&nbsp;<a href="https://github.com/stephenhutchings/typicons.font">Typicons</a> icons by Stephen Hutchings (CC BY-SA 4.0)<br>
&nbsp;&bull;&nbsp;<a href="https://github.com/chriskempson/base16">Tomorrow</a> syntax themes by Chris Kempson (MIT License)<br>
&nbsp;&bull;&nbsp;<a href="https://github.com/sdras/night-owl-vscode-theme">Owl</a> syntax themes by Sarah Drasner (MIT License)<br>
&nbsp;&bull;&nbsp;<a href="https://github.com/altercation/solarized">Solarized</a> themes by Ethan Schoonover (MIT License)
</p>
<h3>Fonts</h3>
<p>The font used for the main novelWriter logo, mimetype and text banners is:</p>
<p>The font used for the main novelWriter logo, mimetype and text banners is Pridi. Other fonts are
used on buttons and icons.</p>
<p>
Pridi by Cadson Demak (Open Font License, Version 1.1)
&nbsp;&bull;&nbsp;Pridi by Cadson Demak (Open Font License, Version 1.1)<br>
&nbsp;&bull;&nbsp;Source Sans Pro by Paul D. Hunt (SIL Open Font License)
</p>
<h3>Special Mentions</h3>
+3 -1
View File
@@ -67,7 +67,7 @@ class nwRegEx:
FMT_EI = r"(?<![\w\\])(_)(?![\s_])(.+?)(?<![\s\\])(\1)(?!\w)"
FMT_EB = r"(?<![\w\\])([\*]{2})(?![\s\*])(.+?)(?<![\s\\])(\1)(?!\w)"
FMT_ST = r"(?<![\w\\])([~]{2})(?![\s~])(.+?)(?<![\s\\])(\1)(?!\w)"
FMT_SC = r"(?i)(?<!\\)(\[[\/\!]?(?:i|b|s|u|sup|sub)\])"
FMT_SC = r"(?i)(?<!\\)(\[[\/\!]?(?:i|b|s|u|m|sup|sub)\])"
FMT_SV = r"(?<!\\)(\[(?i)(?:fn|footnote):)(.+?)(?<!\\)(\])"
# Pre-Compiled RegEx
@@ -86,6 +86,8 @@ class nwShortcode:
STRIKE_C = "[/s]"
ULINE_O = "[u]"
ULINE_C = "[/u]"
MARK_O = "[m]"
MARK_C = "[/m]"
SUP_O = "[sup]"
SUP_C = "[/sup]"
SUB_O = "[sub]"
+4
View File
@@ -133,6 +133,8 @@ class ToHtml(Tokenizer):
self.FMT_D_E: "</span>",
self.FMT_U_B: "<u>",
self.FMT_U_E: "</u>",
self.FMT_M_B: "<mark>",
self.FMT_M_E: "</mark>",
}
else:
htmlTags = { # HTML5 (for export)
@@ -144,6 +146,8 @@ class ToHtml(Tokenizer):
self.FMT_D_E: "</del>",
self.FMT_U_B: "<span style='text-decoration: underline;'>",
self.FMT_U_E: "</span>",
self.FMT_M_B: "<mark>",
self.FMT_M_E: "</mark>",
}
htmlTags[self.FMT_SUP_B] = "<sup>"
+7 -4
View File
@@ -74,10 +74,12 @@ class Tokenizer(ABC):
FMT_D_E = 6 # End strikeout
FMT_U_B = 7 # Begin underline
FMT_U_E = 8 # End underline
FMT_SUP_B = 9 # Begin superscript
FMT_SUP_E = 10 # End superscript
FMT_SUB_B = 11 # Begin subscript
FMT_SUB_E = 12 # End subscript
FMT_M_B = 9 # Begin mark
FMT_M_E = 10 # End mark
FMT_SUP_B = 11 # Begin superscript
FMT_SUP_E = 12 # End superscript
FMT_SUB_B = 13 # Begin subscript
FMT_SUB_E = 14 # End subscript
# Block Type
T_EMPTY = 1 # Empty line (new paragraph)
@@ -187,6 +189,7 @@ class Tokenizer(ABC):
nwShortcode.BOLD_O: self.FMT_B_B, nwShortcode.BOLD_C: self.FMT_B_E,
nwShortcode.STRIKE_O: self.FMT_D_B, nwShortcode.STRIKE_C: self.FMT_D_E,
nwShortcode.ULINE_O: self.FMT_U_B, nwShortcode.ULINE_C: self.FMT_U_E,
nwShortcode.MARK_O: self.FMT_M_B, nwShortcode.MARK_C: self.FMT_M_E,
nwShortcode.SUP_O: self.FMT_SUP_B, nwShortcode.SUP_C: self.FMT_SUP_E,
nwShortcode.SUB_O: self.FMT_SUB_B, nwShortcode.SUB_C: self.FMT_SUB_E,
}
+4
View File
@@ -95,6 +95,8 @@ class ToMarkdown(Tokenizer):
self.FMT_D_E: "",
self.FMT_U_B: "",
self.FMT_U_E: "",
self.FMT_M_B: "",
self.FMT_M_E: "",
self.FMT_SUP_B: "",
self.FMT_SUP_E: "",
self.FMT_SUB_B: "",
@@ -111,6 +113,8 @@ class ToMarkdown(Tokenizer):
self.FMT_D_E: "~~",
self.FMT_U_B: "",
self.FMT_U_E: "",
self.FMT_M_B: "==",
self.FMT_M_E: "==",
self.FMT_SUP_B: "^",
self.FMT_SUP_E: "^",
self.FMT_SUB_B: "~",
+19 -2
View File
@@ -84,14 +84,16 @@ X_BLD = 0x01 # Bold format
X_ITA = 0x02 # Italic format
X_DEL = 0x04 # Strikethrough format
X_UND = 0x08 # Underline format
X_SUP = 0x10 # Superscript
X_SUB = 0x20 # Subscript
X_MRK = 0x10 # Marked format
X_SUP = 0x20 # Superscript
X_SUB = 0x40 # Subscript
# Formatting Masks
M_BLD = ~X_BLD
M_ITA = ~X_ITA
M_DEL = ~X_DEL
M_UND = ~X_UND
M_MRK = ~X_MRK
M_SUP = ~X_SUP
M_SUB = ~X_SUB
@@ -189,6 +191,7 @@ class ToOdt(Tokenizer):
self._opaHead34 = None
self._colMetaTx = None
self._opaMetaTx = None
self._markText = "#ffffa6"
return
@@ -643,6 +646,10 @@ class ToOdt(Tokenizer):
xFmt |= X_UND
elif fFmt == self.FMT_U_E:
xFmt &= M_UND
elif fFmt == self.FMT_M_B:
xFmt |= X_MRK
elif fFmt == self.FMT_M_E:
xFmt &= M_MRK
elif fFmt == self.FMT_SUP_B:
xFmt |= X_SUP
elif fFmt == self.FMT_SUP_E:
@@ -710,6 +717,8 @@ class ToOdt(Tokenizer):
newStyle.setUnderlineStyle("solid")
newStyle.setUnderlineWidth("auto")
newStyle.setUnderlineColour("font-color")
if hFmt & X_MRK:
newStyle.setBackgroundColor(self._markText)
if hFmt & X_SUP:
newStyle.setTextPosition("super")
if hFmt & X_SUB:
@@ -1279,6 +1288,7 @@ class ODTTextStyle:
self._tAttr = {
"font-weight": ["fo", None],
"font-style": ["fo", None],
"background-color": ["fo", None],
"text-position": ["style", None],
"text-line-through-style": ["style", None],
"text-line-through-type": ["style", None],
@@ -1306,6 +1316,13 @@ class ODTTextStyle:
self._tAttr["font-style"][1] = None
return
def setBackgroundColor(self, value: str | None) -> None:
if value and len(value) == 7 and value[0] == "#":
self._tAttr["background-color"][1] = value
else:
self._tAttr["background-color"][1] = None
return
def setTextPosition(self, value: str | None) -> None:
if value in self.VALID_POS:
self._tAttr["text-position"][1] = f"{value} 58%"
+3 -2
View File
@@ -124,8 +124,9 @@ class nwDocAction(Enum):
SC_BOLD = 31
SC_STRIKE = 32
SC_ULINE = 33
SC_SUP = 34
SC_SUB = 35
SC_MARK = 34
SC_SUP = 35
SC_SUB = 36
# END Enum nwDocAction
+11
View File
@@ -769,6 +769,8 @@ class GuiDocEditor(QPlainTextEdit):
self._wrapSelection(nwShortcode.STRIKE_O, nwShortcode.STRIKE_C)
elif action == nwDocAction.SC_ULINE:
self._wrapSelection(nwShortcode.ULINE_O, nwShortcode.ULINE_C)
elif action == nwDocAction.SC_MARK:
self._wrapSelection(nwShortcode.MARK_O, nwShortcode.MARK_C)
elif action == nwDocAction.SC_SUP:
self._wrapSelection(nwShortcode.SUP_O, nwShortcode.SUP_C)
elif action == nwDocAction.SC_SUB:
@@ -2313,6 +2315,13 @@ class GuiDocToolBar(QWidget):
lambda: self.requestDocAction.emit(nwDocAction.SC_ULINE)
)
self.tbMark = QToolButton(self)
self.tbMark.setIconSize(iconSize)
self.tbMark.setToolTip(self.tr("Shortcode Highlight"))
self.tbMark.clicked.connect(
lambda: self.requestDocAction.emit(nwDocAction.SC_MARK)
)
self.tbSuperscript = QToolButton(self)
self.tbSuperscript.setIconSize(iconSize)
self.tbSuperscript.setToolTip(self.tr("Shortcode Superscript"))
@@ -2339,6 +2348,7 @@ class GuiDocToolBar(QWidget):
self.outerBox.addWidget(self.tbItalic)
self.outerBox.addWidget(self.tbStrike)
self.outerBox.addWidget(self.tbUnderline)
self.outerBox.addWidget(self.tbMark)
self.outerBox.addWidget(self.tbSuperscript)
self.outerBox.addWidget(self.tbSubscript)
self.outerBox.setContentsMargins(cM, cM, cM, cM)
@@ -2369,6 +2379,7 @@ class GuiDocToolBar(QWidget):
self.tbItalic.setIcon(SHARED.theme.getIcon("fmt_italic"))
self.tbStrike.setIcon(SHARED.theme.getIcon("fmt_strike"))
self.tbUnderline.setIcon(SHARED.theme.getIcon("fmt_underline"))
self.tbMark.setIcon(SHARED.theme.getIcon("fmt_mark"))
self.tbSuperscript.setIcon(SHARED.theme.getIcon("fmt_superscript"))
self.tbSubscript.setIcon(SHARED.theme.getIcon("fmt_subscript"))
+18 -36
View File
@@ -466,48 +466,30 @@ class GuiDocViewer(QTextBrowser):
colText = SHARED.theme.colText
colHead = SHARED.theme.colHead
colVals = SHARED.theme.colVal
colEmph = SHARED.theme.colEmph
colMark = SHARED.theme.colMark
colKeys = SHARED.theme.colKey
colHide = SHARED.theme.colHidden
colMods = SHARED.theme.colMod
colOpts = SHARED.theme.colOpt
styleSheet = (
"body {{"
" color: rgb({tColR}, {tColG}, {tColB});"
"}}\n"
"h1, h2, h3, h4 {{"
" color: rgb({hColR}, {hColG}, {hColB});"
"}}\n"
"a {{"
" color: rgb({aColR}, {aColG}, {aColB});"
"}}\n"
"mark {{"
" color: rgb({eColR}, {eColG}, {eColB});"
"}}\n"
".tags {{"
" color: rgb({kColR}, {kColG}, {kColB});"
"}}\n"
".optional {{"
" color: rgb({oColR}, {oColG}, {oColB});"
"}}\n"
".comment {{"
" color: rgb({cColR}, {cColG}, {cColB});"
"}}\n"
".synopsis {{"
" color: rgb({mColR}, {mColG}, {mColB});"
"}}\n"
".title {{"
" text-align: center;"
"}}\n"
"body {{color: rgb({rT}, {gT}, {bT});}}\n"
"h1, h2, h3, h4 {{color: rgb({rH}, {gH}, {bH});}}\n"
"a {{color: rgb({rA}, {gA}, {bA});}}\n"
"mark {{background-color: rgba({rE}, {gE}, {bE}, {aE});}}\n"
".tags {{color: rgb({rK}, {gK}, {bK});}}\n"
".optional {{color: rgb({rO}, {gO}, {bO});}}\n"
".comment {{color: rgb({rC}, {gC}, {bC});}}\n"
".synopsis {{color: rgb({rM}, {gM}, {bM});}}\n"
".title {{text-align: center;}}\n"
).format(
tColR=colText.red(), tColG=colText.green(), tColB=colText.blue(),
hColR=colHead.red(), hColG=colHead.green(), hColB=colHead.blue(),
aColR=colVals.red(), aColG=colVals.green(), aColB=colVals.blue(),
eColR=colEmph.red(), eColG=colEmph.green(), eColB=colEmph.blue(),
kColR=colKeys.red(), kColG=colKeys.green(), kColB=colKeys.blue(),
cColR=colHide.red(), cColG=colHide.green(), cColB=colHide.blue(),
mColR=colMods.red(), mColG=colMods.green(), mColB=colMods.blue(),
oColR=colOpts.red(), oColG=colOpts.green(), oColB=colOpts.blue(),
rT=colText.red(), gT=colText.green(), bT=colText.blue(),
rH=colHead.red(), gH=colHead.green(), bH=colHead.blue(),
rA=colVals.red(), gA=colVals.green(), bA=colVals.blue(),
rE=colMark.red(), gE=colMark.green(), bE=colMark.blue(), aE=colMark.alpha(),
rK=colKeys.red(), gK=colKeys.green(), bK=colKeys.blue(),
rC=colHide.red(), gC=colHide.green(), bC=colHide.blue(),
rM=colMods.red(), gM=colMods.green(), bM=colMods.blue(),
rO=colOpts.red(), gO=colOpts.green(), bO=colOpts.blue(),
)
self.document().setDefaultStyleSheet(styleSheet)
+6
View File
@@ -672,6 +672,12 @@ class GuiMainMenu(QMenuBar):
lambda: self.requestDocAction.emit(nwDocAction.SC_ULINE)
)
# Shortcode Mark
self.aScMark = self.mShortcodes.addAction(self.tr("Highlight"))
self.aScMark.triggered.connect(
lambda: self.requestDocAction.emit(nwDocAction.SC_MARK)
)
# Shortcode Superscript
self.aScSuper = self.mShortcodes.addAction(self.tr("Superscript"))
self.aScSuper.triggered.connect(
+4 -2
View File
@@ -106,6 +106,7 @@ class GuiTheme:
self.colError = QColor(0, 0, 0)
self.colRepTag = QColor(0, 0, 0)
self.colMod = QColor(0, 0, 0)
self.colMark = QColor(255, 255, 255, 128)
# Class Setup
# ===========
@@ -329,6 +330,7 @@ class GuiTheme:
self.colError = self._parseColour(confParser, cnfSec, "errorline")
self.colRepTag = self._parseColour(confParser, cnfSec, "replacetag")
self.colMod = self._parseColour(confParser, cnfSec, "modifier")
self.colMark = self._parseColour(confParser, cnfSec, "texthighlight")
return True
@@ -448,8 +450,8 @@ class GuiIcons:
"search_regex", "search_word",
# Format Icons
"fmt_bold", "fmt_bold-md", "fmt_italic", "fmt_italic-md", "fmt_strike", "fmt_strike-md",
"fmt_subscript", "fmt_superscript", "fmt_underline",
"fmt_bold", "fmt_bold-md", "fmt_italic", "fmt_italic-md", "fmt_mark", "fmt_strike",
"fmt_strike-md", "fmt_subscript", "fmt_superscript", "fmt_underline",
# General Button Icons
"add", "add_document", "backward", "bookmark", "browse", "checked", "close", "cross",
+2
View File
@@ -768,6 +768,8 @@ class _PreviewWidget(QTextBrowser):
html = html.replace("\t", "!!tab!!")
html = html.replace("<del>", "<span style='text-decoration: line-through;'>")
html = html.replace("</del>", "</span>")
html = html.replace("<mark>", "<span style='background-color: #ffffa6;'>")
html = html.replace("</mark>", "</span>")
self.setHtml(html)
qApp.processEvents()
while self.find("!!tab!!"):
+3 -3
View File
@@ -1,8 +1,8 @@
%%~name: Making a Scene
%%~path: 6a2d6d5f4f401/636b6aa9b697b
%%~kind: NOVEL/DOCUMENT
%%~hash: d7920fe95fb48140278ae160fe7c3c1ce530072c
%%~date: Unknown/2023-10-20 22:57:56
%%~hash: e1c58699b05b512306a534da70c2952aafc60e8b
%%~date: Unknown/2024-02-25 16:33:40
### Making a Scene
@pov: Jane
@@ -13,7 +13,7 @@ A scene is defined by a level three heading, like the one at the top of this pag
Each paragraph in the scene is separated by a blank line. The text supports minimal formatting, like **bold**, _italic_ and **_bold italic_**. You can also ~~strike through~~ text. There is **some support for _nested_ emphasis**, but there are some known limitations. If the syntax highlighter doesnt show it correctly, the export tool will not either.
For special formatting aside from standard emphasis, you can use “shortcodes”. Here we have super[sup]script[/sup] and sub[sub]script[/sub], and [b]part[/b]ial bold too, which ends in the middle of a word. The shortcodes also support [u]underline[/u].
For special formatting aside from standard emphasis, you can use “shortcodes”. Here we have super[sup]script[/sup] and sub[sub]script[/sub], and [b]part[/b]ial bold too, which ends in the middle of a word. The shortcodes also support [u]underline[/u], and you can [m]highlight text as well[/m].
In addition, the editor supports automatic formatting of “quotes”, both double and single. Depending on the syntax highlighter settings and colour theme, these can be in different colours. “You can of course use **bold** and _italic_ text inside of quotes too.”
+4 -4
View File
@@ -1,6 +1,6 @@
<?xml version='1.0' encoding='utf-8'?>
<novelWriterXML appVersion="2.3b1" hexVersion="0x020300b1" fileVersion="1.5" fileRevision="2" timeStamp="2024-02-15 22:37:50">
<project id="e2be99af-f9bf-4403-857a-c3d1ac25abea" saveCount="1681" autoCount="263" editTime="82755">
<novelWriterXML appVersion="2.4a0" hexVersion="0x020400a0" fileVersion="1.5" fileRevision="2" timeStamp="2024-02-25 16:33:49">
<project id="e2be99af-f9bf-4403-857a-c3d1ac25abea" saveCount="1690" autoCount="264" editTime="83277">
<name>Sample Project</name>
<author>Jane Smith</author>
</project>
@@ -35,7 +35,7 @@
<entry key="i56be10" count="1" red="117" green="0" blue="175">Main</entry>
</importance>
</settings>
<content items="31" novelWords="991" notesWords="416">
<content items="31" novelWords="998" notesWords="416">
<item handle="7031beac91f75" parent="None" root="7031beac91f75" order="0" type="ROOT" class="NOVEL">
<meta expanded="yes" />
<name status="sc24b8f" import="ia857f0">Novel</name>
@@ -57,7 +57,7 @@
<name status="sf24ce6" import="ia857f0" active="yes">Chapter One</name>
</item>
<item handle="636b6aa9b697b" parent="6a2d6d5f4f401" root="7031beac91f75" order="0" type="FILE" class="NOVEL" layout="DOCUMENT">
<meta expanded="no" heading="H3" charCount="2901" wordCount="513" paraCount="15" cursorPos="66" />
<meta expanded="no" heading="H3" charCount="2937" wordCount="520" paraCount="15" cursorPos="1465" />
<name status="s90e6c9" import="ia857f0" active="yes">Making a Scene</name>
</item>
<item handle="bc0cbd2a407f3" parent="6a2d6d5f4f401" root="7031beac91f75" order="1" type="FILE" class="NOVEL" layout="DOCUMENT">
+36 -14
View File
@@ -29,8 +29,8 @@ from novelwriter.core.project import NWProject
@pytest.mark.core
def testCoreToHtml_ConvertFormat(mockGUI):
"""Test the tokenizer and converter chain using the ToHtml class."""
def testCoreToHtml_ConvertHeaders(mockGUI):
"""Test header formats in the ToHtml class."""
project = NWProject()
html = ToHtml(project)
@@ -129,6 +129,19 @@ def testCoreToHtml_ConvertFormat(mockGUI):
html.doConvert()
assert html.result == "<h2><a name='T0001'></a>Heading Two</h2>\n"
# END Test testCoreToHtml_ConvertHeaders
@pytest.mark.core
def testCoreToHtml_ConvertParagraphs(mockGUI):
"""Test paragraph formats in the ToHtml class."""
project = NWProject()
html = ToHtml(project)
html._isNovel = True
html._isNote = False
html._isFirst = True
# Paragraphs
# ==========
@@ -141,6 +154,19 @@ def testCoreToHtml_ConvertFormat(mockGUI):
"<del>strikethrough</del> text</strong> here</p>\n"
)
# Shortcodes
html._text = (
"Some [b]bold[/b], [i]italic[/i], [s]strike[/s], [u]underline[/u], [m]mark[/m], "
"super[sup]script[/sup], sub[sub]script[/sub] here\n"
)
html.tokenizeText()
html.doConvert()
assert html.result == (
"<p>Some <strong>bold</strong>, <em>italic</em>, <del>strike</del>, "
"<span style='text-decoration: underline;'>underline</span>, <mark>mark</mark>, "
"super<sup>script</sup>, sub<sub>script</sub> here</p>\n"
)
# Text w/Hard Break
html._text = "Line one \nLine two \nLine three\n"
html.tokenizeText()
@@ -206,17 +232,13 @@ def testCoreToHtml_ConvertFormat(mockGUI):
html.tokenizeText()
html.doConvert()
assert html.result == (
"<h2>"
"<a name='T0001'></a>Chapter</h2>\n"
"<p style='margin-bottom: 0;'>"
"<span class='tags'>Point of View:</span> <a href='#tag_Bod'>Bod</a>"
"</p>\n"
"<p style='margin-bottom: 0; margin-top: 0;'>"
"<span class='tags'>Plot:</span> <a href='#tag_Main'>Main</a>"
"</p>\n"
"<p style='margin-top: 0;'>"
"<span class='tags'>Locations:</span> <a href='#tag_Europe'>Europe</a>"
"</p>\n"
"<h1 style='page-break-before: always;'>Chapter</h1>\n"
"<p style='margin-bottom: 0;'><span class='tags'>Point of View:</span> "
"<a href='#tag_Bod'>Bod</a></p>\n"
"<p style='margin-bottom: 0; margin-top: 0;'><span class='tags'>Plot:</span> "
"<a href='#tag_Main'>Main</a></p>\n"
"<p style='margin-top: 0;'><span class='tags'>Locations:</span> "
"<a href='#tag_Europe'>Europe</a></p>\n"
)
# Preview Mode
@@ -234,7 +256,7 @@ def testCoreToHtml_ConvertFormat(mockGUI):
"text</b> here</p>\n"
)
# END Test testCoreToHtml_ConvertFormat
# END Test testCoreToHtml_ConvertParagraphs
@pytest.mark.core
+5
View File
@@ -638,6 +638,11 @@ def testCoreToken_ExtractFormats(mockGUI):
assert text == "Text with underline in it."
assert fmt == [(10, tokens.FMT_U_B), (19, tokens.FMT_U_E)]
# Plain mark
text, fmt = tokens._extractFormats("Text with [m]highlight[/m] in it.")
assert text == "Text with highlight in it."
assert fmt == [(10, tokens.FMT_M_B), (19, tokens.FMT_M_E)]
# Plain superscript
text, fmt = tokens._extractFormats("Text with super[sup]script[/sup] in it.")
assert text == "Text with superscript in it."
+40 -10
View File
@@ -29,16 +29,11 @@ from novelwriter.core.project import NWProject
@pytest.mark.core
def testCoreToMarkdown_ConvertFormat(mockGUI):
"""Test the tokenizer and converter chain using the ToMarkdown
class.
"""
def testCoreToMarkdown_ConvertHeaders(mockGUI):
"""Test header formats in the ToMarkdown class."""
project = NWProject()
toMD = ToMarkdown(project)
# Headers
# =======
toMD._isNovel = True
toMD._isNote = False
toMD._isFirst = True
@@ -79,8 +74,18 @@ def testCoreToMarkdown_ConvertFormat(mockGUI):
toMD.doConvert()
assert toMD.result == "## Prologue\n\n"
# Paragraphs
# ==========
# END Test testCoreToMarkdown_ConvertHeaders
@pytest.mark.core
def testCoreToMarkdown_ConvertParagraphs(mockGUI):
"""Test paragraph formats in the ToMarkdown class."""
project = NWProject()
toMD = ToMarkdown(project)
toMD._isNovel = True
toMD._isNote = False
toMD._isFirst = True
# Text for Extended Markdown
toMD.setExtendedMarkdown()
@@ -100,6 +105,31 @@ def testCoreToMarkdown_ConvertFormat(mockGUI):
"Some **nested bold and _italic_ and strikethrough text** here\n\n"
)
# Shortcodes for Extended Markdown
toMD.setExtendedMarkdown()
toMD._text = (
"Some [b]bold[/b], [i]italic[/i], [s]strike[/s], [u]underline[/u], [m]mark[/m], "
"super[sup]script[/sup], sub[sub]script[/sub] here\n"
)
toMD.tokenizeText()
toMD.doConvert()
assert toMD.result == (
"Some **bold**, _italic_, ~~strike~~, underline, ==mark==, "
"super^script^, sub~script~ here\n\n"
)
# Shortcodes for Standard Markdown
toMD.setStandardMarkdown()
toMD._text = (
"Some [b]bold[/b], [i]italic[/i], [s]strike[/s], [u]underline[/u], [m]mark[/m], "
"super[sup]script[/sup], sub[sub]script[/sub] here\n"
)
toMD.tokenizeText()
toMD.doConvert()
assert toMD.result == (
"Some **bold**, _italic_, strike, underline, mark, superscript, subscript here\n\n"
)
# Text w/Hard Break
toMD._text = "Line one \nLine two \nLine three\n"
toMD.tokenizeText()
@@ -160,7 +190,7 @@ def testCoreToMarkdown_ConvertFormat(mockGUI):
"**Locations:** Europe\n\n"
)
# END Test testCoreToMarkdown_ConvertFormat
# END Test testCoreToMarkdown_ConvertParagraphs
@pytest.mark.core
+69 -40
View File
@@ -237,22 +237,12 @@ def testCoreToOdt_TextFormatting(mockGUI):
@pytest.mark.core
def testCoreToOdt_Convert(mockGUI):
def testCoreToOdt_ConvertHeaders(mockGUI):
"""Test the converter of the ToOdt class."""
project = NWProject()
odt = ToOdt(project, isFlat=True)
odt._isNovel = True
def getStyle(styleName):
for aSet in odt._autoPara.values():
if aSet[0] == styleName:
return aSet[1]
return None
# Headers
# =======
# Header 1
odt._text = "# Title\n"
odt.tokenizeText()
@@ -331,8 +321,21 @@ def testCoreToOdt_Convert(mockGUI):
'</office:text>'
)
# Paragraphs
# ==========
# END Test testCoreToOdt_ConvertHeaders
@pytest.mark.core
def testCoreToOdt_ConvertParagraphs(mockGUI):
"""Test the converter of the ToOdt class."""
project = NWProject()
odt = ToOdt(project, isFlat=True)
odt._isNovel = True
def getStyle(styleName):
for aSet in odt._autoPara.values():
if aSet[0] == styleName:
return aSet[1]
return None
# Nested Markdown Text
odt._text = "Some ~~nested **bold** and _italics_ text~~ text."
@@ -372,7 +375,7 @@ def testCoreToOdt_Convert(mockGUI):
'</office:text>'
)
# Nested Shortcode Text, Super/Subscript
# Shortcode Text, Super/Subscript
odt._text = "Some super[sup]script[/sup] and sub[sub]script[/sub] text."
odt.tokenizeText()
odt.initDocument()
@@ -387,6 +390,21 @@ def testCoreToOdt_Convert(mockGUI):
'</office:text>'
)
# Shortcode Text, Underline/Highlight
odt._text = "Some [u]underlined and [m]highlighted[/m][/u] text."
odt.tokenizeText()
odt.initDocument()
odt.doConvert()
odt.closeDocument()
assert odt.errData == []
assert xmlToText(odt._xText) == (
'<office:text>'
'<text:p text:style-name="Text_20_body">Some '
'<text:span text:style-name="T7">underlined and </text:span>'
'<text:span text:style-name="T8">highlighted</text:span> text.</text:p>'
'</office:text>'
)
# Hard Break
odt._text = "Some text.\nNext line\n"
odt.tokenizeText()
@@ -422,7 +440,7 @@ def testCoreToOdt_Convert(mockGUI):
assert odt.errData == []
assert xmlToText(odt._xText) == (
'<office:text>'
'<text:p text:style-name="Text_20_body">Some <text:span text:style-name="T7">'
'<text:p text:style-name="Text_20_body">Some <text:span text:style-name="T9">'
'bold<text:tab />text</text:span></text:p>'
'</office:text>'
)
@@ -467,13 +485,13 @@ def testCoreToOdt_Convert(mockGUI):
assert xmlToText(odt._xText) == (
'<office:text>'
'<text:h text:style-name="Heading_20_3" text:outline-level="3">Scene</text:h>'
'<text:p text:style-name="Text_20_Meta"><text:span text:style-name="T7">'
'<text:p text:style-name="Text_20_Meta"><text:span text:style-name="T9">'
'Point of View:</text:span> Jane</text:p>'
'<text:p text:style-name="Text_20_Meta"><text:span text:style-name="T7">'
'<text:p text:style-name="Text_20_Meta"><text:span text:style-name="T9">'
'Synopsis:</text:span> So it begins</text:p>'
'<text:p text:style-name="Text_20_Meta"><text:span text:style-name="T7">'
'<text:p text:style-name="Text_20_Meta"><text:span text:style-name="T9">'
'Short Description:</text:span> Then what</text:p>'
'<text:p text:style-name="Text_20_Meta"><text:span text:style-name="T7">'
'<text:p text:style-name="Text_20_Meta"><text:span text:style-name="T9">'
'Comment:</text:span> A plain comment</text:p>'
'</office:text>'
)
@@ -535,26 +553,26 @@ def testCoreToOdt_Convert(mockGUI):
assert xmlToText(odt._xText) == (
'<office:text>'
'<text:h text:style-name="Heading_20_3" text:outline-level="3">Scene</text:h>'
'<text:p text:style-name="P3"><text:span text:style-name="T7">'
'<text:p text:style-name="P1"><text:span text:style-name="T9">'
'Point of View:</text:span> Jane</text:p>'
'<text:p text:style-name="P4"><text:span text:style-name="T7">'
'<text:p text:style-name="P2"><text:span text:style-name="T9">'
'Characters:</text:span> John</text:p>'
'<text:p text:style-name="Text_20_Meta"><text:span text:style-name="T7">'
'<text:p text:style-name="Text_20_Meta"><text:span text:style-name="T9">'
'Plot:</text:span> Main</text:p>'
'<text:p text:style-name="P5">Right align</text:p>'
'<text:p text:style-name="P3">Right align</text:p>'
'<text:p text:style-name="Text_20_body">Left Align</text:p>'
'<text:p text:style-name="P6">Centered</text:p>'
'<text:p text:style-name="P7">Left indent</text:p>'
'<text:p text:style-name="P8">Right indent</text:p>'
'<text:p text:style-name="P4">Centered</text:p>'
'<text:p text:style-name="P5">Left indent</text:p>'
'<text:p text:style-name="P6">Right indent</text:p>'
'</office:text>'
)
assert getStyle("P3")._pAttr["margin-bottom"] == ["fo", "0.000cm"] # type: ignore
assert getStyle("P4")._pAttr["margin-bottom"] == ["fo", "0.000cm"] # type: ignore
assert getStyle("P4")._pAttr["margin-top"] == ["fo", "0.000cm"] # type: ignore
assert getStyle("P5")._pAttr["text-align"] == ["fo", "right"] # type: ignore
assert getStyle("P6")._pAttr["text-align"] == ["fo", "center"] # type: ignore
assert getStyle("P7")._pAttr["margin-left"] == ["fo", "1.693cm"] # type: ignore
assert getStyle("P8")._pAttr["margin-right"] == ["fo", "1.693cm"] # type: ignore
assert getStyle("P1")._pAttr["margin-bottom"] == ["fo", "0.000cm"] # type: ignore
assert getStyle("P2")._pAttr["margin-bottom"] == ["fo", "0.000cm"] # type: ignore
assert getStyle("P2")._pAttr["margin-top"] == ["fo", "0.000cm"] # type: ignore
assert getStyle("P3")._pAttr["text-align"] == ["fo", "right"] # type: ignore
assert getStyle("P4")._pAttr["text-align"] == ["fo", "center"] # type: ignore
assert getStyle("P5")._pAttr["margin-left"] == ["fo", "1.693cm"] # type: ignore
assert getStyle("P6")._pAttr["margin-right"] == ["fo", "1.693cm"] # type: ignore
# Justified
odt._text = (
@@ -573,11 +591,11 @@ def testCoreToOdt_Convert(mockGUI):
'<office:text>'
'<text:h text:style-name="Heading_20_3" text:outline-level="3">Scene</text:h>'
'<text:p text:style-name="Text_20_body">Regular paragraph</text:p>'
'<text:p text:style-name="P9">with<text:line-break />break</text:p>'
'<text:p text:style-name="P9">Left Align</text:p>'
'<text:p text:style-name="P7">with<text:line-break />break</text:p>'
'<text:p text:style-name="P7">Left Align</text:p>'
'</office:text>'
)
assert getStyle("P9")._pAttr["text-align"] == ["fo", "left"] # type: ignore
assert getStyle("P7")._pAttr["text-align"] == ["fo", "left"] # type: ignore
# Page Breaks
odt._text = (
@@ -593,9 +611,9 @@ def testCoreToOdt_Convert(mockGUI):
assert odt.errData == []
assert xmlToText(odt._xText) == (
'<office:text>'
'<text:h text:style-name="P2" text:outline-level="2">Chapter One</text:h>'
'<text:h text:style-name="P8" text:outline-level="2">Chapter One</text:h>'
'<text:p text:style-name="Text_20_body">Text</text:p>'
'<text:h text:style-name="P2" text:outline-level="2">Chapter Two</text:h>'
'<text:h text:style-name="P8" text:outline-level="2">Chapter Two</text:h>'
'<text:p text:style-name="Text_20_body">Text</text:p>'
'</office:text>'
)
@@ -612,12 +630,12 @@ def testCoreToOdt_Convert(mockGUI):
assert odt.errData == []
assert xmlToText(odt._xText) == (
'<office:text>'
'<text:p text:style-name="Text_20_body">Test text **<text:span text:style-name="T8">'
'<text:p text:style-name="Text_20_body">Test text **<text:span text:style-name="T10">'
'bold</text:span>** and more.</text:p>'
'</office:text>'
)
# END Test testCoreToOdt_Convert
# END Test testCoreToOdt_ConvertParagraphs
@pytest.mark.core
@@ -1081,6 +1099,17 @@ def testCoreToOdt_ODTTextStyle():
txtStyle.setFontStyle("stuff")
assert txtStyle._tAttr["font-style"] == ["fo", None]
# Background Color
assert txtStyle._tAttr["background-color"] == ["fo", None]
txtStyle.setBackgroundColor("stuff")
assert txtStyle._tAttr["background-color"] == ["fo", None]
txtStyle.setBackgroundColor("012345")
assert txtStyle._tAttr["background-color"] == ["fo", None]
txtStyle.setBackgroundColor("#012345")
assert txtStyle._tAttr["background-color"] == ["fo", "#012345"]
txtStyle.setBackgroundColor("stuff")
assert txtStyle._tAttr["background-color"] == ["fo", None]
# Text Position
assert txtStyle._tAttr["text-position"] == ["style", None]
txtStyle.setTextPosition("stuff")
+7
View File
@@ -491,6 +491,13 @@ def testGuiEditor_Actions(qtbot, nwGUI, projPath, ipsumText, mockRnd):
assert nwGUI.docEditor.docAction(nwDocAction.UNDO) is True
assert nwGUI.docEditor.getText() == text
# Mark
nwGUI.docEditor.setCursorPosition(46)
assert nwGUI.docEditor.docAction(nwDocAction.SC_MARK) is True
assert nwGUI.docEditor.getText() == text.replace("consectetur", "[m]consectetur[/m]")
assert nwGUI.docEditor.docAction(nwDocAction.UNDO) is True
assert nwGUI.docEditor.getText() == text
# Superscript
nwGUI.docEditor.setCursorPosition(46)
assert nwGUI.docEditor.docAction(nwDocAction.SC_SUP) is True