From ffc577c943bb2348b78b68c0f7b5007c233e50de Mon Sep 17 00:00:00 2001 From: "Veronica K. B. Olsen" Date: Tue, 23 Apr 2019 16:37:48 +0200 Subject: [PATCH] Added format menu back in, and added a generic wrapping function that can do text formatting and wrap selection in quotes. --- nw/config.py | 4 + nw/enum.py | 16 ++ nw/gui/doceditor.py | 42 ++++- nw/gui/dochighlight.py | 25 ++- nw/gui/winmain.py | 176 +++++++++++------- .../sampleNovel/data_9/6b68994dfa3d_main.nwd | 2 +- sample/sampleNovel/nwProject.nwx | 6 +- 7 files changed, 192 insertions(+), 79 deletions(-) diff --git a/nw/config.py b/nw/config.py index 19337372..f34c870d 100644 --- a/nw/config.py +++ b/nw/config.py @@ -61,6 +61,7 @@ class Config: self.textFixedW = True self.textWidth = 600 self.textMargin = [40, 40] + self.autoSelect = True self.doReplace = True self.doReplaceSQuote = True self.doReplaceDQuote = True @@ -121,6 +122,8 @@ class Config: self.textMargin = self.unpackList( confParser.get(cnfSec,"margins"), 2, self.textMargin ) + if confParser.has_option(cnfSec,"autoselect"): + self.autoSelect = confParser.getboolean(cnfSec,"autoselect") if confParser.has_option(cnfSec,"autoreplace"): self.doReplace = confParser.getboolean(cnfSec,"autoreplace") if confParser.has_option(cnfSec,"repsquotes"): @@ -166,6 +169,7 @@ class Config: confParser.set(cnfSec,"fixedwidth", str(self.textFixedW)) confParser.set(cnfSec,"width", str(self.textWidth)) confParser.set(cnfSec,"margins", self.packList(self.textMargin)) + confParser.set(cnfSec,"autoselect", str(self.autoSelect)) confParser.set(cnfSec,"autoreplace",str(self.doReplace)) confParser.set(cnfSec,"repsquotes", str(self.doReplaceSQuote)) confParser.set(cnfSec,"repdquotes", str(self.doReplaceDQuote)) diff --git a/nw/enum.py b/nw/enum.py index ad6642ab..1936151e 100644 --- a/nw/enum.py +++ b/nw/enum.py @@ -54,3 +54,19 @@ class nwItemAction(Enum): EMPTY_TRASH = 12 # END Enum nwItemAction + +class nwDocAction(Enum): + + NONE = 0 + UNDO = 1 + REDO = 2 + CUT = 3 + COPY = 4 + PASTE = 5 + BOLD = 6 + ITALIC = 7 + U_LINE = 8 + S_QUOTE = 9 + D_QUOTE = 10 + +# END Enum nwDocAction diff --git a/nw/gui/doceditor.py b/nw/gui/doceditor.py index 7c622125..374962a8 100644 --- a/nw/gui/doceditor.py +++ b/nw/gui/doceditor.py @@ -13,13 +13,15 @@ import logging import nw -from time import time +from time import time from PyQt5.QtWidgets import QTextEdit from PyQt5.QtCore import QTimer +from PyQt5.QtGui import QTextCursor from nw.gui.dochighlight import GuiDocHighlighter from nw.gui.wordcounter import WordCounter +from nw.enum import nwDocAction logger = logging.getLogger(__name__) @@ -106,6 +108,22 @@ class GuiDocEditor(QTextEdit): self.setViewportMargins(tM,mTB,0,mTB) return + def docAction(self, theAction): + logger.verbose("Requesting action: %s" % theAction.name) + if theAction == nwDocAction.UNDO: self.undo() + elif theAction == nwDocAction.REDO: self.redo() + elif theAction == nwDocAction.CUT: self.cut() + elif theAction == nwDocAction.COPY: self.copy() + elif theAction == nwDocAction.PASTE: self.paste() + elif theAction == nwDocAction.BOLD: self._wrapSelection("**","**") + elif theAction == nwDocAction.ITALIC: self._wrapSelection("_","_") + elif theAction == nwDocAction.U_LINE: self._wrapSelection("__","__") + elif theAction == nwDocAction.S_QUOTE: self._wrapSelection(self.typSQOpen,self.typSQClose) + elif theAction == nwDocAction.D_QUOTE: self._wrapSelection(self.typDQOpen,self.typDQClose) + else: + logger.error("Unknown or unsupported document action %s" % str(theAction)) + return + ## # Document Events and Maintenance ## @@ -217,4 +235,26 @@ class GuiDocEditor(QTextEdit): return + def _wrapSelection(self, tBefore, tAfter): + """Wraps the selected text in whatever is in tBefore and tAfter. If there is no selection, the autoSelect setting decides + the action. AutoSelect will select the word under the cursor before wrapping it. If this feature is disabled, nothing is + done. + """ + theCursor = self.textCursor() + if self.mainConf.autoSelect and not theCursor.hasSelection(): + theCursor.select(QTextCursor.WordUnderCursor) + if theCursor.hasSelection(): + posS = theCursor.selectionStart() + posE = theCursor.selectionEnd() + theCursor.clearSelection() + theCursor.beginEditBlock() + theCursor.setPosition(posE) + theCursor.insertText(tAfter) + theCursor.setPosition(posS) + theCursor.insertText(tBefore) + theCursor.endEditBlock() + else: + logger.warning("No selection made, nothing to do") + return + # END Class GuiDocEditor diff --git a/nw/gui/dochighlight.py b/nw/gui/dochighlight.py index da0db3db..7f11e96d 100644 --- a/nw/gui/dochighlight.py +++ b/nw/gui/dochighlight.py @@ -27,12 +27,14 @@ class GuiDocHighlighter(QSyntaxHighlighter): self.mainConf = nw.CONFIG self.theDoc = theDoc - self.colHead = ( 0,155,200,255) - self.colEmph = (200,120, 0,255) - self.colDial = (184,200, 0,255) - self.colComm = (120,120,120,255) - self.colKey = (200, 0, 0,255) - self.colVal = (184,200, 0,255) + self.colHead = ( 0,155,200,255) + self.colEmph = (200,120, 0,255) + self.colDialN = (48, 200, 0,255) + self.colDialD = (184,200, 0,255) + self.colDialS = (136,200, 0,255) + self.colComm = (120,120,120,255) + self.colKey = (200, 0, 0,255) + self.colVal = (184,200, 0,255) self.hStyles = { "header1" : self._makeFormat(self.colHead,"bold",20), @@ -43,7 +45,9 @@ class GuiDocHighlighter(QSyntaxHighlighter): "italic" : self._makeFormat(self.colEmph,"italic"), "strike" : self._makeFormat(self.colEmph,"strike"), "underline" : self._makeFormat(self.colEmph,"underline"), - "dialogue" : self._makeFormat(self.colDial), + "dialogue1" : self._makeFormat(self.colDialN), + "dialogue2" : self._makeFormat(self.colDialD), + "dialogue3" : self._makeFormat(self.colDialS), "hidden" : self._makeFormat(self.colComm), "keyword" : self._makeFormat(self.colKey), "value" : self._makeFormat(self.colVal), @@ -56,18 +60,19 @@ class GuiDocHighlighter(QSyntaxHighlighter): (r"^#{4}[^#].*[^\n]", 0, self.hStyles["header4"]), (r"(? New Project - menuNewProject = QAction(QIcon.fromTheme("folder-new"), "New Project", menuBar) - menuNewProject.setStatusTip("Create New Project") - menuNewProject.triggered.connect(self.newProject) - fileMenu.addAction(menuNewProject) + menuItem = QAction(QIcon.fromTheme("folder-new"), "New Project", menuBar) + menuItem.setStatusTip("Create New Project") + menuItem.triggered.connect(self.newProject) + fileMenu.addAction(menuItem) # File > Open Project - menuOpenProject = QAction(QIcon.fromTheme("folder-open"), "Open Project", menuBar) - menuOpenProject.setStatusTip("Open Project") - menuOpenProject.triggered.connect(self.openProject) - fileMenu.addAction(menuOpenProject) + menuItem = QAction(QIcon.fromTheme("folder-open"), "Open Project", menuBar) + menuItem.setStatusTip("Open Project") + menuItem.triggered.connect(self.openProject) + fileMenu.addAction(menuItem) # File > Save Project - menuSaveProject = QAction(QIcon.fromTheme("document-save"), "Save Project", menuBar) - menuSaveProject.setStatusTip("Save Project") - menuSaveProject.triggered.connect(self.saveProject) - fileMenu.addAction(menuSaveProject) + menuItem = QAction(QIcon.fromTheme("document-save"), "Save Project", menuBar) + menuItem.setStatusTip("Save Project") + menuItem.triggered.connect(self.saveProject) + fileMenu.addAction(menuItem) # File > Recent Project recentMenu = fileMenu.addMenu(QIcon.fromTheme("document-open-recent"),"Recent Projects") itemCount = 0 for recentProject in self.mainConf.recentList: if recentProject == "": continue - menuRecentProject = QAction(QIcon.fromTheme("folder-open"), "%d: %s" % (itemCount,recentProject), fileMenu) - menuRecentProject.triggered.connect(self.openRecentProject, itemCount) - recentMenu.addAction(menuRecentProject) + menuItem = QAction(QIcon.fromTheme("folder-open"), "%d: %s" % (itemCount,recentProject), fileMenu) + menuItem.triggered.connect(self.openRecentProject, itemCount) + recentMenu.addAction(menuItem) itemCount += 1 # File > Separator fileMenu.addSeparator() # File > Project Settings - menuProjectSettings = QAction(QIcon.fromTheme("document-properties"), "Project Settings", menuBar) - menuProjectSettings.setStatusTip("Project Settings") - menuProjectSettings.triggered.connect(self.editProject) - fileMenu.addAction(menuProjectSettings) + menuItem = QAction(QIcon.fromTheme("document-properties"), "Project Settings", menuBar) + menuItem.setStatusTip("Project Settings") + menuItem.triggered.connect(self.editProject) + fileMenu.addAction(menuItem) # File > Separator fileMenu.addSeparator() # File > New - menuNew = QAction(QIcon.fromTheme("document-new"), "&New", menuBar) - menuNew.setShortcut("Ctrl+N") - menuNew.setStatusTip("Create new document") - fileMenu.addAction(menuNew) + menuItem = QAction(QIcon.fromTheme("document-new"), "&New", menuBar) + menuItem.setStatusTip("Create new document") + menuItem.setShortcut("Ctrl+N") + fileMenu.addAction(menuItem) # File > Save - menuSave = QAction(QIcon.fromTheme("document-save"), "&Save", menuBar) - menuSave.setShortcut("Ctrl+S") - menuSave.setStatusTip("Save document") - menuSave.triggered.connect(self.saveDocument) - fileMenu.addAction(menuSave) + menuItem = QAction(QIcon.fromTheme("document-save"), "&Save", menuBar) + menuItem.setStatusTip("Save document") + menuItem.setShortcut("Ctrl+S") + menuItem.triggered.connect(self.saveDocument) + fileMenu.addAction(menuItem) # File > Separator fileMenu.addSeparator() # File > Exit - menuExit = QAction(QIcon.fromTheme("application-exit"), "Exit", menuBar) - menuExit.setShortcut("Ctrl+Q") - menuExit.setStatusTip("Exit %s" % nw.__package__) - menuExit.triggered.connect(self._menuExit) - fileMenu.addAction(menuExit) + menuItem = QAction(QIcon.fromTheme("application-exit"), "Exit", menuBar) + menuItem.setStatusTip("Exit %s" % nw.__package__) + menuItem.setShortcut("Ctrl+Q") + menuItem.triggered.connect(self._menuExit) + fileMenu.addAction(menuItem) ############################################################################################ @@ -329,45 +329,93 @@ class GuiMain(QMainWindow): editMenu = menuBar.addMenu("&Edit") # Edit > Undo - menuUndo = QAction(QIcon.fromTheme("edit-undo"), "Undo", menuBar) - menuUndo.setShortcut("Ctrl+Z") - menuUndo.setStatusTip("Undo Last Change") - editMenu.addAction(menuUndo) + menuItem = QAction(QIcon.fromTheme("edit-undo"), "Undo", menuBar) + menuItem.setStatusTip("Undo Last Change") + menuItem.setShortcut("Ctrl+Z") + menuItem.triggered.connect(lambda: self.docEditor.docAction(nwDocAction.UNDO)) + editMenu.addAction(menuItem) # Edit > Redo - menuRedo = QAction(QIcon.fromTheme("edit-redo"), "Redo", menuBar) - menuRedo.setShortcut("Ctrl+Y") - menuRedo.setStatusTip("Redo Last Change") - editMenu.addAction(menuRedo) + menuItem = QAction(QIcon.fromTheme("edit-redo"), "Redo", menuBar) + menuItem.setStatusTip("Redo Last Change") + menuItem.setShortcut("Ctrl+Y") + menuItem.triggered.connect(lambda: self.docEditor.docAction(nwDocAction.REDO)) + editMenu.addAction(menuItem) # Edit > Separator editMenu.addSeparator() # Edit > Cut - menuCut = QAction(QIcon.fromTheme("edit-cut"), "Cut", menuBar) - menuCut.setShortcut("Ctrl+X") - menuCut.setStatusTip("Cut Selected Text") - editMenu.addAction(menuCut) + menuItem = QAction(QIcon.fromTheme("edit-cut"), "Cut", menuBar) + menuItem.setStatusTip("Cut Selected Text") + menuItem.setShortcut("Ctrl+X") + menuItem.triggered.connect(lambda: self.docEditor.docAction(nwDocAction.CUT)) + editMenu.addAction(menuItem) # Edit > Copy - menuCopy = QAction(QIcon.fromTheme("edit-copy"), "Copy", menuBar) - menuCopy.setShortcut("Ctrl+C") - menuCopy.setStatusTip("Copy Selected Text") - editMenu.addAction(menuCopy) + menuItem = QAction(QIcon.fromTheme("edit-copy"), "Copy", menuBar) + menuItem.setStatusTip("Copy Selected Text") + menuItem.setShortcut("Ctrl+C") + menuItem.triggered.connect(lambda: self.docEditor.docAction(nwDocAction.COPY)) + editMenu.addAction(menuItem) # Edit > Paste - menuPaste = QAction(QIcon.fromTheme("edit-paste"), "Paste", menuBar) - menuPaste.setShortcut("Ctrl+V") - menuPaste.setStatusTip("Paste Text from Clipboard") - editMenu.addAction(menuPaste) + menuItem = QAction(QIcon.fromTheme("edit-paste"), "Paste", menuBar) + menuItem.setStatusTip("Paste Text from Clipboard") + menuItem.setShortcut("Ctrl+V") + menuItem.triggered.connect(lambda: self.docEditor.docAction(nwDocAction.PASTE)) + editMenu.addAction(menuItem) # Edit > Separator editMenu.addSeparator() # Edit > Settings - menuSettings = QAction(QIcon.fromTheme("applications-system"), "Program Setting", menuBar) - menuSettings.setStatusTip("Change %s Settings" % nw.__package__) - editMenu.addAction(menuSettings) + menuItem = QAction(QIcon.fromTheme("applications-system"), "Program Setting", menuBar) + menuItem.setStatusTip("Change %s Settings" % nw.__package__) + editMenu.addAction(menuItem) + + ############################################################################################ + + # Format + fmtMenu = menuBar.addMenu("&Format") + + # Format > Bold Text + menuItem = QAction(QIcon.fromTheme("format-text-bold"), "Bold Text", menuBar) + menuItem.setStatusTip("Make Selected Text Bold") + menuItem.setShortcut("Ctrl+B") + menuItem.triggered.connect(lambda: self.docEditor.docAction(nwDocAction.BOLD)) + fmtMenu.addAction(menuItem) + + # Format > Italic Text + menuItem = QAction(QIcon.fromTheme("format-text-italic"), "Italic Text", menuBar) + menuItem.setStatusTip("Make Selected Text Italic") + menuItem.setShortcut("Ctrl+I") + menuItem.triggered.connect(lambda: self.docEditor.docAction(nwDocAction.ITALIC)) + fmtMenu.addAction(menuItem) + + # Format > Underline Text + menuItem = QAction(QIcon.fromTheme("format-text-underline"), "Underline Text", menuBar) + menuItem.setStatusTip("Underline Selected Text") + menuItem.setShortcut("Ctrl+U") + menuItem.triggered.connect(lambda: self.docEditor.docAction(nwDocAction.U_LINE)) + fmtMenu.addAction(menuItem) + + # Edit > Separator + fmtMenu.addSeparator() + + # Format > Double Quotes + menuItem = QAction(QIcon.fromTheme("insert-text"), "Wrap Double Quotes", menuBar) + menuItem.setStatusTip("Wrap Selected Text in Double Quotes") + menuItem.setShortcut("Ctrl+D") + menuItem.triggered.connect(lambda: self.docEditor.docAction(nwDocAction.D_QUOTE)) + fmtMenu.addAction(menuItem) + + # Format > Single Quotes + menuItem = QAction(QIcon.fromTheme("insert-text"), "Wrap Single Quotes", menuBar) + menuItem.setStatusTip("Wrap Selected Text in Single Quotes") + menuItem.setShortcut("Ctrl+Shift+D") + menuItem.triggered.connect(lambda: self.docEditor.docAction(nwDocAction.S_QUOTE)) + fmtMenu.addAction(menuItem) ############################################################################################ @@ -375,15 +423,15 @@ class GuiMain(QMainWindow): helpMenu = menuBar.addMenu("&Help") # Help > About - menuAbout = QAction(QIcon.fromTheme("help-about"), "About %s" % nw.__package__, menuBar) - menuAbout.setStatusTip("About %s" % nw.__package__) - menuAbout.triggered.connect(self._showAbout) - helpMenu.addAction(menuAbout) + menuItem = QAction(QIcon.fromTheme("help-about"), "About %s" % nw.__package__, menuBar) + menuItem.setStatusTip("About %s" % nw.__package__) + menuItem.triggered.connect(self._showAbout) + helpMenu.addAction(menuItem) # Help > About Qt5 - menuAboutQt5 = QAction(QIcon.fromTheme("help-about"), "About Qt5", menuBar) - menuAboutQt5.setStatusTip("About Qt5") - helpMenu.addAction(menuAboutQt5) + menuItem = QAction(QIcon.fromTheme("help-about"), "About Qt5", menuBar) + menuItem.setStatusTip("About Qt5") + helpMenu.addAction(menuItem) if not self.mainConf.debugGUI: return diff --git a/sample/sampleNovel/data_9/6b68994dfa3d_main.nwd b/sample/sampleNovel/data_9/6b68994dfa3d_main.nwd index 13844f46..b738b4d3 100644 --- a/sample/sampleNovel/data_9/6b68994dfa3d_main.nwd +++ b/sample/sampleNovel/data_9/6b68994dfa3d_main.nwd @@ -6,7 +6,7 @@ #### Header 4 -**Lorem** ipsum dolor sit amet, consectetur "adipiscing" elit. Proin vitae nisi augue. Sed elementum lacus risus, eu lobortis ipsum malesuada rutrum. Nam egestas elit id commodo porta. **Ut eget lacinia ipsum, non interdum mi.** Sed tincidunt commodo metus, at faucibus nisi finibus eget. In malesuada egestas nulla et tempor. _Nulla eu sem_ vel mi sollicitudin cursus. Nullam ultricies ex eu dui scelerisque, ut venenatis turpis ultricies. +**Lorem** ipsum dolor sit amet, consectetur "adipiscing" elit. Proin vitae nisi augue. Sed elementum lacus risus, eu lobortis ipsum malesuada rutrum. Nam egestas elit id commodo porta. **Ut eget lacinia ipsum, non interdum mi.** Sed tincidunt commodo metus, at faucibus nisi finibus eget. In malesuada egestas nulla et tempor. _Nulla eu sem_ vel mi sollicitudin cursus. “Nullam ultricies ex eu dui ‘scelerisque’, ut venenatis turpis ultricies.” Nunc in ex molestie, __efficitur__ diam ~~semper~~, pellentesque eros. Morbi vel lacus quis turpis sagittis iaculis. Sed rhoncus tortor et finibus lobortis. Suspendisse non ultrices odio, at venenatis mi. Sed congue congue tortor, et egestas neque malesuada ac. Nulla facilisi. Maecenas finibus elementum vestibulum. Nam id rhoncus mauris, vel “ullamcorper” «neque». diff --git a/sample/sampleNovel/nwProject.nwx b/sample/sampleNovel/nwProject.nwx index 9175266a..d9b994ab 100644 --- a/sample/sampleNovel/nwProject.nwx +++ b/sample/sampleNovel/nwProject.nwx @@ -1,12 +1,12 @@ - + Sample Project Sample Project Jane Smith Jay Doh - + Novel ROOT @@ -30,7 +30,7 @@ 2 False False - 2573 + 2575 377 5