diff --git a/novelwriter/assets/icons/typicons_dark/icons.conf b/novelwriter/assets/icons/typicons_dark/icons.conf
index 521e9ee8..fa8b8619 100644
--- a/novelwriter/assets/icons/typicons_dark/icons.conf
+++ b/novelwriter/assets/icons/typicons_dark/icons.conf
@@ -21,7 +21,7 @@ backward = typ_chevron-left.svg
bookmark = typ_bookmark.svg
bullet-off = typ_media-record-outline.svg
bullet-on = typ_media-record.svg
-check = typ_tick.svg
+checked = mixed_input-checked.svg
close = typ_times.svg
cls_archive = typ_delete.svg
cls_character = typ_user.svg
@@ -41,13 +41,14 @@ forward = typ_chevron-right.svg
maximise = typ_arrow-maximise.svg
menu = typ_th-menu.svg
minimise = typ_arrow-minimise.svg
+noncheckable = mixed_input-none.svg
proj_chapter = mixed_document-chapter.svg
proj_details = typ_th-list-grey.svg
proj_document = typ_document-text.svg
proj_folder = typ_folder.svg
proj_note = mixed_document-note.svg
-proj_section = mixed_document-section.svg
proj_scene = mixed_document-scene.svg
+proj_section = mixed_document-section.svg
proj_stats = typ_chart-bar-grey.svg
proj_title = mixed_document-title.svg
reference = typ_at.svg
@@ -70,6 +71,7 @@ status_stats = typ_chart-bar-grey.svg
status_time = typ_stopwatch-grey.svg
sticky-off = typ_pin-outline.svg
sticky-on = typ_pin.svg
+unchecked = mixed_input-unchecked.svg
up = typ_chevron-up.svg
view_build = typ_export.svg
view_editor = mixed_edit.svg
diff --git a/novelwriter/assets/icons/typicons_dark/mixed_input-checked.svg b/novelwriter/assets/icons/typicons_dark/mixed_input-checked.svg
new file mode 100644
index 00000000..a044fbaa
--- /dev/null
+++ b/novelwriter/assets/icons/typicons_dark/mixed_input-checked.svg
@@ -0,0 +1,39 @@
+
+
diff --git a/novelwriter/assets/icons/typicons_dark/mixed_input-none.svg b/novelwriter/assets/icons/typicons_dark/mixed_input-none.svg
new file mode 100644
index 00000000..105e1d8f
--- /dev/null
+++ b/novelwriter/assets/icons/typicons_dark/mixed_input-none.svg
@@ -0,0 +1,44 @@
+
+
diff --git a/novelwriter/assets/icons/typicons_dark/mixed_input-unchecked.svg b/novelwriter/assets/icons/typicons_dark/mixed_input-unchecked.svg
new file mode 100644
index 00000000..b5ee8b37
--- /dev/null
+++ b/novelwriter/assets/icons/typicons_dark/mixed_input-unchecked.svg
@@ -0,0 +1,39 @@
+
+
diff --git a/novelwriter/assets/icons/typicons_dark/typ_tick.svg b/novelwriter/assets/icons/typicons_dark/typ_tick.svg
deleted file mode 100644
index 84383114..00000000
--- a/novelwriter/assets/icons/typicons_dark/typ_tick.svg
+++ /dev/null
@@ -1,31 +0,0 @@
-
-
diff --git a/novelwriter/assets/icons/typicons_light/icons.conf b/novelwriter/assets/icons/typicons_light/icons.conf
index 1b6b1348..5212b685 100644
--- a/novelwriter/assets/icons/typicons_light/icons.conf
+++ b/novelwriter/assets/icons/typicons_light/icons.conf
@@ -21,7 +21,7 @@ backward = typ_chevron-left.svg
bookmark = typ_bookmark.svg
bullet-off = typ_media-record-outline.svg
bullet-on = typ_media-record.svg
-check = typ_tick.svg
+checked = mixed_input-checked.svg
close = typ_times.svg
cls_archive = typ_delete.svg
cls_character = typ_user.svg
@@ -41,13 +41,14 @@ forward = typ_chevron-right.svg
maximise = typ_arrow-maximise.svg
menu = typ_th-menu.svg
minimise = typ_arrow-minimise.svg
+noncheckable = mixed_input-none.svg
proj_chapter = mixed_document-chapter.svg
proj_details = typ_th-list-grey.svg
proj_document = typ_document-text.svg
proj_folder = typ_folder.svg
proj_note = mixed_document-note.svg
-proj_section = mixed_document-section.svg
proj_scene = mixed_document-scene.svg
+proj_section = mixed_document-section.svg
proj_stats = typ_chart-bar-grey.svg
proj_title = mixed_document-title.svg
reference = typ_at.svg
@@ -70,6 +71,7 @@ status_stats = typ_chart-bar-grey.svg
status_time = typ_stopwatch-grey.svg
sticky-off = typ_pin-outline.svg
sticky-on = typ_pin.svg
+unchecked = mixed_input-unchecked.svg
up = typ_chevron-up.svg
view_build = typ_export.svg
view_editor = mixed_edit.svg
diff --git a/novelwriter/assets/icons/typicons_light/mixed_input-checked.svg b/novelwriter/assets/icons/typicons_light/mixed_input-checked.svg
new file mode 100644
index 00000000..8e42a8b6
--- /dev/null
+++ b/novelwriter/assets/icons/typicons_light/mixed_input-checked.svg
@@ -0,0 +1,39 @@
+
+
diff --git a/novelwriter/assets/icons/typicons_light/mixed_input-none.svg b/novelwriter/assets/icons/typicons_light/mixed_input-none.svg
new file mode 100644
index 00000000..f80dd7ff
--- /dev/null
+++ b/novelwriter/assets/icons/typicons_light/mixed_input-none.svg
@@ -0,0 +1,44 @@
+
+
diff --git a/novelwriter/assets/icons/typicons_light/mixed_input-unchecked.svg b/novelwriter/assets/icons/typicons_light/mixed_input-unchecked.svg
new file mode 100644
index 00000000..0bd5f6dc
--- /dev/null
+++ b/novelwriter/assets/icons/typicons_light/mixed_input-unchecked.svg
@@ -0,0 +1,39 @@
+
+
diff --git a/novelwriter/assets/icons/typicons_light/typ_tick.svg b/novelwriter/assets/icons/typicons_light/typ_tick.svg
deleted file mode 100644
index 1c24677a..00000000
--- a/novelwriter/assets/icons/typicons_light/typ_tick.svg
+++ /dev/null
@@ -1,31 +0,0 @@
-
-
diff --git a/novelwriter/core/status.py b/novelwriter/core/status.py
index a379f911..c466461e 100644
--- a/novelwriter/core/status.py
+++ b/novelwriter/core/status.py
@@ -30,7 +30,8 @@ import novelwriter
from lxml import etree
-from PyQt5.QtGui import QIcon, QPixmap, QColor
+from PyQt5.QtGui import QIcon, QPainter, QPainterPath, QPixmap, QColor
+from PyQt5.QtCore import QRectF, Qt
from novelwriter.common import checkInt, minmax, simplified
@@ -49,10 +50,15 @@ class NWStatus:
self._reverse = {}
self._default = None
- self._iconSize = novelwriter.CONFIG.pxInt(32)
- pixmap = QPixmap(self._iconSize, self._iconSize)
- pixmap.fill(QColor(100, 100, 100))
- self._defaultIcon = QIcon(pixmap)
+ self._iPX = novelwriter.CONFIG.pxInt(24)
+
+ pA = novelwriter.CONFIG.pxInt(2)
+ pB = novelwriter.CONFIG.pxInt(20)
+ pR = float(novelwriter.CONFIG.pxInt(4))
+ self._iconPath = QPainterPath()
+ self._iconPath.addRoundedRect(QRectF(pA, pA, pB, pB), pR, pR)
+
+ self._defaultIcon = self._createIcon([100, 100, 100])
if self._type == self.STATUS:
self._prefix = "s"
@@ -63,19 +69,16 @@ class NWStatus:
return
- def write(self, key, name, cols, count=None):
+ def write(self, key, name, col, count=None):
"""Add or update a status entry. If the key is invalid, a new
key is generated.
"""
if not self._isKey(key):
key = self._newKey()
- if not isinstance(cols, tuple):
- cols = (100, 100, 100)
- if len(cols) != 3:
- cols = (100, 100, 100)
-
- pixmap = QPixmap(self._iconSize, self._iconSize)
- pixmap.fill(QColor(*cols))
+ if not isinstance(col, tuple):
+ col = (100, 100, 100)
+ if len(col) != 3:
+ col = (100, 100, 100)
name = simplified(name)
if count is None:
@@ -83,8 +86,8 @@ class NWStatus:
self._store[key] = {
"name": name,
- "icon": QIcon(pixmap),
- "cols": cols,
+ "icon": self._createIcon(col),
+ "cols": col,
"count": count,
}
self._reverse[name] = key
@@ -267,6 +270,19 @@ class NWStatus:
return False
return True
+ def _createIcon(self, col):
+ """Generate an icon for a status label.
+ """
+ pixmap = QPixmap(self._iPX, self._iPX)
+ pixmap.fill(Qt.transparent)
+
+ painter = QPainter(pixmap)
+ painter.setRenderHint(QPainter.Antialiasing)
+ painter.fillPath(self._iconPath, QColor(*col))
+ painter.end()
+
+ return QIcon(pixmap)
+
##
# Iterator Bits
##
diff --git a/novelwriter/gui/projtree.py b/novelwriter/gui/projtree.py
index 19d8af38..0055340a 100644
--- a/novelwriter/gui/projtree.py
+++ b/novelwriter/gui/projtree.py
@@ -417,11 +417,15 @@ class GuiProjectToolBar(QWidget):
class GuiProjectTree(QTreeWidget):
+ C_DATA = 0
C_NAME = 0
C_COUNT = 1
C_ACTIVE = 2
C_STATUS = 3
+ D_HANDLE = Qt.UserRole
+ D_WORDS = Qt.UserRole + 1
+
def __init__(self, projView):
super().__init__(parent=projView)
@@ -947,10 +951,13 @@ class GuiProjectTree(QTreeWidget):
trItem.setToolTip(self.C_STATUS, itemStatus)
if nwItem.isFileType():
- iconName = "check" if nwItem.isActive else "cross"
+ iconName = "checked" if nwItem.isActive else "unchecked"
toolTip = self._lblActive if nwItem.isActive else self._lblInactive
- trItem.setIcon(self.C_ACTIVE, self.mainTheme.getIcon(iconName))
trItem.setToolTip(self.C_ACTIVE, toolTip)
+ else:
+ iconName = "noncheckable"
+
+ trItem.setIcon(self.C_ACTIVE, self.mainTheme.getIcon(iconName))
if self.mainConf.emphLabels and nwItem.isDocumentLayout():
trFont = trItem.font(self.C_NAME)
@@ -974,10 +981,10 @@ class GuiProjectTree(QTreeWidget):
if countChildren:
for i in range(tItem.childCount()):
- newCount += int(tItem.child(i).data(self.C_COUNT, Qt.UserRole))
+ newCount += int(tItem.child(i).data(self.C_DATA, self.D_WORDS))
tItem.setText(self.C_COUNT, f"{newCount:n}")
- tItem.setData(self.C_COUNT, Qt.UserRole, int(newCount))
+ tItem.setData(self.C_DATA, self.D_WORDS, int(newCount))
pItem = tItem.parent()
if pItem is None:
@@ -986,8 +993,8 @@ class GuiProjectTree(QTreeWidget):
pCount = 0
pHandle = None
for i in range(pItem.childCount()):
- pCount += int(pItem.child(i).data(self.C_COUNT, Qt.UserRole))
- pHandle = pItem.data(self.C_NAME, Qt.UserRole)
+ pCount += int(pItem.child(i).data(self.C_DATA, self.D_WORDS))
+ pHandle = pItem.data(self.C_DATA, self.D_HANDLE)
if pHandle:
if self.theProject.tree.checkType(pHandle, nwItemType.FILE):
@@ -1038,8 +1045,8 @@ class GuiProjectTree(QTreeWidget):
return False
dstIndex = min(max(0, dstIndex), dstItem.childCount())
- sHandle = srcItem.data(self.C_NAME, Qt.UserRole)
- dHandle = dstItem.data(self.C_NAME, Qt.UserRole)
+ sHandle = srcItem.data(self.C_DATA, self.D_HANDLE)
+ dHandle = dstItem.data(self.C_DATA, self.D_HANDLE)
logger.debug("Moving item '%s' back to '%s', index %d", sHandle, dHandle, dstIndex)
wCount = self._getItemWordCount(sHandle)
@@ -1063,7 +1070,7 @@ class GuiProjectTree(QTreeWidget):
"""
selItem = self.selectedItems()
if selItem:
- return selItem[0].data(self.C_NAME, Qt.UserRole)
+ return selItem[0].data(self.C_DATA, self.D_HANDLE)
return None
@@ -1149,7 +1156,7 @@ class GuiProjectTree(QTreeWidget):
hasChild = False
selItem = self.itemAt(clickPos)
if isinstance(selItem, QTreeWidgetItem):
- tHandle = selItem.data(self.C_NAME, Qt.UserRole)
+ tHandle = selItem.data(self.C_DATA, self.D_HANDLE)
tItem = self.theProject.tree[tHandle]
hasChild = selItem.childCount() > 0
@@ -1308,7 +1315,7 @@ class GuiProjectTree(QTreeWidget):
if not isinstance(selItem, QTreeWidgetItem):
return
- tHandle = selItem.data(self.C_NAME, Qt.UserRole)
+ tHandle = selItem.data(self.C_DATA, self.D_HANDLE)
tItem = self.theProject.tree[tHandle]
if tItem is None:
return
@@ -1367,7 +1374,7 @@ class GuiProjectTree(QTreeWidget):
# Update item parent handle in the project, make sure meta data
# is updated accordingly, and update word count
- pHandle = trItemP.data(self.C_NAME, Qt.UserRole)
+ pHandle = trItemP.data(self.C_DATA, self.D_HANDLE)
nwItemS.setParent(pHandle)
trItemP.setExpanded(True)
logger.debug("The parent of item '%s' has been changed to '%s'", tHandle, pHandle)
@@ -1397,7 +1404,7 @@ class GuiProjectTree(QTreeWidget):
tItem = self._getTreeItem(tHandle)
if tItem is None:
return 0
- return int(tItem.data(self.C_COUNT, Qt.UserRole))
+ return int(tItem.data(self.C_DATA, self.D_WORDS))
def _getTreeItem(self, tHandle):
"""Return the QTreeWidgetItem of a given item handle.
@@ -1617,7 +1624,7 @@ class GuiProjectTree(QTreeWidget):
"""This is a recursive function returning all items in a tree
starting at a given QTreeWidgetItem.
"""
- tHandle = tItem.data(self.C_NAME, Qt.UserRole)
+ tHandle = tItem.data(self.C_DATA, self.D_HANDLE)
cCount = tItem.childCount()
# Update tree-related meta data
@@ -1650,8 +1657,8 @@ class GuiProjectTree(QTreeWidget):
newItem.setTextAlignment(self.C_ACTIVE, Qt.AlignLeft)
newItem.setTextAlignment(self.C_STATUS, Qt.AlignLeft)
- newItem.setData(self.C_NAME, Qt.UserRole, tHandle)
- newItem.setData(self.C_COUNT, Qt.UserRole, 0)
+ newItem.setData(self.C_DATA, self.D_HANDLE, tHandle)
+ newItem.setData(self.C_DATA, self.D_WORDS, 0)
self._treeMap[tHandle] = newItem
if pHandle is None:
diff --git a/novelwriter/gui/theme.py b/novelwriter/gui/theme.py
index 93c26440..570b06b2 100644
--- a/novelwriter/gui/theme.py
+++ b/novelwriter/gui/theme.py
@@ -448,9 +448,9 @@ class GuiIcons:
"view_editor", "view_novel", "view_outline",
# General Button Icons
- "add", "backward", "bookmark", "check", "close", "cross", "down", "edit", "forward",
- "maximise", "menu", "minimise", "reference", "refresh", "remove", "search_replace",
- "search", "settings", "up",
+ "add", "backward", "bookmark", "checked", "close", "cross", "down", "edit", "forward",
+ "maximise", "menu", "minimise", "noncheckable", "reference", "refresh", "remove",
+ "search_replace", "search", "settings", "unchecked", "up",
# Switches
"sticky-on", "sticky-off",
diff --git a/setup.py b/setup.py
index a0bb9b03..675a29c8 100755
--- a/setup.py
+++ b/setup.py
@@ -131,6 +131,7 @@ def makeCheckSum(sumFile, cwd=None):
except Exception as exc:
print("Could not generate sha256 file")
print(str(exc))
+ return ""
return shaFile