diff --git a/novelwriter/gui/noveltree.py b/novelwriter/gui/noveltree.py index b96f5331..0dec2551 100644 --- a/novelwriter/gui/noveltree.py +++ b/novelwriter/gui/noveltree.py @@ -174,7 +174,7 @@ class GuiNovelToolBar(QWidget): self.mainTheme = novelView.mainGui.mainTheme iPx = self.mainTheme.baseIconSize - mPx = self.mainConf.pxInt(3) + mPx = self.mainConf.pxInt(2) self.setContentsMargins(0, 0, 0, 0) self.setAutoFillBackground(True) @@ -396,8 +396,6 @@ class GuiNovelTree(QTreeWidget): self.mainTheme.loadDecoration("deco_doc_h4", pxH=iPx), ] self._pMore = self.mainTheme.loadDecoration("deco_doc_more", pxH=iPx) - self._pActive = self.mainTheme.loadDecoration("deco_more_on", pxH=iPx) - self._pInactive = self.mainTheme.loadDecoration("deco_more_off", pxH=iPx) # Connect signals self.clicked.connect(self._treeItemClicked) diff --git a/novelwriter/gui/outline.py b/novelwriter/gui/outline.py index 0ae253f9..49efe5f0 100644 --- a/novelwriter/gui/outline.py +++ b/novelwriter/gui/outline.py @@ -37,16 +37,16 @@ from PyQt5.QtCore import ( Qt, pyqtSignal, pyqtSlot, QSize, QT_TRANSLATE_NOOP ) from PyQt5.QtWidgets import ( - QAbstractItemView, QAction, QGridLayout, QGroupBox, QHBoxLayout, QLabel, - QMenu, QScrollArea, QSplitter, QTreeWidget, QTreeWidgetItem, QVBoxLayout, - QWidget, QFrame, QToolBar, QSizePolicy, QComboBox, QToolButton + QAbstractItemView, QAction, QComboBox, QFrame, QGridLayout, QGroupBox, + QHBoxLayout, QLabel, QMenu, QScrollArea, QSizePolicy, QSplitter, QToolBar, + QToolButton, QTreeWidget, QTreeWidgetItem, QVBoxLayout, QWidget ) from novelwriter.enum import ( nwDocMode, nwItemClass, nwItemLayout, nwItemType, nwOutline ) from novelwriter.common import checkInt -from novelwriter.constants import trConst, nwKeyWords, nwLabels +from novelwriter.constants import nwHeaders, trConst, nwKeyWords, nwLabels logger = logging.getLogger(__name__) @@ -313,6 +313,9 @@ class GuiOutlineTree(QTreeWidget): nwOutline.SYNOP: False, } + D_HANDLE = Qt.UserRole + D_TITLE = Qt.UserRole + 1 + hiddenStateChanged = pyqtSignal() activeItemChanged = pyqtSignal(str, str) @@ -337,11 +340,35 @@ class GuiOutlineTree(QTreeWidget): iPx = self.mainTheme.baseIconSize self.setIconSize(QSize(iPx, iPx)) - self.setIndentation(iPx) + self.setIndentation(0) self.treeHead = self.header() self.treeHead.sectionMoved.connect(self._columnMoved) + # Pre-Generate Tree Formatting + fH1 = self.font() + fH1.setBold(True) + fH1.setUnderline(True) + + fH2 = self.font() + fH2.setBold(True) + + self._hFonts = [self.font(), fH1, fH2, self.font(), self.font()] + self._pIndent = [ + self.mainTheme.loadDecoration("deco_doc_h0", pxH=iPx), + self.mainTheme.loadDecoration("deco_doc_h1", pxH=iPx), + self.mainTheme.loadDecoration("deco_doc_h2", pxH=iPx), + self.mainTheme.loadDecoration("deco_doc_h3", pxH=iPx), + self.mainTheme.loadDecoration("deco_doc_h4", pxH=iPx), + ] + self._dIcon = { + "H0": self.mainTheme.getItemIcon(nwItemType.FILE, None, nwItemLayout.DOCUMENT, "H0"), + "H1": self.mainTheme.getItemIcon(nwItemType.FILE, None, nwItemLayout.DOCUMENT, "H1"), + "H2": self.mainTheme.getItemIcon(nwItemType.FILE, None, nwItemLayout.DOCUMENT, "H2"), + "H3": self.mainTheme.getItemIcon(nwItemType.FILE, None, nwItemLayout.DOCUMENT, "H3"), + "H4": self.mainTheme.getItemIcon(nwItemType.FILE, None, nwItemLayout.DOCUMENT, "H4"), + } + # Internals self._treeOrder = [] self._colWidth = {} @@ -449,7 +476,7 @@ class GuiOutlineTree(QTreeWidget): tHandle = None tLine = 0 if selItem: - tHandle = selItem[0].data(self._colIdx[nwOutline.TITLE], Qt.UserRole) + tHandle = selItem[0].data(self._colIdx[nwOutline.TITLE], self.D_HANDLE) tLine = checkInt(selItem[0].text(self._colIdx[nwOutline.LINE]), 1) - 1 return tHandle, tLine @@ -475,8 +502,8 @@ class GuiOutlineTree(QTreeWidget): """ selItems = self.selectedItems() if selItems: - tHandle = selItems[0].data(self._colIdx[nwOutline.TITLE], Qt.UserRole) - sTitle = selItems[0].data(self._colIdx[nwOutline.LINE], Qt.UserRole) + tHandle = selItems[0].data(self._colIdx[nwOutline.TITLE], self.D_HANDLE) + sTitle = selItems[0].data(self._colIdx[nwOutline.TITLE], self.D_TITLE) self.activeItemChanged.emit(tHandle, sTitle) return @@ -614,8 +641,7 @@ class GuiOutlineTree(QTreeWidget): self.setColumnWidth(self._colIdx[hItem], self._colWidth[hItem]) self.setColumnHidden(self._colIdx[hItem], self._colHidden[hItem]) - # Make sure title column is always visible, - # and handle column always hidden + # Make sure title column is always visible self.setColumnHidden(self._colIdx[nwOutline.TITLE], False) headItem = self.headerItem() @@ -623,101 +649,51 @@ class GuiOutlineTree(QTreeWidget): headItem.setTextAlignment(self._colIdx[nwOutline.WCOUNT], Qt.AlignRight) headItem.setTextAlignment(self._colIdx[nwOutline.PCOUNT], Qt.AlignRight) - currTitle = None - currChapter = None - currScene = None - novStruct = self.theProject.index.novelStructure(rootHandle=rootHandle, skipExcl=True) for _, tHandle, sTitle, novIdx in novStruct: - tItem = self._createTreeItem(tHandle, sTitle, novIdx) + iLevel = nwHeaders.H_LEVEL.get(novIdx.level, 0) + dLevel = self.theProject.index.getHandleHeaderLevel(tHandle) + if iLevel == 0: + continue - tLevel = novIdx.level - if tLevel == "H1": - self.addTopLevelItem(tItem) - currTitle = tItem - currChapter = None - currScene = None + trItem = QTreeWidgetItem() + nwItem = self.theProject.tree[tHandle] - elif tLevel == "H2": - if currTitle is None: - self.addTopLevelItem(tItem) - else: - currTitle.addChild(tItem) - currChapter = tItem - currScene = None + trItem.setData(self._colIdx[nwOutline.TITLE], Qt.DecorationRole, self._pIndent[iLevel]) + trItem.setText(self._colIdx[nwOutline.TITLE], novIdx.title) + trItem.setData(self._colIdx[nwOutline.TITLE], self.D_HANDLE, tHandle) + trItem.setData(self._colIdx[nwOutline.TITLE], self.D_TITLE, sTitle) + trItem.setFont(self._colIdx[nwOutline.TITLE], self._hFonts[iLevel]) + trItem.setText(self._colIdx[nwOutline.LEVEL], novIdx.level) + trItem.setIcon(self._colIdx[nwOutline.LABEL], self._dIcon[dLevel]) + trItem.setText(self._colIdx[nwOutline.LABEL], nwItem.itemName) + trItem.setText(self._colIdx[nwOutline.LINE], sTitle[1:].lstrip("0")) + trItem.setText(self._colIdx[nwOutline.SYNOP], novIdx.synopsis) + trItem.setText(self._colIdx[nwOutline.CCOUNT], f"{novIdx.charCount:n}") + trItem.setText(self._colIdx[nwOutline.WCOUNT], f"{novIdx.wordCount:n}") + trItem.setText(self._colIdx[nwOutline.PCOUNT], f"{novIdx.paraCount:n}") + trItem.setTextAlignment(self._colIdx[nwOutline.CCOUNT], Qt.AlignRight) + trItem.setTextAlignment(self._colIdx[nwOutline.WCOUNT], Qt.AlignRight) + trItem.setTextAlignment(self._colIdx[nwOutline.PCOUNT], Qt.AlignRight) - elif tLevel == "H3": - if currChapter is None: - if currTitle is None: - self.addTopLevelItem(tItem) - else: - currTitle.addChild(tItem) - else: - currChapter.addChild(tItem) - currScene = tItem + refs = self.theProject.index.getReferences(tHandle, sTitle) + trItem.setText(self._colIdx[nwOutline.POV], ", ".join(refs[nwKeyWords.POV_KEY])) + trItem.setText(self._colIdx[nwOutline.FOCUS], ", ".join(refs[nwKeyWords.FOCUS_KEY])) + trItem.setText(self._colIdx[nwOutline.CHAR], ", ".join(refs[nwKeyWords.CHAR_KEY])) + trItem.setText(self._colIdx[nwOutline.PLOT], ", ".join(refs[nwKeyWords.PLOT_KEY])) + trItem.setText(self._colIdx[nwOutline.TIME], ", ".join(refs[nwKeyWords.TIME_KEY])) + trItem.setText(self._colIdx[nwOutline.WORLD], ", ".join(refs[nwKeyWords.WORLD_KEY])) + trItem.setText(self._colIdx[nwOutline.OBJECT], ", ".join(refs[nwKeyWords.OBJECT_KEY])) + trItem.setText(self._colIdx[nwOutline.ENTITY], ", ".join(refs[nwKeyWords.ENTITY_KEY])) + trItem.setText(self._colIdx[nwOutline.CUSTOM], ", ".join(refs[nwKeyWords.CUSTOM_KEY])) - elif tLevel == "H4": - if currScene is None: - if currChapter is None: - if currTitle is None: - self.addTopLevelItem(tItem) - else: - currTitle.addChild(tItem) - else: - currChapter.addChild(tItem) - else: - currScene.addChild(tItem) - - tItem.setExpanded(True) + self.addTopLevelItem(trItem) self._lastBuild = time() return - def _createTreeItem(self, tHandle, sTitle, novIdx): - """Populate a tree item with all the column values. - """ - nwItem = self.theProject.tree[tHandle] - newItem = QTreeWidgetItem() - hIcon = "doc_%s" % novIdx.level.lower() - - hLevel = self.theProject.index.getHandleHeaderLevel(tHandle) - dIcon = self.mainTheme.getItemIcon(nwItemType.FILE, None, nwItemLayout.DOCUMENT, hLevel) - - cC = int(novIdx.charCount) - wC = int(novIdx.wordCount) - pC = int(novIdx.paraCount) - - newItem.setText(self._colIdx[nwOutline.TITLE], novIdx.title) - newItem.setData(self._colIdx[nwOutline.TITLE], Qt.UserRole, tHandle) - newItem.setIcon(self._colIdx[nwOutline.TITLE], self.mainTheme.getIcon(hIcon)) - newItem.setText(self._colIdx[nwOutline.LEVEL], novIdx.level) - newItem.setText(self._colIdx[nwOutline.LABEL], nwItem.itemName) - newItem.setIcon(self._colIdx[nwOutline.LABEL], dIcon) - newItem.setText(self._colIdx[nwOutline.LINE], sTitle[1:].lstrip("0")) - newItem.setData(self._colIdx[nwOutline.LINE], Qt.UserRole, sTitle) - newItem.setText(self._colIdx[nwOutline.SYNOP], novIdx.synopsis) - newItem.setText(self._colIdx[nwOutline.CCOUNT], f"{cC:n}") - newItem.setText(self._colIdx[nwOutline.WCOUNT], f"{wC:n}") - newItem.setText(self._colIdx[nwOutline.PCOUNT], f"{pC:n}") - newItem.setTextAlignment(self._colIdx[nwOutline.CCOUNT], Qt.AlignRight) - newItem.setTextAlignment(self._colIdx[nwOutline.WCOUNT], Qt.AlignRight) - newItem.setTextAlignment(self._colIdx[nwOutline.PCOUNT], Qt.AlignRight) - - theRefs = self.theProject.index.getReferences(tHandle, sTitle) - newItem.setText(self._colIdx[nwOutline.POV], ", ".join(theRefs[nwKeyWords.POV_KEY])) - newItem.setText(self._colIdx[nwOutline.FOCUS], ", ".join(theRefs[nwKeyWords.FOCUS_KEY])) - newItem.setText(self._colIdx[nwOutline.CHAR], ", ".join(theRefs[nwKeyWords.CHAR_KEY])) - newItem.setText(self._colIdx[nwOutline.PLOT], ", ".join(theRefs[nwKeyWords.PLOT_KEY])) - newItem.setText(self._colIdx[nwOutline.TIME], ", ".join(theRefs[nwKeyWords.TIME_KEY])) - newItem.setText(self._colIdx[nwOutline.WORLD], ", ".join(theRefs[nwKeyWords.WORLD_KEY])) - newItem.setText(self._colIdx[nwOutline.OBJECT], ", ".join(theRefs[nwKeyWords.OBJECT_KEY])) - newItem.setText(self._colIdx[nwOutline.ENTITY], ", ".join(theRefs[nwKeyWords.ENTITY_KEY])) - newItem.setText(self._colIdx[nwOutline.CUSTOM], ", ".join(theRefs[nwKeyWords.CUSTOM_KEY])) - - return newItem - # END Class GuiOutlineTree diff --git a/novelwriter/gui/projtree.py b/novelwriter/gui/projtree.py index 13b0b619..acb5e8b4 100644 --- a/novelwriter/gui/projtree.py +++ b/novelwriter/gui/projtree.py @@ -177,7 +177,7 @@ class GuiProjectToolBar(QWidget): self.mainTheme = projView.mainGui.mainTheme iPx = self.mainTheme.baseIconSize - mPx = self.mainConf.pxInt(3) + mPx = self.mainConf.pxInt(2) self.setContentsMargins(0, 0, 0, 0) self.setAutoFillBackground(True)