novelWriter 2.2b1__py3-none-any.whl → 2.2rc1__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.
Files changed (62) hide show
  1. {novelWriter-2.2b1.dist-info → novelWriter-2.2rc1.dist-info}/METADATA +3 -3
  2. {novelWriter-2.2b1.dist-info → novelWriter-2.2rc1.dist-info}/RECORD +60 -48
  3. novelwriter/__init__.py +3 -3
  4. novelwriter/assets/i18n/project_en_GB.json +1 -0
  5. novelwriter/assets/icons/novelwriter.ico +0 -0
  6. novelwriter/assets/icons/typicons_dark/icons.conf +8 -1
  7. novelwriter/assets/icons/typicons_dark/nw_deco-h2-narrow.svg +4 -0
  8. novelwriter/assets/icons/typicons_dark/nw_deco-h3-narrow.svg +4 -0
  9. novelwriter/assets/icons/typicons_dark/nw_deco-h4-narrow.svg +4 -0
  10. novelwriter/assets/icons/typicons_dark/nw_deco-note.svg +4 -0
  11. novelwriter/assets/icons/typicons_dark/nw_panel.svg +4 -0
  12. novelwriter/assets/icons/typicons_dark/typ_eye.svg +4 -0
  13. novelwriter/assets/icons/typicons_light/icons.conf +8 -1
  14. novelwriter/assets/icons/typicons_light/nw_deco-h2-narrow.svg +4 -0
  15. novelwriter/assets/icons/typicons_light/nw_deco-h3-narrow.svg +4 -0
  16. novelwriter/assets/icons/typicons_light/nw_deco-h4-narrow.svg +4 -0
  17. novelwriter/assets/icons/typicons_light/nw_deco-note.svg +4 -0
  18. novelwriter/assets/icons/typicons_light/nw_panel.svg +4 -0
  19. novelwriter/assets/icons/typicons_light/typ_eye.svg +4 -0
  20. novelwriter/assets/icons/x-novelwriter-project.ico +0 -0
  21. novelwriter/assets/manual.pdf +0 -0
  22. novelwriter/assets/sample.zip +0 -0
  23. novelwriter/assets/text/release_notes.htm +4 -4
  24. novelwriter/common.py +22 -1
  25. novelwriter/config.py +12 -27
  26. novelwriter/constants.py +20 -3
  27. novelwriter/core/buildsettings.py +1 -1
  28. novelwriter/core/coretools.py +6 -1
  29. novelwriter/core/index.py +100 -34
  30. novelwriter/core/options.py +3 -0
  31. novelwriter/core/project.py +2 -2
  32. novelwriter/core/projectdata.py +1 -1
  33. novelwriter/core/tohtml.py +9 -3
  34. novelwriter/core/tokenizer.py +27 -20
  35. novelwriter/core/tomd.py +4 -0
  36. novelwriter/core/toodt.py +11 -4
  37. novelwriter/dialogs/preferences.py +80 -82
  38. novelwriter/dialogs/updates.py +25 -14
  39. novelwriter/enum.py +14 -4
  40. novelwriter/gui/doceditor.py +282 -177
  41. novelwriter/gui/dochighlight.py +7 -9
  42. novelwriter/gui/docviewer.py +142 -319
  43. novelwriter/gui/docviewerpanel.py +457 -0
  44. novelwriter/gui/editordocument.py +1 -1
  45. novelwriter/gui/mainmenu.py +16 -7
  46. novelwriter/gui/outline.py +10 -6
  47. novelwriter/gui/projtree.py +461 -376
  48. novelwriter/gui/sidebar.py +3 -3
  49. novelwriter/gui/statusbar.py +1 -1
  50. novelwriter/gui/theme.py +21 -2
  51. novelwriter/guimain.py +86 -32
  52. novelwriter/shared.py +23 -1
  53. novelwriter/tools/dictionaries.py +268 -0
  54. novelwriter/tools/manusbuild.py +17 -6
  55. novelwriter/tools/manuscript.py +1 -1
  56. novelwriter/tools/writingstats.py +1 -1
  57. novelwriter/assets/icons/typicons_dark/typ_at.svg +0 -4
  58. novelwriter/assets/icons/typicons_light/typ_at.svg +0 -4
  59. {novelWriter-2.2b1.dist-info → novelWriter-2.2rc1.dist-info}/LICENSE.md +0 -0
  60. {novelWriter-2.2b1.dist-info → novelWriter-2.2rc1.dist-info}/WHEEL +0 -0
  61. {novelWriter-2.2b1.dist-info → novelWriter-2.2rc1.dist-info}/entry_points.txt +0 -0
  62. {novelWriter-2.2b1.dist-info → novelWriter-2.2rc1.dist-info}/top_level.txt +0 -0
@@ -67,7 +67,7 @@ class GuiSideBar(QWidget):
67
67
  self.tbNovel.clicked.connect(lambda: self.viewChangeRequested.emit(nwView.NOVEL))
68
68
 
69
69
  self.tbOutline = QToolButton(self)
70
- self.tbOutline.setToolTip(f"{0} [Ctrl+Shift+T]".format(self.tr("Novel Outline View")))
70
+ self.tbOutline.setToolTip("{0} [Ctrl+Shift+T]".format(self.tr("Novel Outline View")))
71
71
  self.tbOutline.setIconSize(iconSize)
72
72
  self.tbOutline.clicked.connect(lambda: self.viewChangeRequested.emit(nwView.OUTLINE))
73
73
 
@@ -111,7 +111,7 @@ class GuiSideBar(QWidget):
111
111
  self.outerBox.addWidget(self.tbDetails)
112
112
  self.outerBox.addWidget(self.tbStats)
113
113
  self.outerBox.addWidget(self.tbSettings)
114
- self.outerBox.setContentsMargins(0, 0, CONFIG.pxInt(2), 0)
114
+ self.outerBox.setContentsMargins(0, 0, 0, 0)
115
115
  self.outerBox.setSpacing(CONFIG.pxInt(4))
116
116
 
117
117
  self.setLayout(self.outerBox)
@@ -131,7 +131,7 @@ class GuiSideBar(QWidget):
131
131
  buttonStyle = (
132
132
  "QToolButton {{padding: {0}px; border: none; background: transparent;}} "
133
133
  "QToolButton:hover {{border: none; background: rgba({1},{2},{3},0.2);}}"
134
- ).format(CONFIG.pxInt(4), fadeCol.red(), fadeCol.green(), fadeCol.blue())
134
+ ).format(CONFIG.pxInt(6), fadeCol.red(), fadeCol.green(), fadeCol.blue())
135
135
  buttonStyleMenu = f"{buttonStyle} QToolButton::menu-indicator {{image: none;}}"
136
136
 
137
137
  self.tbProject.setIcon(SHARED.theme.getIcon("view_editor"))
@@ -97,7 +97,7 @@ class GuiMainStatus(QStatusBar):
97
97
  self.addPermanentWidget(self.statsText)
98
98
 
99
99
  # The Session Clock
100
- # Set the mimimum width so the label doesn't rescale every second
100
+ # Set the minimum width so the label doesn't rescale every second
101
101
  self.timeIcon = QLabel()
102
102
  self.timeText = QLabel("")
103
103
  self.timeText.setToolTip(self.tr("Session Time"))
novelwriter/gui/theme.py CHANGED
@@ -133,6 +133,7 @@ class GuiTheme:
133
133
  self.getToggleIcon = self.iconCache.getToggleIcon
134
134
  self.loadDecoration = self.iconCache.loadDecoration
135
135
  self.getHeaderDecoration = self.iconCache.getHeaderDecoration
136
+ self.getHeaderDecorationNarrow = self.iconCache.getHeaderDecorationNarrow
136
137
 
137
138
  # Extract Other Info
138
139
  self.guiDPI = qApp.primaryScreen().logicalDotsPerInchX()
@@ -464,8 +465,8 @@ class GuiIcons:
464
465
 
465
466
  # General Button Icons
466
467
  "add", "backward", "bookmark", "browse", "checked", "close", "cross", "down", "edit",
467
- "export", "forward", "maximise", "menu", "minimise", "noncheckable", "reference",
468
- "refresh", "remove", "revert", "search_replace", "search", "settings", "unchecked", "up",
468
+ "export", "forward", "maximise", "menu", "minimise", "noncheckable", "panel", "refresh",
469
+ "remove", "revert", "search_replace", "search", "settings", "unchecked", "up", "view",
469
470
 
470
471
  # Switches
471
472
  "sticky-on", "sticky-off",
@@ -473,6 +474,8 @@ class GuiIcons:
473
474
 
474
475
  # Decorations
475
476
  "deco_doc_h0", "deco_doc_h1", "deco_doc_h2", "deco_doc_h3", "deco_doc_h4", "deco_doc_more",
477
+ "deco_doc_h0_n", "deco_doc_h1_n", "deco_doc_h2_n", "deco_doc_h3_n", "deco_doc_h4_n",
478
+ "deco_doc_nt_n",
476
479
  }
477
480
 
478
481
  TOGGLE_ICON_KEYS = {
@@ -493,6 +496,7 @@ class GuiIcons:
493
496
  self._qIcons: dict[str, QIcon] = {}
494
497
  self._themeMap: dict[str, Path] = {}
495
498
  self._headerDec: list[QPixmap] = []
499
+ self._headerDecNarrow: list[QPixmap] = []
496
500
 
497
501
  # Icon Theme Path
498
502
  self._confName = "icons.conf"
@@ -580,6 +584,7 @@ class GuiIcons:
580
584
  self._qIcons[iconKey] = qIcon
581
585
 
582
586
  self._headerDec = []
587
+ self._headerDecNarrow = []
583
588
 
584
589
  return True
585
590
 
@@ -680,6 +685,20 @@ class GuiIcons:
680
685
  ]
681
686
  return self._headerDec[minmax(hLevel, 0, 4)]
682
687
 
688
+ def getHeaderDecorationNarrow(self, hLevel: int) -> QPixmap:
689
+ """Get the narrow decoration for a specific header level."""
690
+ if not self._headerDecNarrow:
691
+ iPx = self.mainTheme.baseIconSize
692
+ self._headerDecNarrow = [
693
+ self.loadDecoration("deco_doc_h0_n", h=iPx),
694
+ self.loadDecoration("deco_doc_h1_n", h=iPx),
695
+ self.loadDecoration("deco_doc_h2_n", h=iPx),
696
+ self.loadDecoration("deco_doc_h3_n", h=iPx),
697
+ self.loadDecoration("deco_doc_h4_n", h=iPx),
698
+ self.loadDecoration("deco_doc_nt_n", h=iPx),
699
+ ]
700
+ return self._headerDecNarrow[minmax(hLevel, 0, 5)]
701
+
683
702
  ##
684
703
  # Internal Functions
685
704
  ##
novelwriter/guimain.py CHANGED
@@ -44,10 +44,11 @@ from novelwriter.gui.outline import GuiOutlineView
44
44
  from novelwriter.gui.mainmenu import GuiMainMenu
45
45
  from novelwriter.gui.projtree import GuiProjectView
46
46
  from novelwriter.gui.doceditor import GuiDocEditor
47
- from novelwriter.gui.docviewer import GuiDocViewDetails, GuiDocViewer
47
+ from novelwriter.gui.docviewer import GuiDocViewer
48
48
  from novelwriter.gui.noveltree import GuiNovelView
49
49
  from novelwriter.gui.statusbar import GuiMainStatus
50
50
  from novelwriter.gui.itemdetails import GuiItemDetails
51
+ from novelwriter.gui.docviewerpanel import GuiDocViewerPanel
51
52
  from novelwriter.dialogs.about import GuiAbout
52
53
  from novelwriter.dialogs.updates import GuiUpdates
53
54
  from novelwriter.dialogs.projload import GuiProjectLoad
@@ -58,6 +59,7 @@ from novelwriter.dialogs.projsettings import GuiProjectSettings
58
59
  from novelwriter.tools.lipsum import GuiLipsum
59
60
  from novelwriter.tools.manuscript import GuiManuscript
60
61
  from novelwriter.tools.projwizard import GuiProjectWizard
62
+ from novelwriter.tools.dictionaries import GuiDictionaries
61
63
  from novelwriter.tools.writingstats import GuiWritingStats
62
64
  from novelwriter.core.coretools import ProjectBuilder
63
65
 
@@ -133,16 +135,16 @@ class GuiMain(QMainWindow):
133
135
  hWd = CONFIG.pxInt(4)
134
136
 
135
137
  # Main GUI Elements
136
- self.mainStatus = GuiMainStatus(self)
137
- self.projView = GuiProjectView(self)
138
- self.novelView = GuiNovelView(self)
139
- self.docEditor = GuiDocEditor(self)
140
- self.viewMeta = GuiDocViewDetails(self)
141
- self.docViewer = GuiDocViewer(self)
142
- self.itemDetails = GuiItemDetails(self)
143
- self.outlineView = GuiOutlineView(self)
144
- self.mainMenu = GuiMainMenu(self)
145
- self.sideBar = GuiSideBar(self)
138
+ self.mainStatus = GuiMainStatus(self)
139
+ self.projView = GuiProjectView(self)
140
+ self.novelView = GuiNovelView(self)
141
+ self.docEditor = GuiDocEditor(self)
142
+ self.docViewer = GuiDocViewer(self)
143
+ self.docViewerPanel = GuiDocViewerPanel(self)
144
+ self.itemDetails = GuiItemDetails(self)
145
+ self.outlineView = GuiOutlineView(self)
146
+ self.mainMenu = GuiMainMenu(self)
147
+ self.sideBar = GuiSideBar(self)
146
148
 
147
149
  # Project Tree Stack
148
150
  self.projStack = QStackedWidget(self)
@@ -162,7 +164,7 @@ class GuiMain(QMainWindow):
162
164
  # Splitter : Document Viewer / Document Meta
163
165
  self.splitView = QSplitter(Qt.Vertical, self)
164
166
  self.splitView.addWidget(self.docViewer)
165
- self.splitView.addWidget(self.viewMeta)
167
+ self.splitView.addWidget(self.docViewerPanel)
166
168
  self.splitView.setHandleWidth(hWd)
167
169
  self.splitView.setOpaqueResize(False)
168
170
  self.splitView.setSizes(CONFIG.viewPanePos)
@@ -190,12 +192,12 @@ class GuiMain(QMainWindow):
190
192
  self.mainStack.currentChanged.connect(self._mainStackChanged)
191
193
 
192
194
  # Indices of Splitter Widgets
193
- self.idxTree = self.splitMain.indexOf(self.treePane)
194
- self.idxMain = self.splitMain.indexOf(self.splitDocs)
195
- self.idxEditor = self.splitDocs.indexOf(self.docEditor)
196
- self.idxViewer = self.splitDocs.indexOf(self.splitView)
197
- self.idxViewDoc = self.splitView.indexOf(self.docViewer)
198
- self.idxViewMeta = self.splitView.indexOf(self.viewMeta)
195
+ self.idxTree = self.splitMain.indexOf(self.treePane)
196
+ self.idxMain = self.splitMain.indexOf(self.splitDocs)
197
+ self.idxEditor = self.splitDocs.indexOf(self.docEditor)
198
+ self.idxViewer = self.splitDocs.indexOf(self.splitView)
199
+ self.idxViewDoc = self.splitView.indexOf(self.docViewer)
200
+ self.idxViewDocPanel = self.splitView.indexOf(self.docViewerPanel)
199
201
 
200
202
  # Indices of Stack Widgets
201
203
  self.idxEditorView = self.mainStack.indexOf(self.splitMain)
@@ -209,7 +211,7 @@ class GuiMain(QMainWindow):
209
211
  self.splitDocs.setCollapsible(self.idxEditor, False)
210
212
  self.splitDocs.setCollapsible(self.idxViewer, False)
211
213
  self.splitView.setCollapsible(self.idxViewDoc, False)
212
- self.splitView.setCollapsible(self.idxViewMeta, False)
214
+ self.splitView.setCollapsible(self.idxViewDocPanel, False)
213
215
 
214
216
  self.splitMain.setStretchFactor(self.idxTree, 0)
215
217
  self.splitMain.setStretchFactor(self.idxMain, 1)
@@ -242,6 +244,12 @@ class GuiMain(QMainWindow):
242
244
  SHARED.projectStatusChanged.connect(self.mainStatus.updateProjectStatus)
243
245
  SHARED.projectStatusMessage.connect(self.mainStatus.setStatusMessage)
244
246
  SHARED.spellLanguageChanged.connect(self.mainStatus.setLanguage)
247
+ SHARED.indexChangedTags.connect(self.docViewerPanel.updateChangedTags)
248
+ SHARED.indexScannedText.connect(self.docViewerPanel.projectItemChanged)
249
+ SHARED.indexScannedText.connect(self.projView.updateItemValues)
250
+ SHARED.indexScannedText.connect(self.itemDetails.updateViewBox)
251
+ SHARED.indexCleared.connect(self.docViewerPanel.indexWasCleared)
252
+ SHARED.indexAvailable.connect(self.docViewerPanel.indexHasAppeared)
245
253
 
246
254
  self.mainMenu.requestDocAction.connect(self._passDocumentAction)
247
255
  self.mainMenu.requestDocInsert.connect(self._passDocumentInsert)
@@ -257,6 +265,7 @@ class GuiMain(QMainWindow):
257
265
  self.projView.treeItemChanged.connect(self.docEditor.updateDocInfo)
258
266
  self.projView.treeItemChanged.connect(self.docViewer.updateDocInfo)
259
267
  self.projView.treeItemChanged.connect(self.itemDetails.updateViewBox)
268
+ self.projView.treeItemChanged.connect(self.docViewerPanel.projectItemChanged)
260
269
  self.projView.rootFolderChanged.connect(self.outlineView.updateRootItem)
261
270
  self.projView.rootFolderChanged.connect(self.novelView.updateRootItem)
262
271
  self.projView.rootFolderChanged.connect(self.projView.updateRootItem)
@@ -275,8 +284,16 @@ class GuiMain(QMainWindow):
275
284
  self.docEditor.spellCheckStateChanged.connect(self.mainMenu.setSpellCheckState)
276
285
  self.docEditor.closeDocumentRequest.connect(self.closeDocEditor)
277
286
  self.docEditor.toggleFocusModeRequest.connect(self.toggleFocusMode)
287
+ self.docEditor.requestProjectItemSelected.connect(self.projView.setSelectedHandle)
288
+ self.docEditor.requestProjectItemRenamed.connect(self.projView.renameTreeItem)
278
289
 
290
+ self.docViewer.documentLoaded.connect(self.docViewerPanel.updateHandle)
279
291
  self.docViewer.loadDocumentTagRequest.connect(self._followTag)
292
+ self.docViewer.togglePanelVisibility.connect(self._toggleViewerPanelVisibility)
293
+ self.docViewer.requestProjectItemSelected.connect(self.projView.setSelectedHandle)
294
+
295
+ self.docViewerPanel.loadDocumentTagRequest.connect(self._followTag)
296
+ self.docViewerPanel.openDocumentRequest.connect(self._openDocument)
280
297
 
281
298
  self.outlineView.loadDocumentTagRequest.connect(self._followTag)
282
299
  self.outlineView.openDocumentRequest.connect(self._openDocument)
@@ -327,12 +344,12 @@ class GuiMain(QMainWindow):
327
344
 
328
345
  logger.debug("Ready: GUI")
329
346
 
330
- if __hexversion__[-2] == "a" and logger.getEffectiveLevel() > logging.DEBUG:
331
- SHARED.warn(self.tr(
347
+ if __hexversion__[-2] == "a" and not CONFIG.isDebug:
348
+ SHARED.warn(
332
349
  "You are running an untested development version of novelWriter. "
333
- "Please be careful when working on a live project "
350
+ "Please be careful when you are working on live projects "
334
351
  "and make sure you take regular backups."
335
- ))
352
+ )
336
353
 
337
354
  logger.info("novelWriter is ready ...")
338
355
  self.mainStatus.setStatusMessage(self.tr("novelWriter is ready ..."))
@@ -437,6 +454,7 @@ class GuiMain(QMainWindow):
437
454
  self.docViewer.clearNavHistory()
438
455
  self.closeDocViewer(byUser=False)
439
456
 
457
+ self.docViewerPanel.closeProjectTasks()
440
458
  self.outlineView.closeProjectTasks()
441
459
  self.novelView.closeProjectTasks()
442
460
  self.projView.clearProjectView()
@@ -510,6 +528,7 @@ class GuiMain(QMainWindow):
510
528
  self.projView.openProjectTasks()
511
529
  self.novelView.openProjectTasks()
512
530
  self.outlineView.openProjectTasks()
531
+ self.docViewerPanel.openProjectTasks()
513
532
  self._updateStatusWordCount()
514
533
 
515
534
  # Restore previously open documents, if any
@@ -675,13 +694,19 @@ class GuiMain(QMainWindow):
675
694
  logger.debug("Viewing document with handle '%s'", tHandle)
676
695
  if self.docViewer.loadText(tHandle):
677
696
  if not self.splitView.isVisible():
697
+ cursorVisible = self.docEditor.cursorIsVisible()
678
698
  bPos = self.splitMain.sizes()
679
699
  self.splitView.setVisible(True)
680
700
  vPos = [0, 0]
681
701
  vPos[0] = int(bPos[1]/2)
682
702
  vPos[1] = bPos[1] - vPos[0]
683
703
  self.splitDocs.setSizes(vPos)
684
- self.viewMeta.setVisible(CONFIG.showRefPanel)
704
+ self.docViewerPanel.setVisible(CONFIG.showViewerPanel)
705
+
706
+ # Since editor width changes, we need to make sure we
707
+ # restore cursor visibility in the editor. See #1302
708
+ if cursorVisible:
709
+ self.docEditor.ensureCursorVisibleNoCentre()
685
710
 
686
711
  if sTitle:
687
712
  self.docViewer.navigateTo(f"#{sTitle}")
@@ -782,11 +807,9 @@ class GuiMain(QMainWindow):
782
807
  if not SHARED.hasProject:
783
808
  logger.error("No project open")
784
809
  return False
785
-
786
810
  if tHandle is None and (self.docEditor.anyFocus() or self.isFocusMode):
787
811
  tHandle = self.docEditor.docHandle
788
812
  self.projView.renameTreeItem(tHandle)
789
-
790
813
  return True
791
814
 
792
815
  def rebuildTrees(self) -> None:
@@ -877,6 +900,7 @@ class GuiMain(QMainWindow):
877
900
  SHARED.theme.loadTheme()
878
901
  self.docEditor.updateTheme()
879
902
  self.docViewer.updateTheme()
903
+ self.docViewerPanel.updateTheme()
880
904
  self.sideBar.updateTheme()
881
905
  self.projView.updateTheme()
882
906
  self.novelView.updateTheme()
@@ -1047,6 +1071,20 @@ class GuiMain(QMainWindow):
1047
1071
 
1048
1072
  return
1049
1073
 
1074
+ @pyqtSlot()
1075
+ def showDictionariesDialog(self) -> None:
1076
+ """Show the download dictionaries dialog."""
1077
+ dlgDicts = GuiDictionaries(self)
1078
+ dlgDicts.setModal(True)
1079
+ dlgDicts.show()
1080
+ dlgDicts.raise_()
1081
+ qApp.processEvents()
1082
+ if not dlgDicts.initDialog():
1083
+ dlgDicts.close()
1084
+ SHARED.error(self.tr("Could not initialise the dialog."))
1085
+
1086
+ return
1087
+
1050
1088
  def reportConfErr(self) -> bool:
1051
1089
  """Checks if the Config module has any errors to report, and let
1052
1090
  the user know if this is the case. The Config module caches
@@ -1076,10 +1114,10 @@ class GuiMain(QMainWindow):
1076
1114
  if not self.isFocusMode:
1077
1115
  CONFIG.setMainPanePos(self.splitMain.sizes())
1078
1116
  CONFIG.setOutlinePanePos(self.outlineView.splitSizes())
1079
- if self.viewMeta.isVisible():
1117
+ if self.docViewerPanel.isVisible():
1080
1118
  CONFIG.setViewPanePos(self.splitView.sizes())
1081
1119
 
1082
- CONFIG.showRefPanel = self.viewMeta.isVisible()
1120
+ CONFIG.showViewerPanel = self.docViewerPanel.isVisible()
1083
1121
  if self.windowState() & Qt.WindowFullScreen != Qt.WindowFullScreen:
1084
1122
  # Ignore window size if in full screen mode
1085
1123
  CONFIG.setMainWinSize(self.width(), self.height())
@@ -1101,11 +1139,18 @@ class GuiMain(QMainWindow):
1101
1139
  # Only reset the last handle if the user called this
1102
1140
  SHARED.project.data.setLastHandle(None, "viewer")
1103
1141
 
1142
+ cursorVisible = self.docEditor.cursorIsVisible()
1143
+
1104
1144
  # Hide the panel
1105
1145
  bPos = self.splitMain.sizes()
1106
1146
  self.splitView.setVisible(False)
1107
1147
  self.splitDocs.setSizes([bPos[1], 0])
1108
1148
 
1149
+ # Since editor width changes, we need to make sure we restore
1150
+ # cursor visibility in the editor. See #1302
1151
+ if cursorVisible:
1152
+ self.docEditor.ensureCursorVisibleNoCentre()
1153
+
1109
1154
  return not self.splitView.isVisible()
1110
1155
 
1111
1156
  def toggleFullScreenMode(self) -> None:
@@ -1121,10 +1166,7 @@ class GuiMain(QMainWindow):
1121
1166
  """Capture the closing event of the GUI and call the close
1122
1167
  function to handle all the close process steps.
1123
1168
  """
1124
- if self.closeMain():
1125
- event.accept()
1126
- else:
1127
- event.ignore()
1169
+ event.accept() if self.closeMain() else event.ignore()
1128
1170
  return
1129
1171
 
1130
1172
  ##
@@ -1154,6 +1196,7 @@ class GuiMain(QMainWindow):
1154
1196
  else:
1155
1197
  logger.debug("Deactivating Focus Mode")
1156
1198
 
1199
+ cursorVisible = self.docEditor.cursorIsVisible()
1157
1200
  isVisible = not self.isFocusMode
1158
1201
  self.treePane.setVisible(isVisible)
1159
1202
  self.mainStatus.setVisible(isVisible)
@@ -1169,6 +1212,9 @@ class GuiMain(QMainWindow):
1169
1212
  elif self.docViewer.docHandle is not None:
1170
1213
  self.splitView.setVisible(True)
1171
1214
 
1215
+ if cursorVisible:
1216
+ self.docEditor.ensureCursorVisibleNoCentre()
1217
+
1172
1218
  return
1173
1219
 
1174
1220
  @pyqtSlot(nwWidget)
@@ -1267,6 +1313,13 @@ class GuiMain(QMainWindow):
1267
1313
  self.docEditor.insertText(content)
1268
1314
  return
1269
1315
 
1316
+ @pyqtSlot()
1317
+ def _toggleViewerPanelVisibility(self):
1318
+ """Toggle the visibility of the document viewer panel."""
1319
+ CONFIG.showViewerPanel = not CONFIG.showViewerPanel
1320
+ self.docViewerPanel.setVisible(CONFIG.showViewerPanel)
1321
+ return
1322
+
1270
1323
  @pyqtSlot()
1271
1324
  def _timeTick(self) -> None:
1272
1325
  """Process time tick of the main timer."""
@@ -1408,6 +1461,7 @@ class GuiMain(QMainWindow):
1408
1461
  self.addAction(self.mainMenu.aInsTimes)
1409
1462
  self.addAction(self.mainMenu.aInsDivide)
1410
1463
  self.addAction(self.mainMenu.aInsSynopsis)
1464
+ self.addAction(self.mainMenu.aInsShort)
1411
1465
 
1412
1466
  for mAction, _ in self.mainMenu.mInsKWItems.values():
1413
1467
  self.addAction(mAction)
novelwriter/shared.py CHANGED
@@ -52,6 +52,10 @@ class SharedData(QObject):
52
52
  projectStatusChanged = pyqtSignal(bool)
53
53
  projectStatusMessage = pyqtSignal(str)
54
54
  spellLanguageChanged = pyqtSignal(str, str)
55
+ indexScannedText = pyqtSignal(str)
56
+ indexChangedTags = pyqtSignal(list, list)
57
+ indexCleared = pyqtSignal()
58
+ indexAvailable = pyqtSignal()
55
59
 
56
60
  def __init__(self) -> None:
57
61
  super().__init__()
@@ -171,7 +175,7 @@ class SharedData(QObject):
171
175
  return
172
176
 
173
177
  def updateSpellCheckLanguage(self, reload: bool = False) -> None:
174
- """Update the active spell check langauge from settings."""
178
+ """Update the active spell check language from settings."""
175
179
  from novelwriter import CONFIG
176
180
  language = self.project.data.spellLang or CONFIG.spellLanguage
177
181
  if language != self.spelling.spellLanguage or reload:
@@ -210,6 +214,24 @@ class SharedData(QObject):
210
214
  QThreadPool.globalInstance().start(runnable, priority=priority)
211
215
  return
212
216
 
217
+ ##
218
+ # Signal Proxy
219
+ ##
220
+
221
+ def indexSignalProxy(self, data: dict) -> None:
222
+ """Emit signals on behalf of the index."""
223
+ event = data.get("event")
224
+ logger.debug("Received '%s' event from the index", event)
225
+ if event == "updateTags":
226
+ self.indexChangedTags.emit(data.get("updated", []), data.get("deleted", []))
227
+ elif event == "scanText":
228
+ self.indexScannedText.emit(data.get("handle", ""))
229
+ elif event == "clearIndex":
230
+ self.indexCleared.emit()
231
+ elif event == "buildIndex":
232
+ self.indexAvailable.emit()
233
+ return
234
+
213
235
  ##
214
236
  # Alert Boxes
215
237
  ##