novelWriter 2.4b1__py3-none-any.whl → 2.4rc1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {novelWriter-2.4b1.dist-info → novelWriter-2.4rc1.dist-info}/METADATA +5 -6
- {novelWriter-2.4b1.dist-info → novelWriter-2.4rc1.dist-info}/RECORD +62 -66
- novelwriter/__init__.py +5 -5
- novelwriter/assets/icons/none.svg +4 -0
- novelwriter/assets/icons/typicons_dark/icons.conf +2 -2
- novelwriter/assets/icons/typicons_dark/typ_unfold-hidden.svg +4 -0
- novelwriter/assets/icons/typicons_dark/typ_unfold-visible.svg +4 -0
- novelwriter/assets/icons/typicons_light/icons.conf +2 -2
- novelwriter/assets/icons/typicons_light/typ_unfold-hidden.svg +4 -0
- novelwriter/assets/icons/typicons_light/typ_unfold-visible.svg +4 -0
- novelwriter/assets/manual.pdf +0 -0
- novelwriter/assets/sample.zip +0 -0
- novelwriter/common.py +6 -1
- novelwriter/config.py +8 -4
- novelwriter/core/coretools.py +21 -22
- novelwriter/core/status.py +3 -2
- novelwriter/core/toodt.py +332 -355
- novelwriter/dialogs/about.py +9 -11
- novelwriter/dialogs/docmerge.py +17 -14
- novelwriter/dialogs/docsplit.py +14 -12
- novelwriter/dialogs/editlabel.py +5 -4
- novelwriter/dialogs/preferences.py +28 -33
- novelwriter/dialogs/projectsettings.py +29 -26
- novelwriter/dialogs/quotes.py +10 -9
- novelwriter/dialogs/wordlist.py +15 -12
- novelwriter/error.py +13 -11
- novelwriter/extensions/circularprogress.py +12 -8
- novelwriter/extensions/configlayout.py +1 -3
- novelwriter/extensions/modified.py +33 -2
- novelwriter/extensions/pagedsidebar.py +16 -14
- novelwriter/extensions/simpleprogress.py +3 -1
- novelwriter/extensions/statusled.py +3 -1
- novelwriter/extensions/switch.py +10 -9
- novelwriter/extensions/switchbox.py +14 -13
- novelwriter/gui/doceditor.py +182 -225
- novelwriter/gui/dochighlight.py +4 -4
- novelwriter/gui/docviewer.py +53 -57
- novelwriter/gui/docviewerpanel.py +16 -13
- novelwriter/gui/editordocument.py +4 -4
- novelwriter/gui/itemdetails.py +45 -48
- novelwriter/gui/noveltree.py +22 -20
- novelwriter/gui/outline.py +87 -88
- novelwriter/gui/projtree.py +31 -29
- novelwriter/gui/search.py +75 -29
- novelwriter/gui/sidebar.py +24 -28
- novelwriter/gui/statusbar.py +14 -14
- novelwriter/gui/theme.py +47 -35
- novelwriter/guimain.py +35 -31
- novelwriter/shared.py +5 -5
- novelwriter/tools/dictionaries.py +13 -12
- novelwriter/tools/lipsum.py +20 -17
- novelwriter/tools/manusbuild.py +35 -27
- novelwriter/tools/manuscript.py +68 -73
- novelwriter/tools/manussettings.py +68 -73
- novelwriter/tools/noveldetails.py +20 -18
- novelwriter/tools/welcome.py +47 -43
- novelwriter/tools/writingstats.py +61 -55
- novelwriter/types.py +90 -0
- novelwriter/assets/icons/typicons_dark/typ_arrow-down.svg +0 -4
- novelwriter/assets/icons/typicons_dark/typ_arrow-right.svg +0 -4
- novelwriter/assets/icons/typicons_light/typ_arrow-down.svg +0 -4
- novelwriter/assets/icons/typicons_light/typ_arrow-right.svg +0 -4
- novelwriter/core/__init__.py +0 -3
- novelwriter/dialogs/__init__.py +0 -3
- novelwriter/extensions/__init__.py +0 -3
- novelwriter/gui/__init__.py +0 -3
- novelwriter/text/__init__.py +0 -3
- novelwriter/tools/__init__.py +0 -3
- {novelWriter-2.4b1.dist-info → novelWriter-2.4rc1.dist-info}/LICENSE.md +0 -0
- {novelWriter-2.4b1.dist-info → novelWriter-2.4rc1.dist-info}/WHEEL +0 -0
- {novelWriter-2.4b1.dist-info → novelWriter-2.4rc1.dist-info}/entry_points.txt +0 -0
- {novelWriter-2.4b1.dist-info → novelWriter-2.4rc1.dist-info}/top_level.txt +0 -0
novelwriter/guimain.py
CHANGED
@@ -30,11 +30,11 @@ from time import time
|
|
30
30
|
from pathlib import Path
|
31
31
|
from datetime import datetime
|
32
32
|
|
33
|
-
from PyQt5.QtGui import QCloseEvent, QCursor, QIcon
|
34
33
|
from PyQt5.QtCore import Qt, QTimer, pyqtSlot
|
34
|
+
from PyQt5.QtGui import QCloseEvent, QCursor, QIcon
|
35
35
|
from PyQt5.QtWidgets import (
|
36
|
-
QFileDialog, QHBoxLayout, QMainWindow, QMessageBox, QShortcut, QSplitter,
|
37
|
-
QStackedWidget, QVBoxLayout, QWidget
|
36
|
+
QApplication, QFileDialog, QHBoxLayout, QMainWindow, QMessageBox, QShortcut, QSplitter,
|
37
|
+
QStackedWidget, QVBoxLayout, QWidget
|
38
38
|
)
|
39
39
|
|
40
40
|
from novelwriter import CONFIG, SHARED, __hexversion__, __version__
|
@@ -109,7 +109,7 @@ class GuiMain(QMainWindow):
|
|
109
109
|
nwIcon = CONFIG.assetPath("icons") / "novelwriter.svg"
|
110
110
|
self.nwIcon = QIcon(str(nwIcon)) if nwIcon.is_file() else QIcon()
|
111
111
|
self.setWindowIcon(self.nwIcon)
|
112
|
-
|
112
|
+
QApplication.setWindowIcon(self.nwIcon)
|
113
113
|
|
114
114
|
# Build the GUI
|
115
115
|
# =============
|
@@ -148,7 +148,7 @@ class GuiMain(QMainWindow):
|
|
148
148
|
self.treePane.setLayout(self.treeBox)
|
149
149
|
|
150
150
|
# Splitter : Document Viewer / Document Meta
|
151
|
-
self.splitView = QSplitter(Qt.Vertical, self)
|
151
|
+
self.splitView = QSplitter(Qt.Orientation.Vertical, self)
|
152
152
|
self.splitView.addWidget(self.docViewer)
|
153
153
|
self.splitView.addWidget(self.docViewerPanel)
|
154
154
|
self.splitView.setHandleWidth(hWd)
|
@@ -158,7 +158,7 @@ class GuiMain(QMainWindow):
|
|
158
158
|
self.splitView.setCollapsible(1, False)
|
159
159
|
|
160
160
|
# Splitter : Document Editor / Document Viewer
|
161
|
-
self.splitDocs = QSplitter(Qt.Horizontal, self)
|
161
|
+
self.splitDocs = QSplitter(Qt.Orientation.Horizontal, self)
|
162
162
|
self.splitDocs.addWidget(self.docEditor)
|
163
163
|
self.splitDocs.addWidget(self.splitView)
|
164
164
|
self.splitDocs.setOpaqueResize(False)
|
@@ -167,7 +167,7 @@ class GuiMain(QMainWindow):
|
|
167
167
|
self.splitDocs.setCollapsible(1, False)
|
168
168
|
|
169
169
|
# Splitter : Project Tree / Document Area
|
170
|
-
self.splitMain = QSplitter(Qt.Horizontal)
|
170
|
+
self.splitMain = QSplitter(Qt.Orientation.Horizontal)
|
171
171
|
self.splitMain.setContentsMargins(0, 0, 0, 0)
|
172
172
|
self.splitMain.addWidget(self.treePane)
|
173
173
|
self.splitMain.addWidget(self.splitDocs)
|
@@ -205,7 +205,7 @@ class GuiMain(QMainWindow):
|
|
205
205
|
self.setMenuBar(self.mainMenu)
|
206
206
|
self.setCentralWidget(self.mainWidget)
|
207
207
|
self.setStatusBar(self.mainStatus)
|
208
|
-
self.setContextMenuPolicy(Qt.NoContextMenu) # Issue #1147
|
208
|
+
self.setContextMenuPolicy(Qt.ContextMenuPolicy.NoContextMenu) # Issue #1147
|
209
209
|
|
210
210
|
# Connect Signals
|
211
211
|
# ===============
|
@@ -262,6 +262,7 @@ class GuiMain(QMainWindow):
|
|
262
262
|
self.docEditor.requestProjectItemSelected.connect(self.projView.setSelectedHandle)
|
263
263
|
self.docEditor.requestProjectItemRenamed.connect(self.projView.renameTreeItem)
|
264
264
|
self.docEditor.requestNewNoteCreation.connect(self.projView.createNewNote)
|
265
|
+
self.docEditor.docTextChanged.connect(self.projSearch.textChanged)
|
265
266
|
|
266
267
|
self.docViewer.documentLoaded.connect(self.docViewerPanel.updateHandle)
|
267
268
|
self.docViewer.loadDocumentTagRequest.connect(self._followTag)
|
@@ -327,7 +328,7 @@ class GuiMain(QMainWindow):
|
|
327
328
|
def postLaunchTasks(self, cmdOpen: str | None) -> None:
|
328
329
|
"""Process tasks after the main window has been created."""
|
329
330
|
if cmdOpen:
|
330
|
-
|
331
|
+
QApplication.processEvents()
|
331
332
|
logger.info("Command line path: %s", cmdOpen)
|
332
333
|
self.openProject(cmdOpen)
|
333
334
|
|
@@ -473,12 +474,12 @@ class GuiMain(QMainWindow):
|
|
473
474
|
break
|
474
475
|
|
475
476
|
if lastEdited is not None:
|
476
|
-
|
477
|
+
QApplication.processEvents()
|
477
478
|
self.openDocument(lastEdited, doScroll=True)
|
478
479
|
|
479
480
|
lastViewed = SHARED.project.data.getLastHandle("viewer")
|
480
481
|
if lastViewed is not None:
|
481
|
-
|
482
|
+
QApplication.processEvents()
|
482
483
|
self.viewDocument(lastViewed)
|
483
484
|
|
484
485
|
# Check if we need to rebuild the index
|
@@ -487,7 +488,7 @@ class GuiMain(QMainWindow):
|
|
487
488
|
self.rebuildIndex()
|
488
489
|
|
489
490
|
# Make sure the changed status is set to false on things opened
|
490
|
-
|
491
|
+
QApplication.processEvents()
|
491
492
|
self.docEditor.setDocumentChanged(False)
|
492
493
|
SHARED.project.setProjectChanged(False)
|
493
494
|
|
@@ -737,7 +738,7 @@ class GuiMain(QMainWindow):
|
|
737
738
|
"""Rebuild the entire index."""
|
738
739
|
if SHARED.hasProject:
|
739
740
|
logger.info("Rebuilding index ...")
|
740
|
-
|
741
|
+
QApplication.setOverrideCursor(QCursor(Qt.CursorShape.WaitCursor))
|
741
742
|
tStart = time()
|
742
743
|
|
743
744
|
self.projView.saveProjectTasks()
|
@@ -751,7 +752,7 @@ class GuiMain(QMainWindow):
|
|
751
752
|
)
|
752
753
|
self.docEditor.updateTagHighLighting()
|
753
754
|
self._updateStatusWordCount()
|
754
|
-
|
755
|
+
QApplication.restoreOverrideCursor()
|
755
756
|
|
756
757
|
if not beQuiet:
|
757
758
|
SHARED.info(self.tr("The project index has been successfully rebuilt."))
|
@@ -767,7 +768,7 @@ class GuiMain(QMainWindow):
|
|
767
768
|
"""Open the welcome dialog."""
|
768
769
|
dialog = GuiWelcome(self)
|
769
770
|
dialog.openProjectRequest.connect(self._openProjectFromWelcome)
|
770
|
-
dialog.
|
771
|
+
dialog.exec()
|
771
772
|
return
|
772
773
|
|
773
774
|
@pyqtSlot()
|
@@ -775,7 +776,7 @@ class GuiMain(QMainWindow):
|
|
775
776
|
"""Open the preferences dialog."""
|
776
777
|
dialog = GuiPreferences(self)
|
777
778
|
dialog.newPreferencesReady.connect(self._processConfigChanges)
|
778
|
-
dialog.
|
779
|
+
dialog.exec()
|
779
780
|
return
|
780
781
|
|
781
782
|
@pyqtSlot()
|
@@ -785,7 +786,7 @@ class GuiMain(QMainWindow):
|
|
785
786
|
if SHARED.hasProject:
|
786
787
|
dialog = GuiProjectSettings(self, gotoPage=focusTab)
|
787
788
|
dialog.newProjectSettingsReady.connect(self._processProjectSettingsChanges)
|
788
|
-
dialog.
|
789
|
+
dialog.exec()
|
789
790
|
return
|
790
791
|
|
791
792
|
@pyqtSlot()
|
@@ -796,7 +797,7 @@ class GuiMain(QMainWindow):
|
|
796
797
|
dialog.setModal(True)
|
797
798
|
dialog.show()
|
798
799
|
dialog.raise_()
|
799
|
-
|
800
|
+
QApplication.processEvents()
|
800
801
|
dialog.updateValues()
|
801
802
|
return
|
802
803
|
|
@@ -809,7 +810,7 @@ class GuiMain(QMainWindow):
|
|
809
810
|
dialog.setModal(False)
|
810
811
|
dialog.show()
|
811
812
|
dialog.raise_()
|
812
|
-
|
813
|
+
QApplication.processEvents()
|
813
814
|
dialog.loadContent()
|
814
815
|
return
|
815
816
|
|
@@ -819,7 +820,7 @@ class GuiMain(QMainWindow):
|
|
819
820
|
if SHARED.hasProject:
|
820
821
|
dialog = GuiWordList(self)
|
821
822
|
dialog.newWordListReady.connect(self._processWordListChanges)
|
822
|
-
dialog.
|
823
|
+
dialog.exec()
|
823
824
|
return
|
824
825
|
|
825
826
|
@pyqtSlot()
|
@@ -831,7 +832,7 @@ class GuiMain(QMainWindow):
|
|
831
832
|
dialog.setModal(False)
|
832
833
|
dialog.show()
|
833
834
|
dialog.raise_()
|
834
|
-
|
835
|
+
QApplication.processEvents()
|
835
836
|
dialog.populateGUI()
|
836
837
|
return
|
837
838
|
|
@@ -842,7 +843,7 @@ class GuiMain(QMainWindow):
|
|
842
843
|
dialog.setModal(True)
|
843
844
|
dialog.show()
|
844
845
|
dialog.raise_()
|
845
|
-
|
846
|
+
QApplication.processEvents()
|
846
847
|
dialog.populateGUI()
|
847
848
|
return
|
848
849
|
|
@@ -860,7 +861,7 @@ class GuiMain(QMainWindow):
|
|
860
861
|
dialog.setModal(True)
|
861
862
|
dialog.show()
|
862
863
|
dialog.raise_()
|
863
|
-
|
864
|
+
QApplication.processEvents()
|
864
865
|
if not dialog.initDialog():
|
865
866
|
dialog.close()
|
866
867
|
SHARED.error(self.tr("Could not initialise the dialog."))
|
@@ -898,7 +899,8 @@ class GuiMain(QMainWindow):
|
|
898
899
|
CONFIG.setViewPanePos(self.splitView.sizes())
|
899
900
|
|
900
901
|
CONFIG.showViewerPanel = self.docViewerPanel.isVisible()
|
901
|
-
|
902
|
+
wFull = Qt.WindowState.WindowFullScreen
|
903
|
+
if self.windowState() & wFull != wFull:
|
902
904
|
# Ignore window size if in full screen mode
|
903
905
|
CONFIG.setMainWinSize(self.width(), self.height())
|
904
906
|
|
@@ -908,7 +910,7 @@ class GuiMain(QMainWindow):
|
|
908
910
|
CONFIG.saveConfig()
|
909
911
|
self.reportConfErr()
|
910
912
|
|
911
|
-
|
913
|
+
QApplication.quit()
|
912
914
|
|
913
915
|
return True
|
914
916
|
|
@@ -935,7 +937,7 @@ class GuiMain(QMainWindow):
|
|
935
937
|
|
936
938
|
def toggleFullScreenMode(self) -> None:
|
937
939
|
"""Toggle full screen mode"""
|
938
|
-
self.setWindowState(self.windowState() ^ Qt.WindowFullScreen)
|
940
|
+
self.setWindowState(self.windowState() ^ Qt.WindowState.WindowFullScreen)
|
939
941
|
return
|
940
942
|
|
941
943
|
##
|
@@ -1055,7 +1057,7 @@ class GuiMain(QMainWindow):
|
|
1055
1057
|
|
1056
1058
|
if theme:
|
1057
1059
|
# We are doing this manually instead of connecting to
|
1058
|
-
#
|
1060
|
+
# paletteChanged since the processing order matters
|
1059
1061
|
SHARED.theme.loadTheme()
|
1060
1062
|
self.docEditor.updateTheme()
|
1061
1063
|
self.docViewer.updateTheme()
|
@@ -1114,7 +1116,7 @@ class GuiMain(QMainWindow):
|
|
1114
1116
|
@pyqtSlot(Path)
|
1115
1117
|
def _openProjectFromWelcome(self, path: Path) -> None:
|
1116
1118
|
"""Handle an open project request from the welcome dialog."""
|
1117
|
-
|
1119
|
+
QApplication.processEvents()
|
1118
1120
|
self.openProject(path)
|
1119
1121
|
if not SHARED.hasProject:
|
1120
1122
|
self.showWelcomeDialog()
|
@@ -1167,7 +1169,9 @@ class GuiMain(QMainWindow):
|
|
1167
1169
|
elif view == nwView.SEARCH:
|
1168
1170
|
self.mainStack.setCurrentWidget(self.splitMain)
|
1169
1171
|
self.projStack.setCurrentWidget(self.projSearch)
|
1170
|
-
self.projSearch.beginSearch(
|
1172
|
+
self.projSearch.beginSearch(
|
1173
|
+
self.docEditor.getSelectedText() if self.docEditor.anyFocus() else ""
|
1174
|
+
)
|
1171
1175
|
elif view == nwView.OUTLINE:
|
1172
1176
|
self.mainStack.setCurrentWidget(self.outlineView)
|
1173
1177
|
return
|
@@ -1209,7 +1213,7 @@ class GuiMain(QMainWindow):
|
|
1209
1213
|
if SHARED.hasProject:
|
1210
1214
|
currTime = time()
|
1211
1215
|
editIdle = currTime - self.docEditor.lastActive > CONFIG.userIdleTime
|
1212
|
-
userIdle =
|
1216
|
+
userIdle = QApplication.applicationState() != Qt.ApplicationState.ApplicationActive
|
1213
1217
|
self.mainStatus.setUserIdle(editIdle or userIdle)
|
1214
1218
|
SHARED.updateIdleTime(currTime, editIdle or userIdle)
|
1215
1219
|
self.mainStatus.updateTime(idleTime=SHARED.projectIdleTime)
|
@@ -1266,7 +1270,7 @@ class GuiMain(QMainWindow):
|
|
1266
1270
|
@pyqtSlot()
|
1267
1271
|
def _keyPressEscape(self) -> None:
|
1268
1272
|
"""Process an escape keypress in the main window."""
|
1269
|
-
if self.docEditor.
|
1273
|
+
if self.docEditor.searchVisible():
|
1270
1274
|
self.docEditor.closeSearch()
|
1271
1275
|
elif SHARED.focusMode:
|
1272
1276
|
SHARED.setFocusMode(False)
|
novelwriter/shared.py
CHANGED
@@ -292,7 +292,7 @@ class SharedData(QObject):
|
|
292
292
|
self._lastAlert = alert.logMessage
|
293
293
|
if log:
|
294
294
|
logger.info(self._lastAlert, stacklevel=2)
|
295
|
-
alert.
|
295
|
+
alert.exec()
|
296
296
|
alert.deleteLater()
|
297
297
|
return
|
298
298
|
|
@@ -304,7 +304,7 @@ class SharedData(QObject):
|
|
304
304
|
self._lastAlert = alert.logMessage
|
305
305
|
if log:
|
306
306
|
logger.warning(self._lastAlert, stacklevel=2)
|
307
|
-
alert.
|
307
|
+
alert.exec()
|
308
308
|
alert.deleteLater()
|
309
309
|
return
|
310
310
|
|
@@ -319,7 +319,7 @@ class SharedData(QObject):
|
|
319
319
|
self._lastAlert = alert.logMessage
|
320
320
|
if log:
|
321
321
|
logger.error(self._lastAlert, stacklevel=2)
|
322
|
-
alert.
|
322
|
+
alert.exec()
|
323
323
|
alert.deleteLater()
|
324
324
|
return
|
325
325
|
|
@@ -329,7 +329,7 @@ class SharedData(QObject):
|
|
329
329
|
alert.setMessage(text, info, details)
|
330
330
|
alert.setAlertType(_GuiAlert.WARN if warn else _GuiAlert.ASK, True)
|
331
331
|
self._lastAlert = alert.logMessage
|
332
|
-
alert.
|
332
|
+
alert.exec()
|
333
333
|
isYes = alert.result() == QMessageBox.StandardButton.Yes
|
334
334
|
alert.deleteLater()
|
335
335
|
return isYes
|
@@ -404,7 +404,7 @@ class _GuiAlert(QMessageBox):
|
|
404
404
|
self.setStandardButtons(QMessageBox.Yes | QMessageBox.No)
|
405
405
|
else:
|
406
406
|
self.setStandardButtons(QMessageBox.Ok)
|
407
|
-
pSz = 2*self._theme.
|
407
|
+
pSz = 2*self._theme.baseIconHeight
|
408
408
|
if level == self.INFO:
|
409
409
|
self.setIconPixmap(self._theme.getPixmap("alert_info", (pSz, pSz)))
|
410
410
|
self.setWindowTitle(self.tr("Information"))
|
@@ -28,16 +28,18 @@ import logging
|
|
28
28
|
from pathlib import Path
|
29
29
|
from zipfile import ZipFile
|
30
30
|
|
31
|
-
from PyQt5.QtGui import QCloseEvent, QTextCursor
|
32
31
|
from PyQt5.QtCore import pyqtSlot
|
32
|
+
from PyQt5.QtGui import QCloseEvent, QTextCursor
|
33
33
|
from PyQt5.QtWidgets import (
|
34
|
-
QDialog, QDialogButtonBox, QFileDialog, QFrame, QHBoxLayout,
|
35
|
-
QLineEdit, QPlainTextEdit, QPushButton, QVBoxLayout, QWidget
|
34
|
+
QApplication, QDialog, QDialogButtonBox, QFileDialog, QFrame, QHBoxLayout,
|
35
|
+
QLabel, QLineEdit, QPlainTextEdit, QPushButton, QVBoxLayout, QWidget
|
36
36
|
)
|
37
37
|
|
38
38
|
from novelwriter import CONFIG, SHARED
|
39
|
-
from novelwriter.error import formatException
|
40
39
|
from novelwriter.common import formatFileFilter, openExternalPath, formatInt, getFileSize
|
40
|
+
from novelwriter.error import formatException
|
41
|
+
from novelwriter.extensions.modified import NIconToolButton
|
42
|
+
from novelwriter.types import QtDialogClose
|
41
43
|
|
42
44
|
logger = logging.getLogger(__name__)
|
43
45
|
|
@@ -54,6 +56,7 @@ class GuiDictionaries(QDialog):
|
|
54
56
|
self._installPath = None
|
55
57
|
self._currDicts = set()
|
56
58
|
|
59
|
+
iSz = SHARED.theme.baseIconSize
|
57
60
|
iPx = CONFIG.pxInt(4)
|
58
61
|
mPx = CONFIG.pxInt(8)
|
59
62
|
sPx = CONFIG.pxInt(16)
|
@@ -68,12 +71,11 @@ class GuiDictionaries(QDialog):
|
|
68
71
|
self.tr("Download a dictionary from one of the links, and add it below."),
|
69
72
|
f" \u203a <a href='{foUrl}'>{foUrl}</a>",
|
70
73
|
f" \u203a <a href='{loUrl}'>{loUrl}</a>",
|
71
|
-
]))
|
74
|
+
]), self)
|
72
75
|
self.huInfo.setOpenExternalLinks(True)
|
73
76
|
self.huInfo.setWordWrap(True)
|
74
77
|
self.huInput = QLineEdit(self)
|
75
|
-
self.huBrowse =
|
76
|
-
self.huBrowse.setIcon(SHARED.theme.getIcon("browse"))
|
78
|
+
self.huBrowse = NIconToolButton(self, iSz, "browse")
|
77
79
|
self.huBrowse.clicked.connect(self._doBrowseHunspell)
|
78
80
|
self.huImport = QPushButton(self.tr("Add Dictionary"), self)
|
79
81
|
self.huImport.setIcon(SHARED.theme.getIcon("add"))
|
@@ -88,11 +90,10 @@ class GuiDictionaries(QDialog):
|
|
88
90
|
self.huAddBox.addWidget(self.huImport)
|
89
91
|
|
90
92
|
# Install Path
|
91
|
-
self.inInfo = QLabel(self.tr("Dictionary install location"))
|
93
|
+
self.inInfo = QLabel(self.tr("Dictionary install location"), self)
|
92
94
|
self.inPath = QLineEdit(self)
|
93
95
|
self.inPath.setReadOnly(True)
|
94
|
-
self.inBrowse =
|
95
|
-
self.inBrowse.setIcon(SHARED.theme.getIcon("browse"))
|
96
|
+
self.inBrowse = NIconToolButton(self, iSz, "browse")
|
96
97
|
self.inBrowse.clicked.connect(self._doOpenInstallLocation)
|
97
98
|
|
98
99
|
self.inBox = QHBoxLayout()
|
@@ -107,7 +108,7 @@ class GuiDictionaries(QDialog):
|
|
107
108
|
self.infoBox.setFrameStyle(QFrame.Shape.NoFrame)
|
108
109
|
|
109
110
|
# Buttons
|
110
|
-
self.buttonBox = QDialogButtonBox(
|
111
|
+
self.buttonBox = QDialogButtonBox(QtDialogClose, self)
|
111
112
|
self.buttonBox.rejected.connect(self._doClose)
|
112
113
|
|
113
114
|
# Assemble
|
@@ -158,7 +159,7 @@ class GuiDictionaries(QDialog):
|
|
158
159
|
"Additional dictionaries found: {0}"
|
159
160
|
).format(len(self._currDicts)))
|
160
161
|
|
161
|
-
|
162
|
+
QApplication.processEvents()
|
162
163
|
self.adjustSize()
|
163
164
|
|
164
165
|
return True
|
novelwriter/tools/lipsum.py
CHANGED
@@ -35,6 +35,7 @@ from PyQt5.QtWidgets import (
|
|
35
35
|
from novelwriter import CONFIG, SHARED
|
36
36
|
from novelwriter.common import readTextFile
|
37
37
|
from novelwriter.extensions.switch import NSwitch
|
38
|
+
from novelwriter.types import QtAlignLeft, QtAlignRight, QtRoleAction, QtDialogClose
|
38
39
|
|
39
40
|
logger = logging.getLogger(__name__)
|
40
41
|
|
@@ -53,13 +54,14 @@ class GuiLipsum(QDialog):
|
|
53
54
|
|
54
55
|
self.setWindowTitle(self.tr("Insert Placeholder Text"))
|
55
56
|
|
57
|
+
vSp = CONFIG.pxInt(4)
|
58
|
+
nPx = CONFIG.pxInt(64)
|
59
|
+
|
56
60
|
self.innerBox = QHBoxLayout()
|
57
61
|
self.innerBox.setSpacing(CONFIG.pxInt(16))
|
58
62
|
|
59
63
|
# Icon
|
60
|
-
|
61
|
-
vSp = CONFIG.pxInt(4)
|
62
|
-
self.docIcon = QLabel()
|
64
|
+
self.docIcon = QLabel(self)
|
63
65
|
self.docIcon.setPixmap(SHARED.theme.getPixmap("proj_document", (nPx, nPx)))
|
64
66
|
|
65
67
|
self.leftBox = QVBoxLayout()
|
@@ -69,35 +71,36 @@ class GuiLipsum(QDialog):
|
|
69
71
|
self.innerBox.addLayout(self.leftBox)
|
70
72
|
|
71
73
|
# Form
|
72
|
-
self.headLabel = QLabel(
|
74
|
+
self.headLabel = QLabel(self.tr("Insert Lorem Ipsum Text"))
|
75
|
+
self.headLabel.setFont(SHARED.theme.guiFontB)
|
73
76
|
|
74
|
-
self.paraLabel = QLabel(self.tr("Number of paragraphs"))
|
75
|
-
self.paraCount = QSpinBox()
|
77
|
+
self.paraLabel = QLabel(self.tr("Number of paragraphs"), self)
|
78
|
+
self.paraCount = QSpinBox(self)
|
76
79
|
self.paraCount.setMinimum(1)
|
77
80
|
self.paraCount.setMaximum(100)
|
78
81
|
self.paraCount.setValue(5)
|
79
82
|
|
80
|
-
self.randLabel = QLabel(self.tr("Randomise order"))
|
81
|
-
self.randSwitch = NSwitch()
|
83
|
+
self.randLabel = QLabel(self.tr("Randomise order"), self)
|
84
|
+
self.randSwitch = NSwitch(self)
|
82
85
|
|
83
86
|
self.formBox = QGridLayout()
|
84
|
-
self.formBox.addWidget(self.headLabel, 0, 0, 1, 2,
|
85
|
-
self.formBox.addWidget(self.paraLabel, 1, 0, 1, 1,
|
86
|
-
self.formBox.addWidget(self.paraCount, 1, 1, 1, 1,
|
87
|
-
self.formBox.addWidget(self.randLabel, 2, 0, 1, 1,
|
88
|
-
self.formBox.addWidget(self.randSwitch, 2, 1, 1, 1,
|
87
|
+
self.formBox.addWidget(self.headLabel, 0, 0, 1, 2, QtAlignLeft)
|
88
|
+
self.formBox.addWidget(self.paraLabel, 1, 0, 1, 1, QtAlignLeft)
|
89
|
+
self.formBox.addWidget(self.paraCount, 1, 1, 1, 1, QtAlignRight)
|
90
|
+
self.formBox.addWidget(self.randLabel, 2, 0, 1, 1, QtAlignLeft)
|
91
|
+
self.formBox.addWidget(self.randSwitch, 2, 1, 1, 1, QtAlignRight)
|
89
92
|
self.formBox.setVerticalSpacing(vSp)
|
90
93
|
self.formBox.setRowStretch(3, 1)
|
91
94
|
self.innerBox.addLayout(self.formBox)
|
92
95
|
|
93
96
|
# Buttons
|
94
|
-
self.buttonBox = QDialogButtonBox()
|
97
|
+
self.buttonBox = QDialogButtonBox(self)
|
95
98
|
self.buttonBox.rejected.connect(self.close)
|
96
99
|
|
97
|
-
self.btnClose = self.buttonBox.addButton(
|
100
|
+
self.btnClose = self.buttonBox.addButton(QtDialogClose)
|
98
101
|
self.btnClose.setAutoDefault(False)
|
99
102
|
|
100
|
-
self.btnInsert = self.buttonBox.addButton(self.tr("Insert"),
|
103
|
+
self.btnInsert = self.buttonBox.addButton(self.tr("Insert"), QtRoleAction)
|
101
104
|
self.btnInsert.clicked.connect(self._doInsert)
|
102
105
|
self.btnInsert.setAutoDefault(False)
|
103
106
|
|
@@ -127,7 +130,7 @@ class GuiLipsum(QDialog):
|
|
127
130
|
def getLipsum(cls, parent: QWidget) -> str:
|
128
131
|
"""Pop the dialog and return the lipsum text."""
|
129
132
|
cls = GuiLipsum(parent)
|
130
|
-
cls.
|
133
|
+
cls.exec()
|
131
134
|
text = cls.lipsumText
|
132
135
|
cls.deleteLater()
|
133
136
|
return text
|
novelwriter/tools/manusbuild.py
CHANGED
@@ -27,8 +27,8 @@ import logging
|
|
27
27
|
|
28
28
|
from pathlib import Path
|
29
29
|
|
30
|
+
from PyQt5.QtCore import QTimer, pyqtSlot
|
30
31
|
from PyQt5.QtGui import QCloseEvent
|
31
|
-
from PyQt5.QtCore import QSize, QTimer, Qt, pyqtSlot
|
32
32
|
from PyQt5.QtWidgets import (
|
33
33
|
QAbstractButton, QAbstractItemView, QDialog, QDialogButtonBox, QFileDialog,
|
34
34
|
QGridLayout, QHBoxLayout, QLabel, QLineEdit, QListWidget, QListWidgetItem,
|
@@ -36,13 +36,17 @@ from PyQt5.QtWidgets import (
|
|
36
36
|
)
|
37
37
|
|
38
38
|
from novelwriter import CONFIG, SHARED
|
39
|
-
from novelwriter.enum import nwBuildFmt
|
40
39
|
from novelwriter.common import makeFileNameSafe, openExternalPath
|
41
40
|
from novelwriter.constants import nwLabels
|
42
|
-
from novelwriter.core.item import NWItem
|
43
|
-
from novelwriter.core.docbuild import NWBuildDocument
|
44
41
|
from novelwriter.core.buildsettings import BuildSettings
|
42
|
+
from novelwriter.core.docbuild import NWBuildDocument
|
43
|
+
from novelwriter.core.item import NWItem
|
44
|
+
from novelwriter.enum import nwBuildFmt
|
45
|
+
from novelwriter.extensions.modified import NIconToolButton
|
45
46
|
from novelwriter.extensions.simpleprogress import NProgressSimple
|
47
|
+
from novelwriter.types import (
|
48
|
+
QtAlignCenter, QtDialogClose, QtRoleAction, QtRoleReject, QtUserRole
|
49
|
+
)
|
46
50
|
|
47
51
|
logger = logging.getLogger(__name__)
|
48
52
|
|
@@ -54,7 +58,7 @@ class GuiManuscriptBuild(QDialog):
|
|
54
58
|
independently of the Manuscript Build Tool.
|
55
59
|
"""
|
56
60
|
|
57
|
-
D_KEY =
|
61
|
+
D_KEY = QtUserRole
|
58
62
|
|
59
63
|
def __init__(self, parent: QWidget, build: BuildSettings):
|
60
64
|
super().__init__(parent=parent)
|
@@ -69,7 +73,8 @@ class GuiManuscriptBuild(QDialog):
|
|
69
73
|
self.setMinimumWidth(CONFIG.pxInt(500))
|
70
74
|
self.setMinimumHeight(CONFIG.pxInt(300))
|
71
75
|
|
72
|
-
|
76
|
+
iSz = SHARED.theme.baseIconSize
|
77
|
+
bSz = SHARED.theme.buttonIconSize
|
73
78
|
sp4 = CONFIG.pxInt(4)
|
74
79
|
sp8 = CONFIG.pxInt(8)
|
75
80
|
sp16 = CONFIG.pxInt(16)
|
@@ -85,9 +90,9 @@ class GuiManuscriptBuild(QDialog):
|
|
85
90
|
# Output Format
|
86
91
|
# =============
|
87
92
|
|
88
|
-
self.lblFormat = QLabel(self.tr("Output Format"))
|
89
|
-
self.listFormats = QListWidget()
|
90
|
-
self.listFormats.setIconSize(
|
93
|
+
self.lblFormat = QLabel(self.tr("Output Format"), self)
|
94
|
+
self.listFormats = QListWidget(self)
|
95
|
+
self.listFormats.setIconSize(iSz)
|
91
96
|
current = None
|
92
97
|
for key in nwBuildFmt:
|
93
98
|
item = QListWidgetItem()
|
@@ -104,17 +109,17 @@ class GuiManuscriptBuild(QDialog):
|
|
104
109
|
self.formatBox.addWidget(self.listFormats, 1)
|
105
110
|
self.formatBox.setContentsMargins(0, 0, 0, 0)
|
106
111
|
|
107
|
-
self.formatWidget = QWidget()
|
112
|
+
self.formatWidget = QWidget(self)
|
108
113
|
self.formatWidget.setLayout(self.formatBox)
|
109
114
|
self.formatWidget.setContentsMargins(0, 0, 0, 0)
|
110
115
|
|
111
116
|
# Table of Contents
|
112
117
|
# =================
|
113
118
|
|
114
|
-
self.lblContent = QLabel(self.tr("Table of Contents"))
|
119
|
+
self.lblContent = QLabel(self.tr("Table of Contents"), self)
|
115
120
|
|
116
121
|
self.listContent = QListWidget(self)
|
117
|
-
self.listContent.setIconSize(
|
122
|
+
self.listContent.setIconSize(iSz)
|
118
123
|
self.listContent.setSelectionMode(QAbstractItemView.SelectionMode.NoSelection)
|
119
124
|
|
120
125
|
self.contentBox = QVBoxLayout()
|
@@ -122,7 +127,7 @@ class GuiManuscriptBuild(QDialog):
|
|
122
127
|
self.contentBox.addWidget(self.listContent, 0)
|
123
128
|
self.contentBox.setContentsMargins(0, 0, 0, 0)
|
124
129
|
|
125
|
-
self.contentWidget = QWidget()
|
130
|
+
self.contentWidget = QWidget(self)
|
126
131
|
self.contentWidget.setLayout(self.contentBox)
|
127
132
|
self.contentWidget.setContentsMargins(0, 0, 0, 0)
|
128
133
|
|
@@ -134,14 +139,14 @@ class GuiManuscriptBuild(QDialog):
|
|
134
139
|
font.setUnderline(True)
|
135
140
|
font.setPointSizeF(1.5*font.pointSizeF())
|
136
141
|
|
137
|
-
self.lblMain = QLabel(self._build.name)
|
142
|
+
self.lblMain = QLabel(self._build.name, self)
|
138
143
|
self.lblMain.setWordWrap(True)
|
139
144
|
self.lblMain.setFont(font)
|
140
145
|
|
141
146
|
# Build Path
|
142
|
-
self.lblPath = QLabel(self.tr("Path"))
|
147
|
+
self.lblPath = QLabel(self.tr("Path"), self)
|
143
148
|
self.buildPath = QLineEdit(self)
|
144
|
-
self.btnBrowse =
|
149
|
+
self.btnBrowse = NIconToolButton(self, iSz, "browse")
|
145
150
|
|
146
151
|
self.pathBox = QHBoxLayout()
|
147
152
|
self.pathBox.addWidget(self.buildPath)
|
@@ -149,9 +154,9 @@ class GuiManuscriptBuild(QDialog):
|
|
149
154
|
self.pathBox.setSpacing(sp8)
|
150
155
|
|
151
156
|
# Build Name
|
152
|
-
self.lblName = QLabel(self.tr("File Name"))
|
157
|
+
self.lblName = QLabel(self.tr("File Name"), self)
|
153
158
|
self.buildName = QLineEdit(self)
|
154
|
-
self.btnReset =
|
159
|
+
self.btnReset = NIconToolButton(self, iSz, "revert")
|
155
160
|
self.btnReset.setToolTip(self.tr("Reset file name to default"))
|
156
161
|
|
157
162
|
self.nameBox = QHBoxLayout()
|
@@ -176,16 +181,19 @@ class GuiManuscriptBuild(QDialog):
|
|
176
181
|
self.buildBox.setVerticalSpacing(sp4)
|
177
182
|
|
178
183
|
# Dialog Buttons
|
179
|
-
self.btnOpen = QPushButton(SHARED.theme.getIcon("browse"), self.tr("Open Folder"))
|
180
|
-
self.
|
181
|
-
self.
|
182
|
-
self.
|
183
|
-
|
184
|
+
self.btnOpen = QPushButton(SHARED.theme.getIcon("browse"), self.tr("Open Folder"), self)
|
185
|
+
self.btnOpen.setIconSize(bSz)
|
186
|
+
self.btnBuild = QPushButton(SHARED.theme.getIcon("export"), self.tr("&Build"), self)
|
187
|
+
self.btnBuild.setIconSize(bSz)
|
188
|
+
|
189
|
+
self.dlgButtons = QDialogButtonBox(QtDialogClose, self)
|
190
|
+
self.dlgButtons.addButton(self.btnOpen, QtRoleAction)
|
191
|
+
self.dlgButtons.addButton(self.btnBuild, QtRoleAction)
|
184
192
|
|
185
193
|
# Assemble GUI
|
186
194
|
# ============
|
187
195
|
|
188
|
-
self.mainSplit = QSplitter()
|
196
|
+
self.mainSplit = QSplitter(self)
|
189
197
|
self.mainSplit.addWidget(self.formatWidget)
|
190
198
|
self.mainSplit.addWidget(self.contentWidget)
|
191
199
|
self.mainSplit.setHandleWidth(sp16)
|
@@ -199,7 +207,7 @@ class GuiManuscriptBuild(QDialog):
|
|
199
207
|
])
|
200
208
|
|
201
209
|
self.outerBox = QVBoxLayout()
|
202
|
-
self.outerBox.addWidget(self.lblMain, 0,
|
210
|
+
self.outerBox.addWidget(self.lblMain, 0, QtAlignCenter)
|
203
211
|
self.outerBox.addSpacing(sp16)
|
204
212
|
self.outerBox.addWidget(self.mainSplit, 1)
|
205
213
|
self.outerBox.addSpacing(sp4)
|
@@ -255,12 +263,12 @@ class GuiManuscriptBuild(QDialog):
|
|
255
263
|
def _dialogButtonClicked(self, button: QAbstractButton):
|
256
264
|
"""Handle button clicks from the dialog button box."""
|
257
265
|
role = self.dlgButtons.buttonRole(button)
|
258
|
-
if role ==
|
266
|
+
if role == QtRoleAction:
|
259
267
|
if button == self.btnBuild:
|
260
268
|
self._runBuild()
|
261
269
|
elif button == self.btnOpen:
|
262
270
|
self._openOutputFolder()
|
263
|
-
elif role ==
|
271
|
+
elif role == QtRoleReject:
|
264
272
|
self.close()
|
265
273
|
return
|
266
274
|
|