diff --git a/nw/core/tohtml.py b/nw/core/tohtml.py
index 6123ce21..1fd6f00d 100644
--- a/nw/core/tohtml.py
+++ b/nw/core/tohtml.py
@@ -54,6 +54,8 @@ class ToHtml(Tokenizer):
nwUnicode.U_EMDASH : nwUnicode.H_EMDASH,
nwUnicode.U_HELLIP : nwUnicode.H_HELLIP,
nwUnicode.U_NBSP : nwUnicode.H_NBSP,
+ nwUnicode.U_THNSP : nwUnicode.H_THNSP,
+ nwUnicode.U_THNBSP : nwUnicode.H_THNBSP,
}
self.revDict = {}
self.reReplace = []
diff --git a/nw/gui/doceditor.py b/nw/gui/doceditor.py
index eadce6ff..35ac09d8 100644
--- a/nw/gui/doceditor.py
+++ b/nw/gui/doceditor.py
@@ -48,7 +48,7 @@ from PyQt5.QtWidgets import (
from nw.core import NWDoc
from nw.gui.dochighlight import GuiDocHighlighter
from nw.core import NWSpellSimple, countWords
-from nw.constants import nwUnicode, nwDocAction
+from nw.constants import nwUnicode, nwDocAction, nwDocInsert, nwInsertSymbols
from nw.common import transferCase
logger = logging.getLogger(__name__)
@@ -570,6 +570,21 @@ class GuiDocEditor(QTextEdit):
))
return
+ def insertText(self, theInsert):
+ """Insert a specific type of text at the cursor position.
+ """
+ if isinstance(theInsert, str):
+ theText = theInsert
+ elif theInsert in nwInsertSymbols.SYMBOLS:
+ theText = nwInsertSymbols.SYMBOLS[theInsert]
+ else:
+ return False
+ theCursor = self.textCursor()
+ theCursor.beginEditBlock()
+ theCursor.insertText(theText)
+ theCursor.endEditBlock()
+ return True
+
def closeSearch(self):
"""Close the search box.
"""
@@ -598,18 +613,7 @@ class GuiDocEditor(QTextEdit):
# seems to be capturing the return key.
return
- if keyEvent.modifiers() == Qt.ShiftModifier:
- theKey = keyEvent.key()
- if theKey == Qt.Key_Return:
- self._insertHardBreak()
- elif theKey == Qt.Key_Enter:
- self._insertHardBreak()
- elif theKey == Qt.Key_Space:
- self._insertNonBreakingSpace()
- else:
- QTextEdit.keyPressEvent(self, keyEvent)
- else:
- QTextEdit.keyPressEvent(self, keyEvent)
+ QTextEdit.keyPressEvent(self, keyEvent)
return
@@ -797,24 +801,6 @@ class GuiDocEditor(QTextEdit):
return True
- def _insertHardBreak(self):
- """Inserts a hard line break at the cursor position.
- """
- theCursor = self.textCursor()
- theCursor.beginEditBlock()
- theCursor.insertText(" \n")
- theCursor.endEditBlock()
- return
-
- def _insertNonBreakingSpace(self):
- """Inserts a non-breaking space at the cursor position.
- """
- theCursor = self.textCursor()
- theCursor.beginEditBlock()
- theCursor.insertText(nwUnicode.U_NBSP)
- theCursor.endEditBlock()
- return
-
def _openSpellContext(self):
"""Opens the spell check context menu at the current point of
the cursor.
diff --git a/nw/gui/dochighlight.py b/nw/gui/dochighlight.py
index a76c9646..4acc0e7a 100644
--- a/nw/gui/dochighlight.py
+++ b/nw/gui/dochighlight.py
@@ -132,7 +132,7 @@ class GuiDocHighlighter(QSyntaxHighlighter):
# Non-Breaking Spaces
self.hRules.append((
- "[%s]+" % nwUnicode.U_NBSP, {
+ "[%s%s]+" % (nwUnicode.U_NBSP, nwUnicode.U_THNBSP), {
0 : self.hStyles["nobreak"],
}
))
diff --git a/nw/gui/mainmenu.py b/nw/gui/mainmenu.py
index 720eefae..7f7c9164 100644
--- a/nw/gui/mainmenu.py
+++ b/nw/gui/mainmenu.py
@@ -28,12 +28,12 @@
import logging
import nw
-from PyQt5.QtCore import QUrl
+from PyQt5.QtCore import Qt, QUrl
from PyQt5.QtGui import QDesktopServices
from PyQt5.QtWidgets import QMenuBar, QAction, QMessageBox
from nw.gui.about import GuiAbout
-from nw.constants import nwItemType, nwItemClass, nwDocAction
+from nw.constants import nwItemType, nwItemClass, nwDocAction, nwDocInsert
logger = logging.getLogger(__name__)
@@ -50,8 +50,9 @@ class GuiMainMenu(QMenuBar):
self._buildProjectMenu()
self._buildDocumentMenu()
self._buildEditMenu()
- self._buildViewMenu()
+ self._buildInsertMenu()
self._buildFormatMenu()
+ self._buildViewMenu()
self._buildToolsMenu()
self._buildHelpMenu()
@@ -59,6 +60,7 @@ class GuiMainMenu(QMenuBar):
self._docAction = self.theParent.passDocumentAction
self._moveTreeItem = self.theParent.treeView.moveTreeItem
self._newTreeItem = self.theParent.treeView.newTreeItem
+ self._docInsert = self.theParent.docEditor.insertText
logger.debug("GuiMainMenu initialisation complete")
@@ -341,53 +343,6 @@ class GuiMainMenu(QMenuBar):
return
- def _buildViewMenu(self):
-
- # View
- self.viewMenu = self.addMenu("&View")
-
- # View > TreeView
- self.aFocusTree = QAction("Focus Project Tree", self)
- self.aFocusTree.setStatusTip("Move focus to project tree")
- self.aFocusTree.setShortcut("Alt+1")
- self.aFocusTree.triggered.connect(lambda : self.theParent.setFocus(1))
- self.viewMenu.addAction(self.aFocusTree)
-
- # View > Document Pane 1
- self.aFocusEditor = QAction("Focus Document Editor", self)
- self.aFocusEditor.setStatusTip("Move focus to left document pane")
- self.aFocusEditor.setShortcut("Alt+2")
- self.aFocusEditor.triggered.connect(lambda : self.theParent.setFocus(2))
- self.viewMenu.addAction(self.aFocusEditor)
-
- # View > Document Pane 2
- self.aFocusView = QAction("Focus Document Viewer", self)
- self.aFocusView.setStatusTip("Move focus to right document pane")
- self.aFocusView.setShortcut("Alt+3")
- self.aFocusView.triggered.connect(lambda : self.theParent.setFocus(3))
- self.viewMenu.addAction(self.aFocusView)
-
- # View > Separator
- self.viewMenu.addSeparator()
-
- # View > Toggle Distraction Free Mode
- self.aZenMode = QAction("Zen Mode", self)
- self.aZenMode.setStatusTip("Toggles distraction free mode, only showing text editor")
- self.aZenMode.setShortcut("F8")
- self.aZenMode.setCheckable(True)
- self.aZenMode.setChecked(self.theParent.isZenMode)
- self.aZenMode.toggled.connect(self.theParent.toggleZenMode)
- self.viewMenu.addAction(self.aZenMode)
-
- # View > Toggle Full Screen
- self.aFullScreen = QAction("Full Screen Mode", self)
- self.aFullScreen.setStatusTip("Maximises the main window")
- self.aFullScreen.setShortcut("F11")
- self.aFullScreen.triggered.connect(self.theParent.toggleFullScreenMode)
- self.viewMenu.addAction(self.aFullScreen)
-
- return
-
def _buildEditMenu(self):
# Edit
@@ -497,6 +452,65 @@ class GuiMainMenu(QMenuBar):
return
+ def _buildInsertMenu(self):
+
+ # Insert
+ self.insertMenu = self.addMenu("&Insert")
+
+ # Insert > Short Dash
+ self.aInsENDash = QAction("Short Dash", self)
+ self.aInsENDash.setStatusTip("Insert short dash")
+ self.aInsENDash.setShortcut("Ctrl+K, -")
+ self.aInsENDash.triggered.connect(lambda: self._docInsert(nwDocInsert.SHORT_DASH))
+ self.insertMenu.addAction(self.aInsENDash)
+
+ # Insert > Long Dash
+ self.aInsEMDash = QAction("Long Dash", self)
+ self.aInsEMDash.setStatusTip("Insert long dash")
+ self.aInsEMDash.setShortcut("Ctrl+K, _")
+ self.aInsEMDash.triggered.connect(lambda: self._docInsert(nwDocInsert.LONG_DASH))
+ self.insertMenu.addAction(self.aInsEMDash)
+
+ # Insert > Ellipsis
+ self.aInsEllipsis = QAction("Ellipsis", self)
+ self.aInsEllipsis.setStatusTip("Insert ellipsis")
+ self.aInsEllipsis.setShortcut("Ctrl+K, .")
+ self.aInsEllipsis.triggered.connect(lambda: self._docInsert(nwDocInsert.ELLIPSIS))
+ self.insertMenu.addAction(self.aInsEllipsis)
+
+ # Insert > Separator
+ self.insertMenu.addSeparator()
+
+ # Insert > Hard Line Break
+ self.aInsHardBreak = QAction("Hard Line Break", self)
+ self.aInsHardBreak.setStatusTip("Insert a hard line break")
+ self.aInsHardBreak.setShortcut("Ctrl+K, Return")
+ self.aInsHardBreak.triggered.connect(lambda: self._docInsert(nwDocInsert.HARD_BREAK))
+ self.insertMenu.addAction(self.aInsHardBreak)
+
+ # Insert > Non-Breaking Space
+ self.aInsNBSpace = QAction("Non-Breaking Space", self)
+ self.aInsNBSpace.setStatusTip("Insert a non-breaking space")
+ self.aInsNBSpace.setShortcut("Ctrl+K, Space")
+ self.aInsNBSpace.triggered.connect(lambda: self._docInsert(nwDocInsert.NB_SPACE))
+ self.insertMenu.addAction(self.aInsNBSpace)
+
+ # Insert > Thin Space
+ self.aInsThinSpace = QAction("Thin Space", self)
+ self.aInsThinSpace.setStatusTip("Insert a thin space")
+ self.aInsThinSpace.setShortcut("Ctrl+K, Shift+Space")
+ self.aInsThinSpace.triggered.connect(lambda: self._docInsert(nwDocInsert.THIN_SPACE))
+ self.insertMenu.addAction(self.aInsThinSpace)
+
+ # Insert > Thin Non-Breaking Space
+ self.aInsThinNBSpace = QAction("Thin Non-Breaking Space", self)
+ self.aInsThinNBSpace.setStatusTip("Insert a thin non-breaking space")
+ self.aInsThinNBSpace.setShortcut("Ctrl+K, Ctrl+Space")
+ self.aInsThinNBSpace.triggered.connect(lambda: self._docInsert(nwDocInsert.THIN_NB_SPACE))
+ self.insertMenu.addAction(self.aInsThinNBSpace)
+
+ return
+
def _buildFormatMenu(self):
# Format
@@ -594,6 +608,53 @@ class GuiMainMenu(QMenuBar):
return
+ def _buildViewMenu(self):
+
+ # View
+ self.viewMenu = self.addMenu("&View")
+
+ # View > TreeView
+ self.aFocusTree = QAction("Focus Project Tree", self)
+ self.aFocusTree.setStatusTip("Move focus to project tree")
+ self.aFocusTree.setShortcut("Alt+1")
+ self.aFocusTree.triggered.connect(lambda : self.theParent.setFocus(1))
+ self.viewMenu.addAction(self.aFocusTree)
+
+ # View > Document Pane 1
+ self.aFocusEditor = QAction("Focus Document Editor", self)
+ self.aFocusEditor.setStatusTip("Move focus to left document pane")
+ self.aFocusEditor.setShortcut("Alt+2")
+ self.aFocusEditor.triggered.connect(lambda : self.theParent.setFocus(2))
+ self.viewMenu.addAction(self.aFocusEditor)
+
+ # View > Document Pane 2
+ self.aFocusView = QAction("Focus Document Viewer", self)
+ self.aFocusView.setStatusTip("Move focus to right document pane")
+ self.aFocusView.setShortcut("Alt+3")
+ self.aFocusView.triggered.connect(lambda : self.theParent.setFocus(3))
+ self.viewMenu.addAction(self.aFocusView)
+
+ # View > Separator
+ self.viewMenu.addSeparator()
+
+ # View > Toggle Distraction Free Mode
+ self.aZenMode = QAction("Zen Mode", self)
+ self.aZenMode.setStatusTip("Toggles distraction free mode, only showing text editor")
+ self.aZenMode.setShortcut("F8")
+ self.aZenMode.setCheckable(True)
+ self.aZenMode.setChecked(self.theParent.isZenMode)
+ self.aZenMode.toggled.connect(self.theParent.toggleZenMode)
+ self.viewMenu.addAction(self.aZenMode)
+
+ # View > Toggle Full Screen
+ self.aFullScreen = QAction("Full Screen Mode", self)
+ self.aFullScreen.setStatusTip("Maximises the main window")
+ self.aFullScreen.setShortcut("F11")
+ self.aFullScreen.triggered.connect(self.theParent.toggleFullScreenMode)
+ self.viewMenu.addAction(self.aFullScreen)
+
+ return
+
def _buildToolsMenu(self):
# Tools
diff --git a/nw/guimain.py b/nw/guimain.py
index 70a6ba0b..a82d5a99 100644
--- a/nw/guimain.py
+++ b/nw/guimain.py
@@ -966,12 +966,15 @@ class GuiMain(QMainWindow):
"""Connect to the main window all menu actions that need to be
available also when the main menu is hidden.
"""
+ # Project
self.addAction(self.mainMenu.aSaveProject)
self.addAction(self.mainMenu.aExitNW)
+
+ # Document
self.addAction(self.mainMenu.aSaveDoc)
self.addAction(self.mainMenu.aFileDetails)
- self.addAction(self.mainMenu.aZenMode)
- self.addAction(self.mainMenu.aFullScreen)
+
+ # Edit
self.addAction(self.mainMenu.aEditUndo)
self.addAction(self.mainMenu.aEditRedo)
self.addAction(self.mainMenu.aEditCut)
@@ -979,6 +982,17 @@ class GuiMain(QMainWindow):
self.addAction(self.mainMenu.aEditPaste)
self.addAction(self.mainMenu.aSelectAll)
self.addAction(self.mainMenu.aSelectPar)
+
+ # Insert
+ self.addAction(self.mainMenu.aInsENDash)
+ self.addAction(self.mainMenu.aInsEMDash)
+ self.addAction(self.mainMenu.aInsEllipsis)
+ self.addAction(self.mainMenu.aInsHardBreak)
+ self.addAction(self.mainMenu.aInsNBSpace)
+ self.addAction(self.mainMenu.aInsThinSpace)
+ self.addAction(self.mainMenu.aInsThinNBSpace)
+
+ # Format
self.addAction(self.mainMenu.aFmtItalic)
self.addAction(self.mainMenu.aFmtBold)
self.addAction(self.mainMenu.aFmtBoldIt)
@@ -990,10 +1004,19 @@ class GuiMain(QMainWindow):
self.addAction(self.mainMenu.aFmtHead4)
self.addAction(self.mainMenu.aFmtComment)
self.addAction(self.mainMenu.aFmtNoFormat)
+
+ # View
+ self.addAction(self.mainMenu.aZenMode)
+ self.addAction(self.mainMenu.aFullScreen)
+
+ # Tools
self.addAction(self.mainMenu.aSpellCheck)
self.addAction(self.mainMenu.aReRunSpell)
self.addAction(self.mainMenu.aPreferences)
+
+ # Help
self.addAction(self.mainMenu.aHelp)
+
return True
def _setWindowTitle(self, projName=None):