From 4c775f101acc24c7ee85fc581974af3aebb989a5 Mon Sep 17 00:00:00 2001 From: "Veronica K. B. Olsen" <1619840+vkbo@users.noreply.github.com> Date: Thu, 21 May 2020 18:01:44 +0200 Subject: [PATCH 1/4] Moved syntax highlight options to the Editor tab in Preferences --- nw/gui/dialogs/configeditor.py | 72 ++++++++++++++++++---------------- 1 file changed, 38 insertions(+), 34 deletions(-) diff --git a/nw/gui/dialogs/configeditor.py b/nw/gui/dialogs/configeditor.py index 4108cbcc..77abc231 100644 --- a/nw/gui/dialogs/configeditor.py +++ b/nw/gui/dialogs/configeditor.py @@ -64,7 +64,7 @@ class GuiConfigEditor(PagedDialog): self.addTab(self.tabGeneral, "General") self.addTab(self.tabLayout, "Layout") - self.addTab(self.tabEditing, "Editing") + self.addTab(self.tabEditing, "Editor") self.addTab(self.tabAutoRep, "Auto-Replace") self.buttonBox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) @@ -174,22 +174,6 @@ class GuiConfigEditGeneralTab(QWidget): "Changing this requires restarting %s." % nw.__package__ ) - ## Syntax Highlighting - self.selectSyntax = QComboBox() - self.selectSyntax.setMinimumWidth(200) - self.theSyntaxes = self.theTheme.listSyntax() - for syntaxFile, syntaxName in self.theSyntaxes: - self.selectSyntax.addItem(syntaxName, syntaxFile) - syntaxIdx = self.selectSyntax.findData(self.mainConf.guiSyntax) - if syntaxIdx != -1: - self.selectSyntax.setCurrentIndex(syntaxIdx) - - self.mainForm.addRow( - "Syntax highlight theme", - self.selectSyntax, - "" - ) - ## Dark Icons self.preferDarkIcons = QSwitch() self.preferDarkIcons.setChecked(self.mainConf.guiDark) @@ -210,13 +194,6 @@ class GuiConfigEditGeneralTab(QWidget): self.showFullPath ) - self.highlightQuotes = QSwitch() - self.highlightQuotes.setChecked(self.mainConf.highlightQuotes) - self.mainForm.addRow( - "Add highlighting to text in quotes", - self.highlightQuotes - ) - # AutoSave Settings # ================= self.mainForm.addGroupLabel("Automatic Save") @@ -287,11 +264,9 @@ class GuiConfigEditGeneralTab(QWidget): needsRestart = False guiTheme = self.selectTheme.currentData() - guiSyntax = self.selectSyntax.currentData() guiIcons = self.selectIcons.currentData() guiDark = self.preferDarkIcons.isChecked() showFullPath = self.showFullPath.isChecked() - highlightQuotes = self.highlightQuotes.isChecked() autoSaveDoc = self.autoSaveDoc.value() autoSaveProj = self.autoSaveProj.value() backupPath = self.backupPath @@ -303,11 +278,9 @@ class GuiConfigEditGeneralTab(QWidget): needsRestart |= self.mainConf.guiIcons != guiIcons self.mainConf.guiTheme = guiTheme - self.mainConf.guiSyntax = guiSyntax self.mainConf.guiIcons = guiIcons self.mainConf.guiDark = guiDark self.mainConf.showFullPath = showFullPath - self.mainConf.highlightQuotes = highlightQuotes self.mainConf.autoSaveDoc = autoSaveDoc self.mainConf.autoSaveProj = autoSaveProj self.mainConf.backupPath = backupPath @@ -530,6 +503,33 @@ class GuiConfigEditEditingTab(QWidget): self.mainForm.setHelpTextStyle(self.theTheme.helpText) self.setLayout(self.mainForm) + # Spell Checking + # ============== + self.mainForm.addGroupLabel("Syntax Highlighting") + + ## Syntax Highlighting + self.selectSyntax = QComboBox() + self.selectSyntax.setMinimumWidth(200) + self.theSyntaxes = self.theTheme.listSyntax() + for syntaxFile, syntaxName in self.theSyntaxes: + self.selectSyntax.addItem(syntaxName, syntaxFile) + syntaxIdx = self.selectSyntax.findData(self.mainConf.guiSyntax) + if syntaxIdx != -1: + self.selectSyntax.setCurrentIndex(syntaxIdx) + + self.mainForm.addRow( + "Highlight theme", + self.selectSyntax, + "" + ) + + self.highlightQuotes = QSwitch() + self.highlightQuotes.setChecked(self.mainConf.highlightQuotes) + self.mainForm.addRow( + "Highlight text wrapped in quotes", + self.highlightQuotes + ) + # Spell Checking # ============== self.mainForm.addGroupLabel("Spell Checking") @@ -583,13 +583,17 @@ class GuiConfigEditEditingTab(QWidget): validEntries = True needsRestart = False - spellTool = self.spellToolList.currentData() - spellLanguage = self.spellLangList.currentData() - bigDocLimit = self.bigDocLimit.value() + guiSyntax = self.selectSyntax.currentData() + highlightQuotes = self.highlightQuotes.isChecked() + spellTool = self.spellToolList.currentData() + spellLanguage = self.spellLangList.currentData() + bigDocLimit = self.bigDocLimit.value() - self.mainConf.spellTool = spellTool - self.mainConf.spellLanguage = spellLanguage - self.mainConf.bigDocLimit = bigDocLimit + self.mainConf.guiSyntax = guiSyntax + self.mainConf.highlightQuotes = highlightQuotes + self.mainConf.spellTool = spellTool + self.mainConf.spellLanguage = spellLanguage + self.mainConf.bigDocLimit = bigDocLimit self.mainConf.confChanged = True From a9ff0e8c2ba57c1ada001ab0d803501a1fd8f7cc Mon Sep 17 00:00:00 2001 From: "Veronica K. B. Olsen" <1619840+vkbo@users.noreply.github.com> Date: Thu, 21 May 2020 19:44:35 +0200 Subject: [PATCH 2/4] Fallnack icon should still work if no dark icon is specified --- nw/gui/icons.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/nw/gui/icons.py b/nw/gui/icons.py index fe596fe3..a57f3029 100644 --- a/nw/gui/icons.py +++ b/nw/gui/icons.py @@ -76,6 +76,7 @@ class GuiIcons: "cls_trash" : (QStyle.SP_DriveHDIcon, "drive-harddisk"), "proj_document" : (QStyle.SP_FileIcon, "x-office-document"), "proj_folder" : (QStyle.SP_DirIcon, "folder"), + "proj_nwx" : (None, None), "status_lang" : (None, None), "status_time" : (None, None), "status_stats" : (None, None), @@ -295,8 +296,10 @@ class GuiIcons: # Finally. we check if we have a fallback icon if self.mainConf.guiDark: fbackIcon = path.join(self.mainConf.iconPath, self.fbackName, "%s-dark.svg" % iconKey) - else: - fbackIcon = path.join(self.mainConf.iconPath, self.fbackName, "%s.svg" % iconKey) + if path.isfile(fbackIcon): + logger.verbose("Loading icon '%s' from fallback theme" % iconKey) + return QIcon(fbackIcon) + fbackIcon = path.join(self.mainConf.iconPath, self.fbackName, "%s.svg" % iconKey) if path.isfile(fbackIcon): logger.verbose("Loading icon '%s' from fallback theme" % iconKey) return QIcon(fbackIcon) From 0bbd7de8057445084632d99dcd52bc2571303c7b Mon Sep 17 00:00:00 2001 From: "Veronica K. B. Olsen" <1619840+vkbo@users.noreply.github.com> Date: Thu, 21 May 2020 19:45:00 +0200 Subject: [PATCH 3/4] Redesigned the open project dialog --- nw/assets/icons/fallback/proj_nwx.svg | 252 ++++++++++++++++++++++++++ nw/gui/dialogs/projectload.py | 97 +++++++--- nw/guimain.py | 7 +- 3 files changed, 326 insertions(+), 30 deletions(-) create mode 100644 nw/assets/icons/fallback/proj_nwx.svg diff --git a/nw/assets/icons/fallback/proj_nwx.svg b/nw/assets/icons/fallback/proj_nwx.svg new file mode 100644 index 00000000..6495b39c --- /dev/null +++ b/nw/assets/icons/fallback/proj_nwx.svg @@ -0,0 +1,252 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + diff --git a/nw/gui/dialogs/projectload.py b/nw/gui/dialogs/projectload.py index 1ae20b64..46d48824 100644 --- a/nw/gui/dialogs/projectload.py +++ b/nw/gui/dialogs/projectload.py @@ -33,7 +33,7 @@ from datetime import datetime from PyQt5.QtCore import Qt from PyQt5.QtWidgets import ( QDialog, QHBoxLayout, QVBoxLayout, QGridLayout, QPushButton, QTreeWidget, - QAbstractItemView, QTreeWidgetItem + QAbstractItemView, QTreeWidgetItem, QDialogButtonBox, QLabel ) from nw.common import formatInt @@ -42,25 +42,33 @@ logger = logging.getLogger(__name__) class GuiProjectLoad(QDialog): + NONE_STATE = 0 + BROWSE_STATE = 1 + NEW_STATE = 2 + OPEN_STATE = 3 + def __init__(self, theParent): QDialog.__init__(self, theParent) logger.debug("Initialising GuiProjectLoad ...") - self.mainConf = nw.CONFIG - self.theParent = theParent - self.sourceItem = None - self.openPath = None + self.mainConf = nw.CONFIG + self.theParent = theParent + self.openState = self.NONE_STATE + self.openPath = None + + self.outerBox = QVBoxLayout() + self.innerBox = QHBoxLayout() + self.outerBox.setSpacing(16) + self.innerBox.setSpacing(16) - self.outerBox = QHBoxLayout() - self.innerBox = QVBoxLayout() self.setWindowTitle("Open Project") - self.setLayout(self.outerBox) + self.setMinimumWidth(650) + self.setMinimumHeight(400) + self.setModal(True) - self.guiDeco = self.theParent.theTheme.loadDecoration("nwicon", (128, 128)) - - self.outerBox.addWidget(self.guiDeco, 0, Qt.AlignTop) - self.outerBox.addLayout(self.innerBox) + self.guiDeco = self.theParent.theTheme.loadDecoration("nwicon", (96, 96)) + self.innerBox.addWidget(self.guiDeco, 0, Qt.AlignTop) self.projectForm = QGridLayout() self.projectForm.setContentsMargins(0, 0, 0, 0) @@ -71,34 +79,45 @@ class GuiProjectLoad(QDialog): self.listBox.setColumnCount(4) self.listBox.setHeaderLabels(["Working Title","Words","Last Opened","Path"]) self.listBox.setRootIsDecorated(False) + self.listBox.setColumnHidden(3, True) + self.listBox.itemClicked.connect(self._doSelectRecent) self.listBox.itemDoubleClicked.connect(self._doOpenRecent) treeHead = self.listBox.headerItem() treeHead.setTextAlignment(1, Qt.AlignRight) treeHead.setTextAlignment(2, Qt.AlignRight) - self.recentButton = QPushButton("Open") - self.recentButton.clicked.connect(self._doOpenRecent) - self.browseButton = QPushButton("Browse") - self.browseButton.clicked.connect(self._doBrowse) - self.closeButton = QPushButton("Close") - self.closeButton.clicked.connect(self._doClose) + self.lblRecent = QLabel("Recently Opened:") + self.lblPath = QLabel("Path:") + self.selPath = QLabel("") + self.selPath.setWordWrap(True) - self.projectForm.addWidget(self.listBox, 0, 0, 1, 4) - self.projectForm.addWidget(self.recentButton, 1, 1) - self.projectForm.addWidget(self.browseButton, 1, 2) - self.projectForm.addWidget(self.closeButton, 1, 3) - self.projectForm.setColumnStretch(0, 1) + self.projectForm.addWidget(self.lblRecent, 0, 0, 1, 2) + self.projectForm.addWidget(self.listBox, 1, 0, 1, 2) + self.projectForm.addWidget(self.lblPath, 2, 0, 1, 1, Qt.AlignTop) + self.projectForm.addWidget(self.selPath, 2, 1, 1, 1, Qt.AlignTop) + self.projectForm.setColumnStretch(1, 1) + self.projectForm.setVerticalSpacing(4) + self.projectForm.setHorizontalSpacing(8) self.innerBox.addLayout(self.projectForm) - self.rejected.connect(self._doClose) - self.setModal(True) - self.setMinimumWidth(750) - self.setMinimumHeight(450) - self.show() + self.buttonBox = QDialogButtonBox(QDialogButtonBox.Open | QDialogButtonBox.Cancel) + self.buttonBox.accepted.connect(self._doOpenRecent) + self.buttonBox.rejected.connect(self._doClose) + + self.newButton = self.buttonBox.addButton("New", QDialogButtonBox.ActionRole) + self.newButton.clicked.connect(self._doNewProject) + + self.browseButton = self.buttonBox.addButton("Browse", QDialogButtonBox.ActionRole) + self.browseButton.clicked.connect(self._doBrowse) + + self.outerBox.addLayout(self.innerBox) + self.outerBox.addWidget(self.buttonBox) + self.setLayout(self.outerBox) self._populateList() + self._doSelectRecent() logger.debug("GuiProjectLoad initialisation complete") @@ -116,10 +135,19 @@ class GuiProjectLoad(QDialog): selItems = self.listBox.selectedItems() if selItems: self.openPath = selItems[0].text(3) + self.openState = self.OPEN_STATE self.accept() else: self.openPath = None + self.openState = self.NONE_STATE + return + def _doSelectRecent(self): + """A recent item has been selected. + """ + selList = self.listBox.selectedItems() + if selList: + self.selPath.setText(selList[0].text(3)) return def _doBrowse(self): @@ -129,6 +157,7 @@ class GuiProjectLoad(QDialog): logger.verbose("GuiProjectLoad browse button clicked") self._saveDialogState() self.openPath = None + self.openState = self.BROWSE_STATE self.accept() return @@ -140,6 +169,16 @@ class GuiProjectLoad(QDialog): self.close() return + def _doNewProject(self): + """Create a new project. + """ + logger.verbose("GuiProjectLoad new project button clicked") + self._saveDialogState() + self.openPath = None + self.openState = self.NEW_STATE + self.accept() + return + ## # Internal Functions ## @@ -156,7 +195,6 @@ class GuiProjectLoad(QDialog): def _populateList(self): """Populate the list box with recent project data. """ - listOrder = [] listData = {} for projPath in self.mainConf.recentProj.keys(): @@ -178,6 +216,7 @@ class GuiProjectLoad(QDialog): hasSelection = False for timeStamp in sorted(listOrder, reverse=True): newItem = QTreeWidgetItem([""]*4) + newItem.setIcon(0, self.theParent.theTheme.getIcon("proj_nwx")) newItem.setText(0, listData[timeStamp][0]) newItem.setText(1, formatInt(listData[timeStamp][1])) newItem.setText(2, datetime.fromtimestamp(timeStamp).strftime("%x %X")) diff --git a/nw/guimain.py b/nw/guimain.py index e8c0840a..558712ed 100644 --- a/nw/guimain.py +++ b/nw/guimain.py @@ -262,7 +262,12 @@ class GuiMain(QMainWindow): dlgProj = GuiProjectLoad(self) dlgProj.exec_() if dlgProj.result() == QDialog.Accepted: - self.openProject(dlgProj.openPath) + if dlgProj.openState == GuiProjectLoad.OPEN_STATE: + self.openProject(dlgProj.openPath) + elif dlgProj.openState == GuiProjectLoad.BROWSE_STATE: + self.openProject(dlgProj.openPath) + elif dlgProj.openState == GuiProjectLoad.NEW_STATE: + self.newProject() return True From cc340d721b45d1750dd6e40e868fcf617733dfe6 Mon Sep 17 00:00:00 2001 From: "Veronica K. B. Olsen" <1619840+vkbo@users.noreply.github.com> Date: Thu, 21 May 2020 19:56:31 +0200 Subject: [PATCH 4/4] Session word count should just be a +/- number in brackets --- nw/gui/statusbar.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/nw/gui/statusbar.py b/nw/gui/statusbar.py index 6d104357..0d2643c6 100644 --- a/nw/gui/statusbar.py +++ b/nw/gui/statusbar.py @@ -212,7 +212,7 @@ class GuiMainStatus(QStatusBar): sWC = self.sessWords, )) self.statsText.setText(( - "D:{wC:n} P:{pWC:n} S:{sWC:n}" + "D:{wC:n} P:{pWC:n} ({sWC:+n})" ).format( wC = self.wordCount, pWC = self.projWords, @@ -243,10 +243,10 @@ class StatusLED(QAbstractButton): def __init__(self, colNone, colTrue, colFalse, sW, sH, parent=None): super().__init__(parent=parent) - self.colNone = colNone - self.colTrue = colTrue - self.colFalse = colFalse - self._theCol = colNone + self.colNone = colNone + self.colTrue = colTrue + self.colFalse = colFalse + self._theCol = colNone self.setFixedWidth(sW) self.setFixedHeight(sH)