Merge pull request #565 from vkbo/gui_tweaks

GUI Tweaks
This commit is contained in:
Veronica K. Berglyd Olsen
2021-01-18 19:05:55 +01:00
committed by GitHub
8 changed files with 111 additions and 81 deletions
+23 -21
View File
@@ -35,16 +35,16 @@ from PyQt5.QtWidgets import QApplication, QErrorMessage
from nw.error import exceptionHandler
from nw.config import Config
#
##
# Version Scheme
# ================
# Generally follows PEP 440
# Hex Version:
# - Digit 1,2 : Major Version (01, 02, 03)
# = Digit 3,4 : Minor Version (01, 09, 10, 99)
# - Digit 5,6 : Patch Version (01, 09, 10, 99)
# - Digit 1,2 : Major Version (01-ff)
# = Digit 3,4 : Minor Version (01-ff)
# - Digit 5,6 : Patch Version (01-ff)
# = Digit 7 : Release Type (a: aplha, b: beta, c: candidate, f: final)
# - Digit 8 : Release Number (0-9)
# - Digit 8 : Release Number (0-f)
#
# Example : Full Short Description
# -------------------------------------------------------------------------
@@ -55,7 +55,7 @@ from nw.config import Config
# 0x010200f0 : 1.2 1.2 Final release
# 0x010200f1 : 1.2-post1 1.2.post1 Post release, but not a code patch!
# 0x010201f0 : 1.2.1 1.2.1 Patch release
#
##
__package__ = "nw"
__copyright__ = "Copyright 20182021, Veronica Berglyd Olsen"
@@ -79,7 +79,7 @@ __credits__ = [
"Marian Lückhof (contributor, tester)"
]
#
##
# Logging
# =========
# Standard used for logging levels in novelWriter:
@@ -90,7 +90,7 @@ __credits__ = [
# ----------- SPAM Threshold : Output above should be minimal -----------------
# DEBUG Use for descriptions of main program flow
# VERBOSE Use for outputting values and program flow details
#
##
# Add verbose logging level
VERBOSE = 5
@@ -104,10 +104,9 @@ logging.Logger.verbose = logVerbose
# Initiating logging
logger = logging.getLogger(__name__)
#
##
# Main Program
# ==============
#
##
# Load the main config as a global object
CONFIG = Config()
@@ -142,15 +141,14 @@ def main(sysArgs=None):
"GNU General Public License for more details.\n"
"\n"
"Usage:\n"
" -h, --help Print this message.\n"
" -v, --version Print program version and exit.\n"
" --info Print additional runtime information.\n"
" --debug Print debug output. Includes --info.\n"
" --verbose Increase verbosity of debug output. Includes --debug.\n"
" --style= Sets Qt5 style flag. Defaults to 'Fusion'.\n"
" --config= Alternative config file.\n"
" --data= Alternative user data path.\n"
" --testmode Do not display GUI. Used by the test suite.\n"
" -h, --help Print this message.\n"
" -v, --version Print program version and exit.\n"
" --info Print additional runtime information.\n"
" --debug Print debug output. Includes --info.\n"
" --verbose Increase verbosity of debug output. Includes --debug.\n"
" --style= Sets Qt5 style flag. Defaults to 'Fusion'.\n"
" --config= Alternative config file.\n"
" --data= Alternative user data path.\n"
).format(
version = __version__,
status = __status__,
@@ -205,7 +203,6 @@ def main(sysArgs=None):
testMode = True
# Set Config Options
CONFIG.showGUI = not testMode
CONFIG.debugInfo = debugLevel < logging.INFO
CONFIG.cmdOpen = cmdOpen
@@ -292,7 +289,12 @@ def main(sysArgs=None):
# Connect the exception handler before making the main GUI
sys.excepthook = exceptionHandler
# Launch main GUI
nwGUI = GuiMain()
if not nwGUI.hasProject:
nwGUI.showProjectLoadDialog()
nwGUI.releaseNotes()
sys.exit(nwApp.exec_())
# END Function main
-1
View File
@@ -56,7 +56,6 @@ class Config:
self.appHandle = self.appName.lower()
# Debug Settings
self.showGUI = True # Allow blocking the GUI (disabled for testing)
self.debugInfo = False # True if log level is DEBUG or VERBOSE
# Config Error Handling
+9 -2
View File
@@ -457,8 +457,13 @@ class NWTree():
return
def _makeHandle(self, addSeed=""):
"""Generate a unique item handle. In the unlikely event that the
key already exists, salt the seed and generate a new handle.
"""Generate a unique item handle. In the event that the key
already exists, salt the seed and generate a new handle.
A key collision is very unlikely to be caused by the truncation
of the sha256 hash to 13 characters. Assuming it is near-random,
it will on average happen every 4.5^15 times. However, the clock
seed is likely to occasionally generate a collision if the
handle requests come faster than the clock resolution.
"""
if self._handleSeed is None:
newSeed = str(time()) + addSeed
@@ -466,11 +471,13 @@ class NWTree():
# This is used for debugging
newSeed = str(self._handleSeed)
self._handleSeed += 1
logger.verbose("Generating handle with seed '%s'" % newSeed)
itemHandle = sha256(newSeed.encode()).hexdigest()[0:13]
if itemHandle in self._projTree:
logger.warning("Duplicate handle encountered! Retrying ...")
itemHandle = self._makeHandle(addSeed+"!")
return itemHandle
# END Class NWTree
+1 -1
View File
@@ -390,7 +390,7 @@ class GuiDocHighlighter(QSyntaxHighlighter):
theFormat.setBackground(QBrush(fmtCol, Qt.SolidPattern))
if fmtSize is not None:
theFormat.setFontPointSize(round(fmtSize*self.mainConf.textSize))
theFormat.setFontPointSize(int(round(fmtSize*self.mainConf.textSize)))
return theFormat
+36 -24
View File
@@ -49,24 +49,22 @@ class GuiItemDetails(QWidget):
self.theTheme = theParent.theTheme
self.theHandle = None
self.mainBox = QGridLayout(self)
self.mainBox.setVerticalSpacing(1)
self.mainBox.setHorizontalSpacing(6)
self.setLayout(self.mainBox)
# Sizes
hSp = self.mainConf.pxInt(6)
vSp = self.mainConf.pxInt(1)
mPx = self.mainConf.pxInt(6)
iPx = self.theTheme.baseIconSize
fPt = self.theTheme.fontPointSize
self.pS = 0.9*self.theTheme.fontPointSize
self.iPx = self.theTheme.baseIconSize
self.sPx = int(round(0.8*self.theTheme.baseIconSize))
self.expCheck = self.theTheme.getPixmap("check", (self.iPx, self.iPx))
self.expCross = self.theTheme.getPixmap("cross", (self.iPx, self.iPx))
self.expCheck = self.theTheme.getPixmap("check", (iPx, iPx))
self.expCross = self.theTheme.getPixmap("cross", (iPx, iPx))
self.fntLabel = QFont()
self.fntLabel.setBold(True)
self.fntLabel.setPointSizeF(self.pS)
self.fntLabel.setPointSizeF(0.9*fPt)
self.fntValue = QFont()
self.fntValue.setPointSizeF(self.pS)
self.fntValue.setPointSizeF(0.9*fPt)
# Label
self.labelName = QLabel("Label")
@@ -147,6 +145,7 @@ class GuiItemDetails(QWidget):
self.pCountData.setAlignment(Qt.AlignRight)
# Assemble
self.mainBox = QGridLayout(self)
self.mainBox.addWidget(self.labelName, 0, 0, 1, 1)
self.mainBox.addWidget(self.labelFlag, 0, 1, 1, 1)
self.mainBox.addWidget(self.labelData, 0, 2, 1, 3)
@@ -175,6 +174,12 @@ class GuiItemDetails(QWidget):
self.mainBox.setColumnStretch(3, 0)
self.mainBox.setColumnStretch(4, 0)
self.mainBox.setHorizontalSpacing(hSp)
self.mainBox.setVerticalSpacing(vSp)
self.mainBox.setContentsMargins(mPx, mPx, mPx, mPx)
self.setLayout(self.mainBox)
# Make sure the columns for flags and counts don't resize too often
flagWidth = self.theTheme.getTextWidth("Mm", self.fntValue)
countWidth = self.theTheme.getTextWidth("99,999", self.fntValue)
@@ -193,26 +198,30 @@ class GuiItemDetails(QWidget):
"""Clear all the data values.
"""
self.labelFlag.setPixmap(QPixmap(1, 1))
self.labelData.setText("")
self.statusFlag.setPixmap(QPixmap(1, 1))
self.statusData.setText("")
self.classFlag.setText("")
self.classData.setText("")
self.layoutFlag.setText("")
self.layoutData.setText("")
self.labelData.setText("")
self.statusData.setText("")
self.classData.setText("")
self.layoutData.setText("")
self.cCountData.setText("")
self.wCountData.setText("")
self.pCountData.setText("")
return
def updateCounts(self, tHandle, cC, wC, pC):
"""Just update the counts if the handle is the same as the one
we're already showing.
"""Update the counts if the handle is the same as the one we're
already showing. Otherwise, do nothing.
"""
if tHandle == self.theHandle:
self.cCountData.setText(f"{cC:n}")
self.wCountData.setText(f"{wC:n}")
self.pCountData.setText(f"{pC:n}")
return
def updateViewBox(self, tHandle):
@@ -229,13 +238,13 @@ class GuiItemDetails(QWidget):
if len(theLabel) > 100:
theLabel = theLabel[:96].rstrip()+" ..."
iStatus = nwItem.itemStatus
itStatus = nwItem.itemStatus
if nwItem.itemClass == nwItemClass.NOVEL:
iStatus = self.theProject.statusItems.checkEntry(iStatus) # Make sure it's valid
flagIcon = self.theParent.statusIcons[iStatus]
itStatus = self.theProject.statusItems.checkEntry(itStatus) # Make sure it's valid
flagIcon = self.theParent.statusIcons[itStatus]
else:
iStatus = self.theProject.importItems.checkEntry(iStatus) # Make sure it's valid
flagIcon = self.theParent.importIcons[iStatus]
itStatus = self.theProject.importItems.checkEntry(itStatus) # Make sure it's valid
flagIcon = self.theParent.importIcons[itStatus]
if nwItem.itemType == nwItemType.FILE:
if nwItem.isExported:
@@ -244,8 +253,11 @@ class GuiItemDetails(QWidget):
self.labelFlag.setPixmap(self.expCross)
else:
self.labelFlag.setPixmap(QPixmap(1, 1))
self.statusFlag.setPixmap(flagIcon.pixmap(self.sPx, self.sPx))
iPx = int(round(0.8*self.theTheme.baseIconSize))
self.statusFlag.setPixmap(flagIcon.pixmap(iPx, iPx))
self.classFlag.setText(nwLabels.CLASS_FLAG[nwItem.itemClass])
if nwItem.itemLayout == nwItemLayout.NO_LAYOUT:
self.layoutFlag.setText("-")
else:
+8 -6
View File
@@ -57,7 +57,7 @@ class GuiProjectDetails(PagedDialog):
self.setWindowTitle("Project Details")
wW = self.mainConf.pxInt(600)
wH = self.mainConf.pxInt(425)
wH = self.mainConf.pxInt(400)
self.setMinimumWidth(wW)
self.setMinimumHeight(wH)
@@ -137,6 +137,7 @@ class GuiProjectDetailsMain(QWidget):
self.theIndex = theParent.theIndex
fPx = self.theTheme.fontPixelSize
fPt = self.theTheme.fontPointSize
vPx = self.mainConf.pxInt(4)
hPx = self.mainConf.pxInt(12)
@@ -145,7 +146,7 @@ class GuiProjectDetailsMain(QWidget):
self.bookTitle = QLabel(self.theProject.bookTitle)
bookFont = self.bookTitle.font()
bookFont.setPixelSize(round(2.2*fPx))
bookFont.setPointSizeF(2.2*fPt)
bookFont.setWeight(QFont.Bold)
self.bookTitle.setFont(bookFont)
self.bookTitle.setAlignment(Qt.AlignHCenter)
@@ -153,7 +154,7 @@ class GuiProjectDetailsMain(QWidget):
self.projName = QLabel("Working Title: %s" % self.theProject.projName)
workFont = self.projName.font()
workFont.setPixelSize(round(0.8*fPx))
workFont.setPointSizeF(0.8*fPt)
workFont.setItalic(True)
self.projName.setFont(workFont)
self.projName.setAlignment(Qt.AlignHCenter)
@@ -161,7 +162,7 @@ class GuiProjectDetailsMain(QWidget):
self.bookAuthors = QLabel("By %s" % self.theProject.getAuthors())
authFont = self.bookAuthors.font()
authFont.setPixelSize(round(1.2*fPx))
authFont.setPointSizeF(1.2*fPt)
self.bookAuthors.setFont(authFont)
self.bookAuthors.setAlignment(Qt.AlignHCenter)
self.bookAuthors.setWordWrap(True)
@@ -219,12 +220,13 @@ class GuiProjectDetailsMain(QWidget):
# ========
self.outerBox = QVBoxLayout()
self.outerBox.addSpacing(fPx)
self.outerBox.addWidget(self.bookTitle)
self.outerBox.addWidget(self.projName)
self.outerBox.addWidget(self.bookAuthors)
self.outerBox.addSpacing(round(2.5*fPx))
self.outerBox.addSpacing(2*fPx)
self.outerBox.addLayout(self.statsGrid)
self.outerBox.addSpacing(round(0.8*fPx))
self.outerBox.addSpacing(fPx)
self.outerBox.addStretch(1)
self.outerBox.addLayout(self.projPathBox)
+31 -26
View File
@@ -95,6 +95,11 @@ class GuiMain(QMainWindow):
# Build the GUI
# =============
# Sizes
mPx = self.mainConf.pxInt(4)
fPx = self.theTheme.fontPixelSize
fPt = self.theTheme.fontPointSize
# Main GUI Elements
self.statusBar = GuiMainStatus(self)
self.treeView = GuiProjectTree(self)
@@ -107,24 +112,24 @@ class GuiMain(QMainWindow):
self.projMeta = GuiOutlineDetails(self)
self.mainMenu = GuiMainMenu(self)
# Minor Gui Elements
# Minor GUI Elements
self.statusIcons = []
self.importIcons = []
# Project Tree Tabs
self.projTabs = QTabWidget()
self.projTabs.setTabPosition(QTabWidget.South)
self.projTabs.setStyleSheet("QTabWidget::pane {border: 0;};")
self.projTabs.setStyleSheet(r"QTabWidget::pane {border: 0;};")
self.projTabs.addTab(self.treeView, "Project")
self.projTabs.addTab(self.novelView, "Novel")
self.projTabs.currentChanged.connect(self._projTabsChanged)
tabFont = self.projTabs.tabBar().font()
tabFont.setPointSize(round(0.9*self.theTheme.fontPointSize))
tabFont.setPointSizeF(0.9*fPt)
self.projTabs.tabBar().setFont(tabFont)
# Project Tree Action Buttons
btnSize = round(0.7*self.theTheme.fontPixelSize)
btnSize = int(round(0.7*fPx))
self.treeButtons = QToolBar()
self.treeButtons.setToolButtonStyle(Qt.ToolButtonIconOnly)
self.treeButtons.setIconSize(QSize(btnSize, btnSize))
@@ -151,7 +156,7 @@ class GuiMain(QMainWindow):
self.treePane = QWidget()
self.treeBox = QVBoxLayout()
self.treeBox.setContentsMargins(0, 0, 0, 0)
self.treeBox.setSpacing(0)
self.treeBox.setSpacing(mPx)
self.treeBox.addWidget(self.projTabs)
self.treeBox.addWidget(self.treeMeta)
self.treePane.setLayout(self.treeBox)
@@ -176,26 +181,27 @@ class GuiMain(QMainWindow):
# Main Tabs : Editor / Outline
self.mainTabs = QTabWidget()
self.mainTabs.setTabPosition(QTabWidget.East)
self.mainTabs.setStyleSheet("QTabWidget::pane {border: 0;}")
self.mainTabs.setStyleSheet(r"QTabWidget::pane {border: 0;}")
self.mainTabs.addTab(self.splitDocs, "Editor")
self.mainTabs.addTab(self.splitOutline, "Outline")
self.mainTabs.currentChanged.connect(self._mainTabChanged)
# Splitter : Project Tree / Main Tabs
xCM = self.mainConf.pxInt(4)
self.splitMain = QSplitter(Qt.Horizontal)
self.splitMain.setContentsMargins(xCM, xCM, xCM, xCM)
self.splitMain.setContentsMargins(mPx, mPx, mPx, mPx)
self.splitMain.addWidget(self.treePane)
self.splitMain.addWidget(self.mainTabs)
self.splitMain.setSizes(self.mainConf.getMainPanePos())
# Indices of All Splitter Widgets
self.idxTree = self.splitMain.indexOf(self.treePane)
self.idxMain = self.splitMain.indexOf(self.mainTabs)
self.idxEditor = self.splitDocs.indexOf(self.docEditor)
self.idxViewer = self.splitDocs.indexOf(self.splitView)
self.idxViewDoc = self.splitView.indexOf(self.docViewer)
self.idxViewMeta = self.splitView.indexOf(self.viewMeta)
# Indices of Splitter Widgets
self.idxTree = self.splitMain.indexOf(self.treePane)
self.idxMain = self.splitMain.indexOf(self.mainTabs)
self.idxEditor = self.splitDocs.indexOf(self.docEditor)
self.idxViewer = self.splitDocs.indexOf(self.splitView)
self.idxViewDoc = self.splitView.indexOf(self.docViewer)
self.idxViewMeta = self.splitView.indexOf(self.viewMeta)
# Indices of Tab Widgets
self.idxTabEdit = self.mainTabs.indexOf(self.splitDocs)
self.idxTabProj = self.mainTabs.indexOf(self.splitOutline)
self.idxTreeView = self.projTabs.indexOf(self.treeView)
@@ -269,20 +275,10 @@ class GuiMain(QMainWindow):
logger.debug("GUI initialisation complete")
# Check if a project path was provided at command line, and if
# not, open the project manager instead.
# If a project path was provided at command line, open it
if self.mainConf.cmdOpen is not None:
logger.debug("Opening project from additional command line option")
self.openProject(self.mainConf.cmdOpen)
else:
if self.mainConf.showGUI:
self.showProjectLoadDialog()
# Show the latest release notes, if they haven't been shown before
if hexToInt(self.mainConf.lastNotes) < hexToInt(nw.__hexversion__):
if self.mainConf.showGUI:
self.showAboutNWDialog(showNotes=True)
self.mainConf.lastNotes = nw.__hexversion__
logger.debug("novelWriter is ready ...")
self.setStatus("novelWriter is ready ...")
@@ -316,6 +312,15 @@ class GuiMain(QMainWindow):
self.asDocTimer.setInterval(int(self.mainConf.autoSaveDoc*1000))
return True
def releaseNotes(self):
"""Determine whether release notes need to be shown, and show
them by calling the About dialog.
"""
if hexToInt(self.mainConf.lastNotes) < hexToInt(nw.__hexversion__):
self.mainConf.lastNotes = nw.__hexversion__
self.showAboutNWDialog(showNotes=True)
return
##
# Project Actions
##
+3
View File
@@ -21,6 +21,9 @@ class DummyMain():
return
def releaseNotes(self):
return
def makeAlert(self, theMessage, theLevel):
print("%s: %s" % (str(theLevel), theMessage))
self.lastAlert = str(theMessage)