From e1af21bf8883108dafa69590f79c5c765b900f95 Mon Sep 17 00:00:00 2001 From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com> Date: Mon, 13 May 2024 17:50:18 +0200 Subject: [PATCH 1/6] Add new dialogue highlighting settings --- novelwriter/config.py | 21 +++++++++------- novelwriter/gui/dochighlight.py | 44 ++++++++++++++++++--------------- novelwriter/gui/theme.py | 8 ++---- 3 files changed, 38 insertions(+), 35 deletions(-) diff --git a/novelwriter/config.py b/novelwriter/config.py index 1627cade..91945fe3 100644 --- a/novelwriter/config.py +++ b/novelwriter/config.py @@ -158,9 +158,10 @@ class Config: self.autoScrollPos = 30 # Start point for typewriter-like scrolling self.scrollPastEnd = True # Scroll past end of document, and centre cursor - self.highlightQuotes = True # Highlight text in quotes - self.allowOpenSQuote = False # Allow open-ended single quotes - self.allowOpenDQuote = True # Allow open-ended double quotes + self.dialogueStyle = 2 # Quote type to use for dialogue + self.allowOpenDial = True # Allow open-ended dialogue quotes + self.narratorBreak = "" # Symbol to use for narrator break + self.dialogueLine = "" # Symbol to use for dialogue line self.highlightEmph = True # Add colour to text emphasis self.stopWhenIdle = True # Stop the status bar clock when the user is idle @@ -618,9 +619,10 @@ class Config: self.showMultiSpaces = conf.rdBool(sec, "showmultispaces", self.showMultiSpaces) self.incNotesWCount = conf.rdBool(sec, "incnoteswcount", self.incNotesWCount) self.showFullPath = conf.rdBool(sec, "showfullpath", self.showFullPath) - self.highlightQuotes = conf.rdBool(sec, "highlightquotes", self.highlightQuotes) - self.allowOpenSQuote = conf.rdBool(sec, "allowopensquote", self.allowOpenSQuote) - self.allowOpenDQuote = conf.rdBool(sec, "allowopendquote", self.allowOpenDQuote) + self.dialogueStyle = conf.rdInt(sec, "dialoguestyle", self.dialogueStyle) + self.allowOpenDial = conf.rdBool(sec, "allowopendial", self.allowOpenDial) + self.narratorBreak = conf.rdStr(sec, "narratorbreak", self.narratorBreak) + self.dialogueLine = conf.rdStr(sec, "dialogueline", self.dialogueLine) self.highlightEmph = conf.rdBool(sec, "highlightemph", self.highlightEmph) self.stopWhenIdle = conf.rdBool(sec, "stopwhenidle", self.stopWhenIdle) self.userIdleTime = conf.rdInt(sec, "useridletime", self.userIdleTime) @@ -726,9 +728,10 @@ class Config: "showmultispaces": str(self.showMultiSpaces), "incnoteswcount": str(self.incNotesWCount), "showfullpath": str(self.showFullPath), - "highlightquotes": str(self.highlightQuotes), - "allowopensquote": str(self.allowOpenSQuote), - "allowopendquote": str(self.allowOpenDQuote), + "dialoguestyle": str(self.dialogueStyle), + "allowopendial": str(self.allowOpenDial), + "narratorbreak": str(self.narratorBreak), + "dialogueline": str(self.dialogueLine), "highlightemph": str(self.highlightEmph), "stopwhenidle": str(self.stopWhenIdle), "useridletime": str(self.userIdleTime), diff --git a/novelwriter/gui/dochighlight.py b/novelwriter/gui/dochighlight.py index 29fe9504..9ecd0270 100644 --- a/novelwriter/gui/dochighlight.py +++ b/novelwriter/gui/dochighlight.py @@ -94,6 +94,7 @@ class GuiDocHighlighter(QSyntaxHighlighter): colBreak.setAlpha(64) # Create Character Formats + self._addCharFormat("text", SHARED.theme.colText) self._addCharFormat("header1", SHARED.theme.colHead, "b", 1.8) self._addCharFormat("header2", SHARED.theme.colHead, "b", 1.6) self._addCharFormat("header3", SHARED.theme.colHead, "b", 1.4) @@ -107,9 +108,7 @@ class GuiDocHighlighter(QSyntaxHighlighter): self._addCharFormat("strike", SHARED.theme.colHidden, "s") self._addCharFormat("mspaces", SHARED.theme.colError, "err") self._addCharFormat("nobreak", colBreak, "bg") - self._addCharFormat("dialog1", SHARED.theme.colDialN) - self._addCharFormat("dialog2", SHARED.theme.colDialD) - self._addCharFormat("dialog3", SHARED.theme.colDialS) + self._addCharFormat("dialog", SHARED.theme.colDialog) self._addCharFormat("replace", SHARED.theme.colRepTag) self._addCharFormat("hidden", SHARED.theme.colHidden) self._addCharFormat("markup", SHARED.theme.colHidden) @@ -127,6 +126,9 @@ class GuiDocHighlighter(QSyntaxHighlighter): self._spellErr.setUnderlineColor(SHARED.theme.colSpell) self._spellErr.setUnderlineStyle(QTextCharFormat.UnderlineStyle.SpellCheckUnderline) + self._txtRules.clear() + self._cmnRules.clear() + # Multiple or Trailing Spaces if CONFIG.showMultiSpaces: rxRule = QRegularExpression(r"[ ]{2,}|[ ]*$") @@ -146,36 +148,38 @@ class GuiDocHighlighter(QSyntaxHighlighter): self._txtRules.append((rxRule, hlRule)) self._cmnRules.append((rxRule, hlRule)) - # Quoted Strings - if CONFIG.highlightQuotes: - fmtDblO = CONFIG.fmtDQuoteOpen - fmtDblC = CONFIG.fmtDQuoteClose - fmtSngO = CONFIG.fmtSQuoteOpen - fmtSngC = CONFIG.fmtSQuoteClose + # Dialogue + if CONFIG.dialogueStyle > 0: + symO = "" + symC = "" + if CONFIG.dialogueStyle in (1, 3): + symO += CONFIG.fmtSQuoteOpen + symC += CONFIG.fmtSQuoteClose + if CONFIG.dialogueStyle in (2, 3): + symO += CONFIG.fmtDQuoteOpen + symC += CONFIG.fmtDQuoteClose - # Straight Quotes - rxRule = QRegularExpression(r'(\B")(.*?)("\B)') + rxEnd = "|$" if CONFIG.allowOpenDial else "" + rxRule = QRegularExpression(f"(\\B[{symO}])(.*?)([{symC}]\\B{rxEnd})") rxRule.setPatternOptions(QRegExUnicode) hlRule = { - 0: self._hStyles["dialog1"], + 0: self._hStyles["dialog"], } self._txtRules.append((rxRule, hlRule)) - # Double Quotes - dblEnd = "|$" if CONFIG.allowOpenDQuote else "" - rxRule = QRegularExpression(f"(\\B{fmtDblO})(.*?)({fmtDblC}\\B{dblEnd})") + if sym := CONFIG.dialogueLine: + rxRule = QRegularExpression(f"^{sym}.*?$") rxRule.setPatternOptions(QRegExUnicode) hlRule = { - 0: self._hStyles["dialog2"], + 0: self._hStyles["dialog"], } self._txtRules.append((rxRule, hlRule)) - # Single Quotes - sngEnd = "|$" if CONFIG.allowOpenSQuote else "" - rxRule = QRegularExpression(f"(\\B{fmtSngO})(.*?)({fmtSngC}\\B{sngEnd})") + if sym := CONFIG.narratorBreak: + rxRule = QRegularExpression(f"({sym}\\b)(.*?)(\\b{sym})") rxRule.setPatternOptions(QRegExUnicode) hlRule = { - 0: self._hStyles["dialog3"], + 0: self._hStyles["text"], } self._txtRules.append((rxRule, hlRule)) diff --git a/novelwriter/gui/theme.py b/novelwriter/gui/theme.py index 5ecc4444..ebcf5e04 100644 --- a/novelwriter/gui/theme.py +++ b/novelwriter/gui/theme.py @@ -95,9 +95,7 @@ class GuiTheme: self.colHead = QColor(0, 0, 0) self.colHeadH = QColor(0, 0, 0) self.colEmph = QColor(0, 0, 0) - self.colDialN = QColor(0, 0, 0) - self.colDialD = QColor(0, 0, 0) - self.colDialS = QColor(0, 0, 0) + self.colDialog = QColor(0, 0, 0) self.colHidden = QColor(0, 0, 0) self.colNote = QColor(0, 0, 0) self.colCode = QColor(0, 0, 0) @@ -338,9 +336,7 @@ class GuiTheme: self.colHead = self._parseColour(confParser, cnfSec, "headertext") self.colHeadH = self._parseColour(confParser, cnfSec, "headertag") self.colEmph = self._parseColour(confParser, cnfSec, "emphasis") - self.colDialN = self._parseColour(confParser, cnfSec, "straightquotes") - self.colDialD = self._parseColour(confParser, cnfSec, "doublequotes") - self.colDialS = self._parseColour(confParser, cnfSec, "singlequotes") + self.colDialog = self._parseColour(confParser, cnfSec, "dialog") self.colHidden = self._parseColour(confParser, cnfSec, "hidden") self.colNote = self._parseColour(confParser, cnfSec, "note") self.colCode = self._parseColour(confParser, cnfSec, "shortcode") From e5e3066b3dddd9067e64d8c0716e5a0220deb6e7 Mon Sep 17 00:00:00 2001 From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com> Date: Mon, 13 May 2024 17:51:16 +0200 Subject: [PATCH 2/6] Update preferences --- novelwriter/dialogs/preferences.py | 76 ++++++++++++++++++------------ novelwriter/extensions/modified.py | 2 +- novelwriter/gui/dochighlight.py | 2 +- 3 files changed, 48 insertions(+), 32 deletions(-) diff --git a/novelwriter/dialogs/preferences.py b/novelwriter/dialogs/preferences.py index 671d4d4e..6f90a26d 100644 --- a/novelwriter/dialogs/preferences.py +++ b/novelwriter/dialogs/preferences.py @@ -133,6 +133,7 @@ class GuiPreferences(QDialog): """Build the settings form.""" section = 0 iSz = SHARED.theme.baseIconSize + boxFixed = 5*SHARED.theme.textNWidth minWidth = CONFIG.pxInt(200) # Label @@ -538,26 +539,42 @@ class GuiPreferences(QDialog): self.sidebar.addButton(title, section) self.mainForm.addGroupLabel(title, section) - self.highlightQuotes = NSwitch(self) - self.highlightQuotes.setChecked(CONFIG.highlightQuotes) - self.highlightQuotes.toggled.connect(self._toggleHighlightQuotes) + self.dialogueStyle = NComboBox(self) + self.dialogueStyle.addItem(self.tr("None"), 0) + self.dialogueStyle.addItem(self.tr("Single Quotes"), 1) + self.dialogueStyle.addItem(self.tr("Double Quotes"), 2) + self.dialogueStyle.addItem(self.tr("Both"), 3) + self.dialogueStyle.setCurrentData(CONFIG.dialogueStyle, 2) self.mainForm.addRow( - self.tr("Highlight text wrapped in quotes"), self.highlightQuotes, - self.tr("Applies to the document editor only.") + self.tr("Highlight dialogue"), self.dialogueStyle, + self.tr("Applies to the selected quote styles.") ) - self.allowOpenSQuote = NSwitch(self) - self.allowOpenSQuote.setChecked(CONFIG.allowOpenSQuote) + self.allowOpenDial = NSwitch(self) + self.allowOpenDial.setChecked(CONFIG.allowOpenDial) self.mainForm.addRow( - self.tr("Allow open-ended single quotes"), self.allowOpenSQuote, - self.tr("Highlight single-quoted line with no closing quote.") + self.tr("Allow open-ended sialogue"), self.allowOpenDial, + self.tr("Highlight dialogue line with no closing quote.") ) - self.allowOpenDQuote = NSwitch(self) - self.allowOpenDQuote.setChecked(CONFIG.allowOpenDQuote) + self.narratorBreak = QLineEdit(self) + self.narratorBreak.setMaxLength(1) + self.narratorBreak.setFixedWidth(boxFixed) + self.narratorBreak.setAlignment(QtAlignCenter) + self.narratorBreak.setText(CONFIG.narratorBreak) self.mainForm.addRow( - self.tr("Allow open-ended double quotes"), self.allowOpenDQuote, - self.tr("Highlight double-quoted line with no closing quote.") + self.tr("Dialogue narrator break symbol"), self.narratorBreak, + self.tr("Symbol to indicate injected narrator break.") + ) + + self.dialogueLine = QLineEdit(self) + self.dialogueLine.setMaxLength(1) + self.dialogueLine.setFixedWidth(boxFixed) + self.dialogueLine.setAlignment(QtAlignCenter) + self.dialogueLine.setText(CONFIG.dialogueLine) + self.mainForm.addRow( + self.tr("Dialogue line symbol"), self.dialogueLine, + self.tr("Lines starting with this symbol are dialogue.") ) self.highlightEmph = NSwitch(self) @@ -667,13 +684,12 @@ class GuiPreferences(QDialog): self.mainForm.addGroupLabel(title, section) self.quoteSym = {} - qWidth = CONFIG.pxInt(40) # Single Quote Style self.quoteSym["SO"] = QLineEdit(self) self.quoteSym["SO"].setMaxLength(1) self.quoteSym["SO"].setReadOnly(True) - self.quoteSym["SO"].setFixedWidth(qWidth) + self.quoteSym["SO"].setFixedWidth(boxFixed) self.quoteSym["SO"].setAlignment(QtAlignCenter) self.quoteSym["SO"].setText(CONFIG.fmtSQuoteOpen) self.btnSingleStyleO = NIconToolButton(self, iSz, "more") @@ -687,7 +703,7 @@ class GuiPreferences(QDialog): self.quoteSym["SC"] = QLineEdit(self) self.quoteSym["SC"].setMaxLength(1) self.quoteSym["SC"].setReadOnly(True) - self.quoteSym["SC"].setFixedWidth(qWidth) + self.quoteSym["SC"].setFixedWidth(boxFixed) self.quoteSym["SC"].setAlignment(QtAlignCenter) self.quoteSym["SC"].setText(CONFIG.fmtSQuoteClose) self.btnSingleStyleC = NIconToolButton(self, iSz, "more") @@ -702,7 +718,7 @@ class GuiPreferences(QDialog): self.quoteSym["DO"] = QLineEdit(self) self.quoteSym["DO"].setMaxLength(1) self.quoteSym["DO"].setReadOnly(True) - self.quoteSym["DO"].setFixedWidth(qWidth) + self.quoteSym["DO"].setFixedWidth(boxFixed) self.quoteSym["DO"].setAlignment(QtAlignCenter) self.quoteSym["DO"].setText(CONFIG.fmtDQuoteOpen) self.btnDoubleStyleO = NIconToolButton(self, iSz, "more") @@ -716,7 +732,7 @@ class GuiPreferences(QDialog): self.quoteSym["DC"] = QLineEdit(self) self.quoteSym["DC"].setMaxLength(1) self.quoteSym["DC"].setReadOnly(True) - self.quoteSym["DC"].setFixedWidth(qWidth) + self.quoteSym["DC"].setFixedWidth(boxFixed) self.quoteSym["DC"].setAlignment(QtAlignCenter) self.quoteSym["DC"].setText(CONFIG.fmtDQuoteClose) self.btnDoubleStyleC = NIconToolButton(self, iSz, "more") @@ -823,13 +839,6 @@ class GuiPreferences(QDialog): self.askBeforeBackup.setEnabled(state) return - @pyqtSlot(bool) - def _toggleHighlightQuotes(self, state: bool) -> None: - """Toggle switches controlled by the highlight quotes switch.""" - self.allowOpenSQuote.setEnabled(state) - self.allowOpenDQuote.setEnabled(state) - return - @pyqtSlot(bool) def _toggleAutoReplaceMain(self, state: bool) -> None: """Toggle switches controlled by the auto replace switch.""" @@ -927,19 +936,26 @@ class GuiPreferences(QDialog): CONFIG.scrollPastEnd = self.scrollPastEnd.isChecked() # Text Highlighting - highlightQuotes = self.highlightQuotes.isChecked() + dialogueStyle = self.dialogueStyle.currentData() + allowOpenDial = self.allowOpenDial.isChecked() + narratorBreak = self.narratorBreak.text() + dialogueLine = self.dialogueLine.text() highlightEmph = self.highlightEmph.isChecked() showMultiSpaces = self.showMultiSpaces.isChecked() - updateSyntax |= CONFIG.highlightQuotes != highlightQuotes + updateSyntax |= CONFIG.dialogueStyle != dialogueStyle + updateSyntax |= CONFIG.allowOpenDial != allowOpenDial + updateSyntax |= CONFIG.narratorBreak != narratorBreak + updateSyntax |= CONFIG.dialogueLine != dialogueLine updateSyntax |= CONFIG.highlightEmph != highlightEmph updateSyntax |= CONFIG.showMultiSpaces != showMultiSpaces - CONFIG.highlightQuotes = highlightQuotes + CONFIG.dialogueStyle = dialogueStyle + CONFIG.allowOpenDial = allowOpenDial + CONFIG.narratorBreak = narratorBreak + CONFIG.dialogueLine = dialogueLine CONFIG.highlightEmph = highlightEmph CONFIG.showMultiSpaces = showMultiSpaces - CONFIG.allowOpenSQuote = self.allowOpenSQuote.isChecked() - CONFIG.allowOpenDQuote = self.allowOpenDQuote.isChecked() # Text Automation CONFIG.doReplace = self.doReplace.isChecked() diff --git a/novelwriter/extensions/modified.py b/novelwriter/extensions/modified.py index 4eed6635..210d9638 100644 --- a/novelwriter/extensions/modified.py +++ b/novelwriter/extensions/modified.py @@ -93,7 +93,7 @@ class NComboBox(QComboBox): event.ignore() return - def setCurrentData(self, data: str | Enum, default: str | Enum) -> None: + def setCurrentData(self, data: str | int | Enum, default: str | int | Enum) -> None: """Set the current index from data, with a fallback.""" idx = self.findData(data) self.setCurrentIndex(self.findData(default) if idx < 0 else idx) diff --git a/novelwriter/gui/dochighlight.py b/novelwriter/gui/dochighlight.py index 9ecd0270..361b7139 100644 --- a/novelwriter/gui/dochighlight.py +++ b/novelwriter/gui/dochighlight.py @@ -160,7 +160,7 @@ class GuiDocHighlighter(QSyntaxHighlighter): symC += CONFIG.fmtDQuoteClose rxEnd = "|$" if CONFIG.allowOpenDial else "" - rxRule = QRegularExpression(f"(\\B[{symO}])(.*?)([{symC}]\\B{rxEnd})") + rxRule = QRegularExpression(f"\\B[{symO}].*?[{symC}]\\B{rxEnd}") rxRule.setPatternOptions(QRegExUnicode) hlRule = { 0: self._hStyles["dialog"], From 7e35b4c675cd322faf726351122a274b664b14cd Mon Sep 17 00:00:00 2001 From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com> Date: Mon, 13 May 2024 17:57:19 +0200 Subject: [PATCH 3/6] Update syntax themes and add alternative dialog colour --- docs/source/more_customise.rst | 8 +-- .../assets/syntax/cyberpunk_night.conf | 5 +- novelwriter/assets/syntax/default_dark.conf | 5 +- novelwriter/assets/syntax/default_light.conf | 5 +- novelwriter/assets/syntax/dracula.conf | 5 +- novelwriter/assets/syntax/grey_dark.conf | 5 +- novelwriter/assets/syntax/grey_light.conf | 5 +- novelwriter/assets/syntax/light_owl.conf | 5 +- novelwriter/assets/syntax/night_owl.conf | 5 +- novelwriter/assets/syntax/snazzy.conf | 5 +- novelwriter/assets/syntax/solarized_dark.conf | 5 +- .../assets/syntax/solarized_light.conf | 5 +- novelwriter/assets/syntax/tango.conf | 5 +- novelwriter/assets/syntax/tomorrow.conf | 5 +- novelwriter/assets/syntax/tomorrow_night.conf | 5 +- .../assets/syntax/tomorrow_night_blue.conf | 5 +- .../assets/syntax/tomorrow_night_bright.conf | 5 +- .../syntax/tomorrow_night_eighties.conf | 5 +- novelwriter/gui/dochighlight.py | 53 ++++++++++--------- novelwriter/gui/theme.py | 6 ++- 20 files changed, 69 insertions(+), 83 deletions(-) diff --git a/docs/source/more_customise.rst b/docs/source/more_customise.rst index 3bc690e1..acbfdb2a 100644 --- a/docs/source/more_customise.rst +++ b/docs/source/more_customise.rst @@ -168,9 +168,8 @@ A syntax theme ``.conf`` file consists of the following settings: headertext = 0, 0, 0 headertag = 0, 0, 0 emphasis = 0, 0, 0 - straightquotes = 0, 0, 0 - doublequotes = 0, 0, 0 - singlequotes = 0, 0, 0 + dialog = 0, 0, 0 + altdialog = 0, 0, 0 note = 0, 0, 0 hidden = 0, 0, 0 shortcode = 0, 0, 0 @@ -201,4 +200,5 @@ Omitted syntax colours default to black, except ``background`` which defaults to The ``texthighlight`` syntax colour entry was added. .. versionadded:: 2.5 - The ``note`` and ``tag`` syntax colour entries were added. + The ``dialog``, ``altdialog``, ``note`` and ``tag`` syntax colour entries were added. + ``straightquotes``, ``doublequotes`` and ``singlequotes`` were removed. diff --git a/novelwriter/assets/syntax/cyberpunk_night.conf b/novelwriter/assets/syntax/cyberpunk_night.conf index 26685da7..4a838580 100644 --- a/novelwriter/assets/syntax/cyberpunk_night.conf +++ b/novelwriter/assets/syntax/cyberpunk_night.conf @@ -12,9 +12,8 @@ link = 77, 077, 255 headertext = 255, 255, 255 headertag = 50, 0, 180 emphasis = 0, 255, 255 -straightquotes = 7, 27, 219 -doublequotes = 0, 255, 0 -singlequotes = 0, 140, 255 +dialog = 0, 255, 0 +altdialog = 0, 140, 255 note = 150, 150, 150 hidden = 77, 77, 100 shortcode = 255, 255, 0 diff --git a/novelwriter/assets/syntax/default_dark.conf b/novelwriter/assets/syntax/default_dark.conf index 98a290db..8e467189 100644 --- a/novelwriter/assets/syntax/default_dark.conf +++ b/novelwriter/assets/syntax/default_dark.conf @@ -26,9 +26,8 @@ link = 102, 153, 204 headertext = 153, 204, 153 headertag = 153, 204, 153, 160 emphasis = 249, 145, 87 -straightquotes = 230, 66, 80 -doublequotes = 102, 153, 204 -singlequotes = 102, 153, 204 +dialog = 102, 153, 204 +altdialog = 102, 153, 204 note = 255, 255, 216 hidden = 150, 150, 150 shortcode = 153, 204, 153 diff --git a/novelwriter/assets/syntax/default_light.conf b/novelwriter/assets/syntax/default_light.conf index f0b7ba25..2e5ae404 100644 --- a/novelwriter/assets/syntax/default_light.conf +++ b/novelwriter/assets/syntax/default_light.conf @@ -26,9 +26,8 @@ link = 0, 0, 200 headertext = 0, 100, 0 headertag = 0, 100, 0, 160 emphasis = 174, 110, 30 -straightquotes = 200, 50, 50 -doublequotes = 0, 0, 200 -singlequotes = 0, 0, 200 +dialog = 0, 0, 200 +altdialog = 0, 0, 200 note = 100, 100, 0 hidden = 100, 100, 100 shortcode = 0, 100, 0 diff --git a/novelwriter/assets/syntax/dracula.conf b/novelwriter/assets/syntax/dracula.conf index 34180c0e..fad01ea8 100644 --- a/novelwriter/assets/syntax/dracula.conf +++ b/novelwriter/assets/syntax/dracula.conf @@ -28,9 +28,8 @@ link = 255, 121, 198 headertext = 189, 147, 249 headertag = 189, 147, 249, 160 emphasis = 255, 184, 108 -straightquotes = 255, 85, 85 -doublequotes = 80, 250, 123 -singlequotes = 241, 250, 140 +dialog = 80, 250, 123 +altdialog = 241, 250, 140 note = 255, 204, 233 hidden = 98, 114, 164 shortcode = 139, 233, 253 diff --git a/novelwriter/assets/syntax/grey_dark.conf b/novelwriter/assets/syntax/grey_dark.conf index ed30ba74..cc36478c 100644 --- a/novelwriter/assets/syntax/grey_dark.conf +++ b/novelwriter/assets/syntax/grey_dark.conf @@ -13,9 +13,8 @@ link = 200, 200, 200 headertext = 225, 225, 225 headertag = 225, 225, 225, 160 emphasis = 200, 200, 200 -straightquotes = 200, 200, 200 -doublequotes = 200, 200, 200 -singlequotes = 200, 200, 200 +dialog = 200, 200, 200 +altdialog = 200, 200, 200 note = 200, 200, 200 hidden = 150, 150, 150 shortcode = 225, 225, 225 diff --git a/novelwriter/assets/syntax/grey_light.conf b/novelwriter/assets/syntax/grey_light.conf index 64a478da..80a8a01c 100644 --- a/novelwriter/assets/syntax/grey_light.conf +++ b/novelwriter/assets/syntax/grey_light.conf @@ -13,9 +13,8 @@ link = 20, 20, 20 headertext = 0, 0, 0 headertag = 0, 0, 0, 160 emphasis = 20, 20, 20 -straightquotes = 20, 20, 20 -doublequotes = 20, 20, 20 -singlequotes = 20, 20, 20 +dialog = 20, 20, 20 +altdialog = 20, 20, 20 note = 20, 20, 20 hidden = 100, 100, 100 shortcode = 0, 0, 0 diff --git a/novelwriter/assets/syntax/light_owl.conf b/novelwriter/assets/syntax/light_owl.conf index 8ad302ce..ce65e704 100644 --- a/novelwriter/assets/syntax/light_owl.conf +++ b/novelwriter/assets/syntax/light_owl.conf @@ -33,9 +33,8 @@ link = 40, 142, 215 headertext = 40, 142, 215 headertag = 40, 142, 215, 160 emphasis = 224, 175, 5 -straightquotes = 222, 61, 58 -doublequotes = 8, 145, 106 -singlequotes = 218, 170, 1 +dialog = 8, 145, 106 +altdialog = 218, 170, 1 note = 128, 118, 75 hidden = 152, 159, 177 shortcode = 40, 142, 215 diff --git a/novelwriter/assets/syntax/night_owl.conf b/novelwriter/assets/syntax/night_owl.conf index 17b231e5..337cdfb8 100644 --- a/novelwriter/assets/syntax/night_owl.conf +++ b/novelwriter/assets/syntax/night_owl.conf @@ -33,9 +33,8 @@ link = 130, 170, 255 headertext = 130, 170, 255 headertag = 130, 170, 255, 160 emphasis = 236, 196, 141 -straightquotes = 247, 140, 108 -doublequotes = 173, 219, 103 -singlequotes = 255, 235, 149 +dialog = 173, 219, 103 +altdialog = 255, 235, 149 note = 255, 249, 202 hidden = 99, 119, 119 shortcode = 130, 170, 255 diff --git a/novelwriter/assets/syntax/snazzy.conf b/novelwriter/assets/syntax/snazzy.conf index 8f44fd43..da979a00 100644 --- a/novelwriter/assets/syntax/snazzy.conf +++ b/novelwriter/assets/syntax/snazzy.conf @@ -26,9 +26,8 @@ link = 9, 161, 237 headertext = 45, 174, 88 headertag = 45, 174, 88, 160 emphasis = 19, 187, 183 -straightquotes = 255, 92, 87 -doublequotes = 207, 156, 0 -singlequotes = 207, 156, 0 +dialog = 207, 156, 0 +altdialog = 207, 156, 0 note = 120, 187, 185 hidden = 145, 148, 162 shortcode = 247, 103, 187 diff --git a/novelwriter/assets/syntax/solarized_dark.conf b/novelwriter/assets/syntax/solarized_dark.conf index 0529e96b..0fbacdb7 100644 --- a/novelwriter/assets/syntax/solarized_dark.conf +++ b/novelwriter/assets/syntax/solarized_dark.conf @@ -13,9 +13,8 @@ link = 38, 139, 210 headertext = 147, 161, 161 headertag = 42, 161, 152 emphasis = 38, 139, 210 -straightquotes = 211, 54, 130 -doublequotes = 42, 161, 152 -singlequotes = 42, 161, 152 +dialog = 42, 161, 152 +altdialog = 42, 161, 152 note = 101, 161, 156 hidden = 147, 161, 161 shortcode = 147, 161, 161 diff --git a/novelwriter/assets/syntax/solarized_light.conf b/novelwriter/assets/syntax/solarized_light.conf index 8366c438..525a59e5 100644 --- a/novelwriter/assets/syntax/solarized_light.conf +++ b/novelwriter/assets/syntax/solarized_light.conf @@ -13,9 +13,8 @@ link = 38, 139, 210 headertext = 88, 110, 117 headertag = 42, 161, 152 emphasis = 38, 139, 210 -straightquotes = 211, 54, 130 -doublequotes = 42, 161, 152 -singlequotes = 42, 161, 152 +dialog = 42, 161, 152 +altdialog = 42, 161, 152 note = 27, 102, 96 hidden = 88, 110, 117 shortcode = 88, 110, 117 diff --git a/novelwriter/assets/syntax/tango.conf b/novelwriter/assets/syntax/tango.conf index 2ee5c3f5..7c5e9daa 100644 --- a/novelwriter/assets/syntax/tango.conf +++ b/novelwriter/assets/syntax/tango.conf @@ -23,9 +23,8 @@ link = 114, 159, 207 headertext = 114, 159, 207 headertag = 114, 159, 207, 160 emphasis = 196, 160, 0 -straightquotes = 239, 41, 41 -doublequotes = 138, 226, 52 -singlequotes = 252, 233, 79 +dialog = 138, 226, 52 +altdialog = 252, 233, 79 note = 252, 242, 164 hidden = 143, 143, 141 shortcode = 114, 159, 207 diff --git a/novelwriter/assets/syntax/tomorrow.conf b/novelwriter/assets/syntax/tomorrow.conf index 1e84f0fd..d3d2b8e4 100644 --- a/novelwriter/assets/syntax/tomorrow.conf +++ b/novelwriter/assets/syntax/tomorrow.conf @@ -33,9 +33,8 @@ link = 66, 113, 174 headertext = 66, 113, 174 headertag = 66, 113, 174, 160 emphasis = 245, 135, 31 -straightquotes = 240, 40, 41 -doublequotes = 113, 140, 0 -singlequotes = 234, 183, 0 +dialog = 113, 140, 0 +altdialog = 234, 183, 0 note = 115, 90, 0 hidden = 142, 144, 140 shortcode = 66, 113, 174 diff --git a/novelwriter/assets/syntax/tomorrow_night.conf b/novelwriter/assets/syntax/tomorrow_night.conf index 0814e46e..15257945 100644 --- a/novelwriter/assets/syntax/tomorrow_night.conf +++ b/novelwriter/assets/syntax/tomorrow_night.conf @@ -33,9 +33,8 @@ link = 197, 200, 198, 160 headertext = 129, 162, 190 headertag = 94, 119, 139 emphasis = 222, 147, 95 -straightquotes = 204, 102, 102 -doublequotes = 181, 189, 104 -singlequotes = 240, 198, 116 +dialog = 181, 189, 104 +altdialog = 240, 198, 116 note = 240, 219, 178 hidden = 150, 152, 150 shortcode = 129, 162, 190 diff --git a/novelwriter/assets/syntax/tomorrow_night_blue.conf b/novelwriter/assets/syntax/tomorrow_night_blue.conf index ea1aa6da..89067e4f 100644 --- a/novelwriter/assets/syntax/tomorrow_night_blue.conf +++ b/novelwriter/assets/syntax/tomorrow_night_blue.conf @@ -33,9 +33,8 @@ link = 187, 218, 255 headertext = 187, 218, 255 headertag = 187, 218, 255, 160 emphasis = 255, 197, 143 -straightquotes = 255, 157, 164 -doublequotes = 209, 241, 169 -singlequotes = 255, 238, 173 +dialog = 209, 241, 169 +altdialog = 255, 238, 173 note = 255, 247, 214 hidden = 114, 133, 183 shortcode = 187, 218, 255 diff --git a/novelwriter/assets/syntax/tomorrow_night_bright.conf b/novelwriter/assets/syntax/tomorrow_night_bright.conf index c4969ad5..0f1fd055 100644 --- a/novelwriter/assets/syntax/tomorrow_night_bright.conf +++ b/novelwriter/assets/syntax/tomorrow_night_bright.conf @@ -33,9 +33,8 @@ link = 122, 166, 218 headertext = 122, 166, 218 headertag = 122, 166, 218, 160 emphasis = 231, 140, 69 -straightquotes = 213, 78, 83 -doublequotes = 185, 202, 74 -singlequotes = 231, 197, 71 +dialog = 185, 202, 74 +altdialog = 231, 197, 71 note = 231, 214, 150 hidden = 150, 152, 150 shortcode = 122, 166, 218 diff --git a/novelwriter/assets/syntax/tomorrow_night_eighties.conf b/novelwriter/assets/syntax/tomorrow_night_eighties.conf index a5c9c651..a638a871 100644 --- a/novelwriter/assets/syntax/tomorrow_night_eighties.conf +++ b/novelwriter/assets/syntax/tomorrow_night_eighties.conf @@ -33,9 +33,8 @@ link = 102, 153, 204 headertext = 102, 153, 204 headertag = 102, 153, 204, 160 emphasis = 249, 145, 57 -straightquotes = 242, 119, 122 -doublequotes = 153, 204, 153 -singlequotes = 255, 204, 102 +dialog = 153, 204, 153 +altdialog = 255, 204, 102 note = 255, 230, 179 hidden = 153, 153, 153 shortcode = 102, 153, 204 diff --git a/novelwriter/gui/dochighlight.py b/novelwriter/gui/dochighlight.py index 361b7139..0039f6bb 100644 --- a/novelwriter/gui/dochighlight.py +++ b/novelwriter/gui/dochighlight.py @@ -94,32 +94,33 @@ class GuiDocHighlighter(QSyntaxHighlighter): colBreak.setAlpha(64) # Create Character Formats - self._addCharFormat("text", SHARED.theme.colText) - self._addCharFormat("header1", SHARED.theme.colHead, "b", 1.8) - self._addCharFormat("header2", SHARED.theme.colHead, "b", 1.6) - self._addCharFormat("header3", SHARED.theme.colHead, "b", 1.4) - self._addCharFormat("header4", SHARED.theme.colHead, "b", 1.2) - self._addCharFormat("head1h", SHARED.theme.colHeadH, "b", 1.8) - self._addCharFormat("head2h", SHARED.theme.colHeadH, "b", 1.6) - self._addCharFormat("head3h", SHARED.theme.colHeadH, "b", 1.4) - self._addCharFormat("head4h", SHARED.theme.colHeadH, "b", 1.2) - self._addCharFormat("bold", colEmph, "b") - self._addCharFormat("italic", colEmph, "i") - self._addCharFormat("strike", SHARED.theme.colHidden, "s") - self._addCharFormat("mspaces", SHARED.theme.colError, "err") - self._addCharFormat("nobreak", colBreak, "bg") - self._addCharFormat("dialog", SHARED.theme.colDialog) - self._addCharFormat("replace", SHARED.theme.colRepTag) - self._addCharFormat("hidden", SHARED.theme.colHidden) - self._addCharFormat("markup", SHARED.theme.colHidden) - self._addCharFormat("note", SHARED.theme.colNote) - self._addCharFormat("code", SHARED.theme.colCode) - self._addCharFormat("keyword", SHARED.theme.colKey) - self._addCharFormat("tag", SHARED.theme.colTag) - self._addCharFormat("modifier", SHARED.theme.colMod) - self._addCharFormat("value", SHARED.theme.colVal) - self._addCharFormat("optional", SHARED.theme.colOpt) - self._addCharFormat("invalid", None, "err") + self._addCharFormat("text", SHARED.theme.colText) + self._addCharFormat("header1", SHARED.theme.colHead, "b", 1.8) + self._addCharFormat("header2", SHARED.theme.colHead, "b", 1.6) + self._addCharFormat("header3", SHARED.theme.colHead, "b", 1.4) + self._addCharFormat("header4", SHARED.theme.colHead, "b", 1.2) + self._addCharFormat("head1h", SHARED.theme.colHeadH, "b", 1.8) + self._addCharFormat("head2h", SHARED.theme.colHeadH, "b", 1.6) + self._addCharFormat("head3h", SHARED.theme.colHeadH, "b", 1.4) + self._addCharFormat("head4h", SHARED.theme.colHeadH, "b", 1.2) + self._addCharFormat("bold", colEmph, "b") + self._addCharFormat("italic", colEmph, "i") + self._addCharFormat("strike", SHARED.theme.colHidden, "s") + self._addCharFormat("mspaces", SHARED.theme.colError, "err") + self._addCharFormat("nobreak", colBreak, "bg") + self._addCharFormat("altdialog", SHARED.theme.colDialA) + self._addCharFormat("dialog", SHARED.theme.colDialN) + self._addCharFormat("replace", SHARED.theme.colRepTag) + self._addCharFormat("hidden", SHARED.theme.colHidden) + self._addCharFormat("markup", SHARED.theme.colHidden) + self._addCharFormat("note", SHARED.theme.colNote) + self._addCharFormat("code", SHARED.theme.colCode) + self._addCharFormat("keyword", SHARED.theme.colKey) + self._addCharFormat("tag", SHARED.theme.colTag) + self._addCharFormat("modifier", SHARED.theme.colMod) + self._addCharFormat("value", SHARED.theme.colVal) + self._addCharFormat("optional", SHARED.theme.colOpt) + self._addCharFormat("invalid", None, "err") # Cache Spell Error Format self._spellErr = QTextCharFormat() diff --git a/novelwriter/gui/theme.py b/novelwriter/gui/theme.py index ebcf5e04..f9c26b2e 100644 --- a/novelwriter/gui/theme.py +++ b/novelwriter/gui/theme.py @@ -95,7 +95,8 @@ class GuiTheme: self.colHead = QColor(0, 0, 0) self.colHeadH = QColor(0, 0, 0) self.colEmph = QColor(0, 0, 0) - self.colDialog = QColor(0, 0, 0) + self.colDialN = QColor(0, 0, 0) + self.colDialA = QColor(0, 0, 0) self.colHidden = QColor(0, 0, 0) self.colNote = QColor(0, 0, 0) self.colCode = QColor(0, 0, 0) @@ -336,7 +337,8 @@ class GuiTheme: self.colHead = self._parseColour(confParser, cnfSec, "headertext") self.colHeadH = self._parseColour(confParser, cnfSec, "headertag") self.colEmph = self._parseColour(confParser, cnfSec, "emphasis") - self.colDialog = self._parseColour(confParser, cnfSec, "dialog") + self.colDialN = self._parseColour(confParser, cnfSec, "dialog") + self.colDialA = self._parseColour(confParser, cnfSec, "altdialog") self.colHidden = self._parseColour(confParser, cnfSec, "hidden") self.colNote = self._parseColour(confParser, cnfSec, "note") self.colCode = self._parseColour(confParser, cnfSec, "shortcode") From b5def640edd3ec2b329134dc7accb70cc7158275 Mon Sep 17 00:00:00 2001 From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com> Date: Mon, 13 May 2024 18:11:44 +0200 Subject: [PATCH 4/6] Add alternative dialog style --- novelwriter/config.py | 18 +++++--- novelwriter/dialogs/preferences.py | 69 ++++++++++++++++++++++-------- novelwriter/gui/dochighlight.py | 18 ++++++-- 3 files changed, 76 insertions(+), 29 deletions(-) diff --git a/novelwriter/config.py b/novelwriter/config.py index 91945fe3..af21e7dd 100644 --- a/novelwriter/config.py +++ b/novelwriter/config.py @@ -158,10 +158,12 @@ class Config: self.autoScrollPos = 30 # Start point for typewriter-like scrolling self.scrollPastEnd = True # Scroll past end of document, and centre cursor - self.dialogueStyle = 2 # Quote type to use for dialogue + self.dialogStyle = 2 # Quote type to use for dialogue self.allowOpenDial = True # Allow open-ended dialogue quotes self.narratorBreak = "" # Symbol to use for narrator break - self.dialogueLine = "" # Symbol to use for dialogue line + self.dialogLine = "" # Symbol to use for dialogue line + self.altDialogOpen = "" # Alternative dialog symbol, open + self.altDialogClose = "" # Alternative dialog symbol, close self.highlightEmph = True # Add colour to text emphasis self.stopWhenIdle = True # Stop the status bar clock when the user is idle @@ -619,10 +621,12 @@ class Config: self.showMultiSpaces = conf.rdBool(sec, "showmultispaces", self.showMultiSpaces) self.incNotesWCount = conf.rdBool(sec, "incnoteswcount", self.incNotesWCount) self.showFullPath = conf.rdBool(sec, "showfullpath", self.showFullPath) - self.dialogueStyle = conf.rdInt(sec, "dialoguestyle", self.dialogueStyle) + self.dialogStyle = conf.rdInt(sec, "dialogstyle", self.dialogStyle) self.allowOpenDial = conf.rdBool(sec, "allowopendial", self.allowOpenDial) self.narratorBreak = conf.rdStr(sec, "narratorbreak", self.narratorBreak) - self.dialogueLine = conf.rdStr(sec, "dialogueline", self.dialogueLine) + self.altDialogOpen = conf.rdStr(sec, "altdialogopen", self.altDialogOpen) + self.altDialogClose = conf.rdStr(sec, "altdialogclose", self.altDialogClose) + self.dialogLine = conf.rdStr(sec, "dialogline", self.dialogLine) self.highlightEmph = conf.rdBool(sec, "highlightemph", self.highlightEmph) self.stopWhenIdle = conf.rdBool(sec, "stopwhenidle", self.stopWhenIdle) self.userIdleTime = conf.rdInt(sec, "useridletime", self.userIdleTime) @@ -728,10 +732,12 @@ class Config: "showmultispaces": str(self.showMultiSpaces), "incnoteswcount": str(self.incNotesWCount), "showfullpath": str(self.showFullPath), - "dialoguestyle": str(self.dialogueStyle), + "dialogstyle": str(self.dialogStyle), "allowopendial": str(self.allowOpenDial), "narratorbreak": str(self.narratorBreak), - "dialogueline": str(self.dialogueLine), + "altdialogopen": str(self.altDialogOpen), + "altdialogclose": str(self.altDialogClose), + "dialogline": str(self.dialogLine), "highlightemph": str(self.highlightEmph), "stopwhenidle": str(self.stopWhenIdle), "useridletime": str(self.userIdleTime), diff --git a/novelwriter/dialogs/preferences.py b/novelwriter/dialogs/preferences.py index 6f90a26d..c28ed169 100644 --- a/novelwriter/dialogs/preferences.py +++ b/novelwriter/dialogs/preferences.py @@ -539,14 +539,14 @@ class GuiPreferences(QDialog): self.sidebar.addButton(title, section) self.mainForm.addGroupLabel(title, section) - self.dialogueStyle = NComboBox(self) - self.dialogueStyle.addItem(self.tr("None"), 0) - self.dialogueStyle.addItem(self.tr("Single Quotes"), 1) - self.dialogueStyle.addItem(self.tr("Double Quotes"), 2) - self.dialogueStyle.addItem(self.tr("Both"), 3) - self.dialogueStyle.setCurrentData(CONFIG.dialogueStyle, 2) + self.dialogStyle = NComboBox(self) + self.dialogStyle.addItem(self.tr("None"), 0) + self.dialogStyle.addItem(self.tr("Single Quotes"), 1) + self.dialogStyle.addItem(self.tr("Double Quotes"), 2) + self.dialogStyle.addItem(self.tr("Both"), 3) + self.dialogStyle.setCurrentData(CONFIG.dialogStyle, 2) self.mainForm.addRow( - self.tr("Highlight dialogue"), self.dialogueStyle, + self.tr("Highlight dialogue"), self.dialogStyle, self.tr("Applies to the selected quote styles.") ) @@ -567,16 +567,41 @@ class GuiPreferences(QDialog): self.tr("Symbol to indicate injected narrator break.") ) - self.dialogueLine = QLineEdit(self) - self.dialogueLine.setMaxLength(1) - self.dialogueLine.setFixedWidth(boxFixed) - self.dialogueLine.setAlignment(QtAlignCenter) - self.dialogueLine.setText(CONFIG.dialogueLine) + self.dialogLine = QLineEdit(self) + self.dialogLine.setMaxLength(1) + self.dialogLine.setFixedWidth(boxFixed) + self.dialogLine.setAlignment(QtAlignCenter) + self.dialogLine.setText(CONFIG.dialogLine) self.mainForm.addRow( - self.tr("Dialogue line symbol"), self.dialogueLine, + self.tr("Dialogue line symbol"), self.dialogLine, self.tr("Lines starting with this symbol are dialogue.") ) + self.altDialogOpen = QLineEdit(self) + self.altDialogOpen.setMaxLength(4) + self.altDialogOpen.setFixedWidth(boxFixed) + self.altDialogOpen.setAlignment(QtAlignCenter) + self.altDialogOpen.setText(CONFIG.altDialogOpen) + + self.altDialogClose = QLineEdit(self) + self.altDialogClose.setMaxLength(4) + self.altDialogClose.setFixedWidth(boxFixed) + self.altDialogClose.setAlignment(QtAlignCenter) + self.altDialogClose.setText(CONFIG.altDialogClose) + + self.altDialogBox = QHBoxLayout() + self.altDialogBox.addWidget(self.altDialogOpen) + self.altDialogBox.addWidget(self.altDialogClose) + self.altDialogBox.setContentsMargins(0, 0, 0, 0) + + self.altDialog = QWidget(self) + self.altDialog.setLayout(self.altDialogBox) + + self.mainForm.addRow( + self.tr("Alternative dialog symbols"), self.altDialog, + self.tr("Custom highlighting of dialog text.") + ) + self.highlightEmph = NSwitch(self) self.highlightEmph.setChecked(CONFIG.highlightEmph) self.mainForm.addRow( @@ -936,24 +961,30 @@ class GuiPreferences(QDialog): CONFIG.scrollPastEnd = self.scrollPastEnd.isChecked() # Text Highlighting - dialogueStyle = self.dialogueStyle.currentData() + dialogueStyle = self.dialogStyle.currentData() allowOpenDial = self.allowOpenDial.isChecked() narratorBreak = self.narratorBreak.text() - dialogueLine = self.dialogueLine.text() + dialogueLine = self.dialogLine.text() + altDialogOpen = self.altDialogOpen.text() + altDialogClose = self.altDialogClose.text() highlightEmph = self.highlightEmph.isChecked() showMultiSpaces = self.showMultiSpaces.isChecked() - updateSyntax |= CONFIG.dialogueStyle != dialogueStyle + updateSyntax |= CONFIG.dialogStyle != dialogueStyle updateSyntax |= CONFIG.allowOpenDial != allowOpenDial updateSyntax |= CONFIG.narratorBreak != narratorBreak - updateSyntax |= CONFIG.dialogueLine != dialogueLine + updateSyntax |= CONFIG.dialogLine != dialogueLine + updateSyntax |= CONFIG.altDialogOpen != altDialogOpen + updateSyntax |= CONFIG.altDialogClose != altDialogClose updateSyntax |= CONFIG.highlightEmph != highlightEmph updateSyntax |= CONFIG.showMultiSpaces != showMultiSpaces - CONFIG.dialogueStyle = dialogueStyle + CONFIG.dialogStyle = dialogueStyle CONFIG.allowOpenDial = allowOpenDial CONFIG.narratorBreak = narratorBreak - CONFIG.dialogueLine = dialogueLine + CONFIG.dialogLine = dialogueLine + CONFIG.altDialogOpen = altDialogOpen + CONFIG.altDialogClose = altDialogClose CONFIG.highlightEmph = highlightEmph CONFIG.showMultiSpaces = showMultiSpaces diff --git a/novelwriter/gui/dochighlight.py b/novelwriter/gui/dochighlight.py index 0039f6bb..0554beb3 100644 --- a/novelwriter/gui/dochighlight.py +++ b/novelwriter/gui/dochighlight.py @@ -150,13 +150,13 @@ class GuiDocHighlighter(QSyntaxHighlighter): self._cmnRules.append((rxRule, hlRule)) # Dialogue - if CONFIG.dialogueStyle > 0: + if CONFIG.dialogStyle > 0: symO = "" symC = "" - if CONFIG.dialogueStyle in (1, 3): + if CONFIG.dialogStyle in (1, 3): symO += CONFIG.fmtSQuoteOpen symC += CONFIG.fmtSQuoteClose - if CONFIG.dialogueStyle in (2, 3): + if CONFIG.dialogStyle in (2, 3): symO += CONFIG.fmtDQuoteOpen symC += CONFIG.fmtDQuoteClose @@ -168,7 +168,7 @@ class GuiDocHighlighter(QSyntaxHighlighter): } self._txtRules.append((rxRule, hlRule)) - if sym := CONFIG.dialogueLine: + if sym := CONFIG.dialogLine: rxRule = QRegularExpression(f"^{sym}.*?$") rxRule.setPatternOptions(QRegExUnicode) hlRule = { @@ -184,6 +184,16 @@ class GuiDocHighlighter(QSyntaxHighlighter): } self._txtRules.append((rxRule, hlRule)) + if CONFIG.altDialogOpen and CONFIG.altDialogClose: + symO = QRegularExpression.escape(CONFIG.altDialogOpen) + symC = QRegularExpression.escape(CONFIG.altDialogClose) + rxRule = QRegularExpression(f"\\B{symO}.*?{symC}\\B") + rxRule.setPatternOptions(QRegExUnicode) + hlRule = { + 0: self._hStyles["altdialog"], + } + self._txtRules.append((rxRule, hlRule)) + # Markdown Italic rxRule = QRegularExpression(nwRegEx.FMT_EI) rxRule.setPatternOptions(QRegExUnicode) From d64acb038b201dd064ef16ae02574e4b2ef2986e Mon Sep 17 00:00:00 2001 From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com> Date: Mon, 13 May 2024 18:31:14 +0200 Subject: [PATCH 5/6] Allow multiple widgets in config form --- novelwriter/dialogs/preferences.py | 10 +--------- novelwriter/extensions/configlayout.py | 24 +++++++++++++++++------- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/novelwriter/dialogs/preferences.py b/novelwriter/dialogs/preferences.py index c28ed169..af4e6980 100644 --- a/novelwriter/dialogs/preferences.py +++ b/novelwriter/dialogs/preferences.py @@ -589,16 +589,8 @@ class GuiPreferences(QDialog): self.altDialogClose.setAlignment(QtAlignCenter) self.altDialogClose.setText(CONFIG.altDialogClose) - self.altDialogBox = QHBoxLayout() - self.altDialogBox.addWidget(self.altDialogOpen) - self.altDialogBox.addWidget(self.altDialogClose) - self.altDialogBox.setContentsMargins(0, 0, 0, 0) - - self.altDialog = QWidget(self) - self.altDialog.setLayout(self.altDialogBox) - self.mainForm.addRow( - self.tr("Alternative dialog symbols"), self.altDialog, + self.tr("Alternative dialog symbols"), [self.altDialogOpen, self.altDialogClose], self.tr("Custom highlighting of dialog text.") ) diff --git a/novelwriter/extensions/configlayout.py b/novelwriter/extensions/configlayout.py index d73774eb..e9f8194d 100644 --- a/novelwriter/extensions/configlayout.py +++ b/novelwriter/extensions/configlayout.py @@ -180,16 +180,26 @@ class NScrollableForm(QScrollArea): self._sections[identifier] = qLabel return - def addRow(self, label: str, widget: QWidget, helpText: str = "", unit: str | None = None, - button: QWidget | None = None, editable: str | None = None, + def addRow(self, label: str, widget: QWidget | list[QWidget], helpText: str = "", + unit: str | None = None, button: QWidget | None = None, editable: str | None = None, stretch: tuple[int, int] = (1, 0)) -> None: """Add a label and a widget as a new row of the form.""" row = QHBoxLayout() row.setSpacing(CONFIG.pxInt(12)) + if isinstance(widget, list): + wBox = QHBoxLayout() + wBox.setContentsMargins(0, 0, 0, 0) + for item in widget: + wBox.addWidget(item) + qWidget = QWidget(self) + qWidget.setLayout(wBox) + else: + qWidget = widget + qLabel = QLabel(label, self) qLabel.setIndent(self._indent) - qLabel.setBuddy(widget) + qLabel.setBuddy(qWidget) if helpText: qHelp = NColourLabel( @@ -208,19 +218,19 @@ class NScrollableForm(QScrollArea): if isinstance(unit, str): box = QHBoxLayout() - box.addWidget(widget, 1) + box.addWidget(qWidget, 1) box.addWidget(QLabel(unit, self), 0) row.addLayout(box, stretch[1]) elif isinstance(button, QAbstractButton): box = QHBoxLayout() - box.addWidget(widget, 1) + box.addWidget(qWidget, 1) box.addWidget(button, 0) row.addLayout(box, stretch[1]) else: - row.addWidget(widget, stretch[1]) + row.addWidget(qWidget, stretch[1]) self._layout.addLayout(row) - self._index[label.strip()] = widget + self._index[label.strip()] = qWidget self._first = False return From 1b4cc933e716dcad3e99e925465a8c37bcf8c3b8 Mon Sep 17 00:00:00 2001 From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com> Date: Mon, 13 May 2024 18:31:31 +0200 Subject: [PATCH 6/6] Add test coverage --- novelwriter/gui/dochighlight.py | 6 +++-- tests/reference/baseConfig_novelwriter.conf | 11 +++++--- tests/test_dialogs/test_dlg_preferences.py | 30 ++++++++++++--------- tests/test_gui/test_gui_guimain.py | 10 ++++++- 4 files changed, 38 insertions(+), 19 deletions(-) diff --git a/novelwriter/gui/dochighlight.py b/novelwriter/gui/dochighlight.py index 0554beb3..ddbdcaa3 100644 --- a/novelwriter/gui/dochighlight.py +++ b/novelwriter/gui/dochighlight.py @@ -168,7 +168,8 @@ class GuiDocHighlighter(QSyntaxHighlighter): } self._txtRules.append((rxRule, hlRule)) - if sym := CONFIG.dialogLine: + if CONFIG.dialogLine: + sym = QRegularExpression.escape(CONFIG.dialogLine) rxRule = QRegularExpression(f"^{sym}.*?$") rxRule.setPatternOptions(QRegExUnicode) hlRule = { @@ -176,7 +177,8 @@ class GuiDocHighlighter(QSyntaxHighlighter): } self._txtRules.append((rxRule, hlRule)) - if sym := CONFIG.narratorBreak: + if CONFIG.narratorBreak: + sym = QRegularExpression.escape(CONFIG.narratorBreak) rxRule = QRegularExpression(f"({sym}\\b)(.*?)(\\b{sym})") rxRule.setPatternOptions(QRegExUnicode) hlRule = { diff --git a/tests/reference/baseConfig_novelwriter.conf b/tests/reference/baseConfig_novelwriter.conf index 668c3fb9..818f4280 100644 --- a/tests/reference/baseConfig_novelwriter.conf +++ b/tests/reference/baseConfig_novelwriter.conf @@ -1,5 +1,5 @@ [Meta] -timestamp = 2024-04-13 18:57:38 +timestamp = 2024-05-13 15:59:59 [Main] theme = default @@ -59,9 +59,12 @@ showlineendings = False showmultispaces = True incnoteswcount = True showfullpath = True -highlightquotes = True -allowopensquote = False -allowopendquote = True +dialogstyle = 2 +allowopendial = True +narratorbreak = +altdialogopen = +altdialogclose = +dialogline = highlightemph = True stopwhenidle = True useridletime = 300 diff --git a/tests/test_dialogs/test_dlg_preferences.py b/tests/test_dialogs/test_dlg_preferences.py index 59e705ff..360c339f 100644 --- a/tests/test_dialogs/test_dlg_preferences.py +++ b/tests/test_dialogs/test_dlg_preferences.py @@ -266,18 +266,21 @@ def testDlgPreferences_Settings(qtbot, monkeypatch, nwGUI, tstPaths): assert CONFIG.autoScrollPos == 30 # Text Highlighting - prefs.allowOpenSQuote.setChecked(True) - prefs.allowOpenDQuote.setChecked(False) - prefs.highlightQuotes.setChecked(False) + prefs.dialogStyle.setCurrentData(3, 0) + prefs.allowOpenDial.setChecked(False) + prefs.narratorBreak.setText("–") + prefs.dialogLine.setText("–") + prefs.altDialogOpen.setText("<") + prefs.altDialogClose.setText(">") prefs.highlightEmph.setChecked(False) prefs.showMultiSpaces.setChecked(False) - assert prefs.allowOpenSQuote.isEnabled() is False - assert prefs.allowOpenDQuote.isEnabled() is False - - assert CONFIG.highlightQuotes is True - assert CONFIG.allowOpenSQuote is False - assert CONFIG.allowOpenDQuote is True + assert CONFIG.dialogStyle == 2 + assert CONFIG.allowOpenDial is True + assert CONFIG.narratorBreak == "" + assert CONFIG.dialogLine == "" + assert CONFIG.altDialogOpen == "" + assert CONFIG.altDialogClose == "" assert CONFIG.highlightEmph is True assert CONFIG.showMultiSpaces is True @@ -384,9 +387,12 @@ def testDlgPreferences_Settings(qtbot, monkeypatch, nwGUI, tstPaths): assert CONFIG.autoScrollPos == 31 # Text Highlighting - assert CONFIG.highlightQuotes is False - assert CONFIG.allowOpenSQuote is True - assert CONFIG.allowOpenDQuote is False + assert CONFIG.dialogStyle == 3 + assert CONFIG.allowOpenDial is False + assert CONFIG.narratorBreak == "–" + assert CONFIG.dialogLine == "–" + assert CONFIG.altDialogOpen == "<" + assert CONFIG.altDialogClose == ">" assert CONFIG.highlightEmph is False assert CONFIG.showMultiSpaces is False diff --git a/tests/test_gui/test_gui_guimain.py b/tests/test_gui/test_gui_guimain.py index 4027a953..e128503c 100644 --- a/tests/test_gui/test_gui_guimain.py +++ b/tests/test_gui/test_gui_guimain.py @@ -231,7 +231,15 @@ def testGuiMain_Editing(qtbot, monkeypatch, nwGUI, projPath, tstPaths, mockRnd): # Text Editor # =========== - docEditor: GuiDocEditor = nwGUI.docEditor + # Syntax Highlighting + CONFIG.dialogStyle = 3 + CONFIG.dialogLine = "–" + CONFIG.narratorBreak = "–" + CONFIG.altDialogOpen = "<|" + CONFIG.altDialogClose = "|>" + + docEditor = nwGUI.docEditor + docEditor._qDocument.syntaxHighlighter.initHighlighter() # Type something into the document nwGUI.switchFocus(nwWidget.EDITOR)