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/dialogs/about.py
    CHANGED
    
    | @@ -26,16 +26,16 @@ from __future__ import annotations | |
| 26 26 | 
             
            import logging
         | 
| 27 27 |  | 
| 28 28 | 
             
            from PyQt5.QtGui import QCloseEvent, QColor
         | 
| 29 | 
            -
            from PyQt5.QtCore import Qt
         | 
| 30 29 | 
             
            from PyQt5.QtWidgets import (
         | 
| 31 30 | 
             
                QDialog, QDialogButtonBox, QHBoxLayout, QLabel, QTextBrowser, QVBoxLayout,
         | 
| 32 31 | 
             
                QWidget
         | 
| 33 32 | 
             
            )
         | 
| 34 33 |  | 
| 35 34 | 
             
            from novelwriter import CONFIG, SHARED
         | 
| 36 | 
            -
            from novelwriter.common import readTextFile
         | 
| 35 | 
            +
            from novelwriter.common import cssCol, readTextFile
         | 
| 37 36 | 
             
            from novelwriter.extensions.configlayout import NColourLabel
         | 
| 38 37 | 
             
            from novelwriter.extensions.versioninfo import VersionInfoWidget
         | 
| 38 | 
            +
            from novelwriter.types import QtAlignRightTop, QtDialogClose
         | 
| 39 39 |  | 
| 40 40 | 
             
            logger = logging.getLogger(__name__)
         | 
| 41 41 |  | 
| @@ -70,7 +70,7 @@ class GuiAbout(QDialog): | |
| 70 70 |  | 
| 71 71 | 
             
                    self.nwLicence = QLabel(self.tr("This application is licenced under {0}").format(
         | 
| 72 72 | 
             
                        "<a href='https://www.gnu.org/licenses/gpl-3.0.html'>GPL v3.0</a>"
         | 
| 73 | 
            -
                    ))
         | 
| 73 | 
            +
                    ), self)
         | 
| 74 74 | 
             
                    self.nwLicence.setOpenExternalLinks(True)
         | 
| 75 75 |  | 
| 76 76 | 
             
                    # Credits
         | 
| @@ -84,7 +84,7 @@ class GuiAbout(QDialog): | |
| 84 84 | 
             
                    self.txtCredits.setViewportMargins(0, hA, hA, 0)
         | 
| 85 85 |  | 
| 86 86 | 
             
                    # Buttons
         | 
| 87 | 
            -
                    self.btnBox = QDialogButtonBox( | 
| 87 | 
            +
                    self.btnBox = QDialogButtonBox(QtDialogClose, self)
         | 
| 88 88 | 
             
                    self.btnBox.rejected.connect(self.close)
         | 
| 89 89 |  | 
| 90 90 | 
             
                    # Assemble
         | 
| @@ -100,10 +100,8 @@ class GuiAbout(QDialog): | |
| 100 100 | 
             
                    self.innerBox.addSpacing(hB)
         | 
| 101 101 | 
             
                    self.innerBox.addWidget(self.btnBox)
         | 
| 102 102 |  | 
| 103 | 
            -
                    topRight = Qt.AlignmentFlag.AlignTop | Qt.AlignmentFlag.AlignRight
         | 
| 104 | 
            -
             | 
| 105 103 | 
             
                    self.outerBox = QHBoxLayout()
         | 
| 106 | 
            -
                    self.outerBox.addWidget(self.nwLogo, 0,  | 
| 104 | 
            +
                    self.outerBox.addWidget(self.nwLogo, 0, QtAlignRightTop)
         | 
| 107 105 | 
             
                    self.outerBox.addLayout(self.innerBox, 1)
         | 
| 108 106 |  | 
| 109 107 | 
             
                    self.setLayout(self.outerBox)
         | 
| @@ -149,10 +147,10 @@ class GuiAbout(QDialog): | |
| 149 147 |  | 
| 150 148 | 
             
                def _setStyleSheet(self) -> None:
         | 
| 151 149 | 
             
                    """Set stylesheet for all browser tabs."""
         | 
| 152 | 
            -
                    baseCol = self.palette().window().color()
         | 
| 153 | 
            -
                    self.txtCredits.setStyleSheet( | 
| 154 | 
            -
                        "QTextBrowser {{border: none; background:  | 
| 155 | 
            -
                    ) | 
| 150 | 
            +
                    baseCol = cssCol(self.palette().window().color())
         | 
| 151 | 
            +
                    self.txtCredits.setStyleSheet(
         | 
| 152 | 
            +
                        f"QTextBrowser {{border: none; background: {baseCol};}} "
         | 
| 153 | 
            +
                    )
         | 
| 156 154 | 
             
                    return
         | 
| 157 155 |  | 
| 158 156 | 
             
            # END Class GuiAbout
         | 
    
        novelwriter/dialogs/docmerge.py
    CHANGED
    
    | @@ -26,8 +26,8 @@ from __future__ import annotations | |
| 26 26 |  | 
| 27 27 | 
             
            import logging
         | 
| 28 28 |  | 
| 29 | 
            +
            from PyQt5.QtCore import Qt, pyqtSlot
         | 
| 29 30 | 
             
            from PyQt5.QtGui import QCloseEvent
         | 
| 30 | 
            -
            from PyQt5.QtCore import Qt, QSize, pyqtSlot
         | 
| 31 31 | 
             
            from PyQt5.QtWidgets import (
         | 
| 32 32 | 
             
                QAbstractItemView, QDialog, QDialogButtonBox, QGridLayout, QLabel,
         | 
| 33 33 | 
             
                QListWidget, QListWidgetItem, QVBoxLayout, QWidget
         | 
| @@ -36,13 +36,14 @@ from PyQt5.QtWidgets import ( | |
| 36 36 | 
             
            from novelwriter import CONFIG, SHARED
         | 
| 37 37 | 
             
            from novelwriter.extensions.switch import NSwitch
         | 
| 38 38 | 
             
            from novelwriter.extensions.configlayout import NColourLabel
         | 
| 39 | 
            +
            from novelwriter.types import QtDialogCancel, QtDialogOk, QtDialogReset, QtUserRole
         | 
| 39 40 |  | 
| 40 41 | 
             
            logger = logging.getLogger(__name__)
         | 
| 41 42 |  | 
| 42 43 |  | 
| 43 44 | 
             
            class GuiDocMerge(QDialog):
         | 
| 44 45 |  | 
| 45 | 
            -
                D_HANDLE =  | 
| 46 | 
            +
                D_HANDLE = QtUserRole
         | 
| 46 47 |  | 
| 47 48 | 
             
                def __init__(self, parent: QWidget, sHandle: str, itemList: list[str]) -> None:
         | 
| 48 49 | 
             
                    super().__init__(parent=parent)
         | 
| @@ -53,27 +54,29 @@ class GuiDocMerge(QDialog): | |
| 53 54 |  | 
| 54 55 | 
             
                    self._data = {}
         | 
| 55 56 |  | 
| 56 | 
            -
                    self.headLabel = QLabel( | 
| 57 | 
            +
                    self.headLabel = QLabel(self.tr("Documents to Merge"), self)
         | 
| 58 | 
            +
                    self.headLabel.setFont(SHARED.theme.guiFontB)
         | 
| 57 59 | 
             
                    self.helpLabel = NColourLabel(
         | 
| 58 60 | 
             
                        self.tr("Drag and drop items to change the order, or uncheck to exclude."),
         | 
| 59 61 | 
             
                        SHARED.theme.helpText, parent=self, wrap=True
         | 
| 60 62 | 
             
                    )
         | 
| 61 63 |  | 
| 62 | 
            -
                    iPx = SHARED.theme. | 
| 64 | 
            +
                    iPx = SHARED.theme.baseIconHeight
         | 
| 65 | 
            +
                    iSz = SHARED.theme.baseIconSize
         | 
| 63 66 | 
             
                    hSp = CONFIG.pxInt(12)
         | 
| 64 67 | 
             
                    vSp = CONFIG.pxInt(8)
         | 
| 65 68 | 
             
                    bSp = CONFIG.pxInt(12)
         | 
| 66 69 |  | 
| 67 | 
            -
                    self.listBox = QListWidget()
         | 
| 68 | 
            -
                    self.listBox.setIconSize( | 
| 70 | 
            +
                    self.listBox = QListWidget(self)
         | 
| 71 | 
            +
                    self.listBox.setIconSize(iSz)
         | 
| 69 72 | 
             
                    self.listBox.setMinimumWidth(CONFIG.pxInt(400))
         | 
| 70 73 | 
             
                    self.listBox.setMinimumHeight(CONFIG.pxInt(180))
         | 
| 71 | 
            -
                    self.listBox.setSelectionBehavior(QAbstractItemView.SelectRows)
         | 
| 72 | 
            -
                    self.listBox.setSelectionMode(QAbstractItemView.SingleSelection)
         | 
| 73 | 
            -
                    self.listBox.setDragDropMode(QAbstractItemView.InternalMove)
         | 
| 74 | 
            +
                    self.listBox.setSelectionBehavior(QAbstractItemView.SelectionBehavior.SelectRows)
         | 
| 75 | 
            +
                    self.listBox.setSelectionMode(QAbstractItemView.SelectionMode.SingleSelection)
         | 
| 76 | 
            +
                    self.listBox.setDragDropMode(QAbstractItemView.DragDropMode.InternalMove)
         | 
| 74 77 |  | 
| 75 78 | 
             
                    # Merge Options
         | 
| 76 | 
            -
                    self.trashLabel = QLabel(self.tr("Move merged items to Trash"))
         | 
| 79 | 
            +
                    self.trashLabel = QLabel(self.tr("Move merged items to Trash"), self)
         | 
| 77 80 | 
             
                    self.trashSwitch = NSwitch(self, height=iPx)
         | 
| 78 81 |  | 
| 79 82 | 
             
                    self.optBox = QGridLayout()
         | 
| @@ -83,11 +86,11 @@ class GuiDocMerge(QDialog): | |
| 83 86 | 
             
                    self.optBox.setColumnStretch(2, 1)
         | 
| 84 87 |  | 
| 85 88 | 
             
                    # Buttons
         | 
| 86 | 
            -
                    self.buttonBox = QDialogButtonBox( | 
| 89 | 
            +
                    self.buttonBox = QDialogButtonBox(QtDialogOk | QtDialogCancel, self)
         | 
| 87 90 | 
             
                    self.buttonBox.accepted.connect(self.accept)
         | 
| 88 91 | 
             
                    self.buttonBox.rejected.connect(self.reject)
         | 
| 89 92 |  | 
| 90 | 
            -
                    self.resetButton = self.buttonBox.addButton( | 
| 93 | 
            +
                    self.resetButton = self.buttonBox.addButton(QtDialogReset)
         | 
| 91 94 | 
             
                    self.resetButton.clicked.connect(self._resetList)
         | 
| 92 95 |  | 
| 93 96 | 
             
                    # Assemble
         | 
| @@ -119,7 +122,7 @@ class GuiDocMerge(QDialog): | |
| 119 122 | 
             
                    finalItems = []
         | 
| 120 123 | 
             
                    for i in range(self.listBox.count()):
         | 
| 121 124 | 
             
                        item = self.listBox.item(i)
         | 
| 122 | 
            -
                        if item is not None and item.checkState() == Qt.Checked:
         | 
| 125 | 
            +
                        if item is not None and item.checkState() == Qt.CheckState.Checked:
         | 
| 123 126 | 
             
                            finalItems.append(item.data(self.D_HANDLE))
         | 
| 124 127 |  | 
| 125 128 | 
             
                    self._data["moveToTrash"] = self.trashSwitch.isChecked()
         | 
| @@ -174,7 +177,7 @@ class GuiDocMerge(QDialog): | |
| 174 177 | 
             
                        newItem.setIcon(itemIcon)
         | 
| 175 178 | 
             
                        newItem.setText(nwItem.itemName)
         | 
| 176 179 | 
             
                        newItem.setData(self.D_HANDLE, tHandle)
         | 
| 177 | 
            -
                        newItem.setCheckState(Qt.Checked)
         | 
| 180 | 
            +
                        newItem.setCheckState(Qt.CheckState.Checked)
         | 
| 178 181 |  | 
| 179 182 | 
             
                        self.listBox.addItem(newItem)
         | 
| 180 183 |  | 
    
        novelwriter/dialogs/docsplit.py
    CHANGED
    
    | @@ -26,8 +26,8 @@ from __future__ import annotations | |
| 26 26 |  | 
| 27 27 | 
             
            import logging
         | 
| 28 28 |  | 
| 29 | 
            +
            from PyQt5.QtCore import pyqtSlot
         | 
| 29 30 | 
             
            from PyQt5.QtGui import QCloseEvent
         | 
| 30 | 
            -
            from PyQt5.QtCore import Qt, pyqtSlot
         | 
| 31 31 | 
             
            from PyQt5.QtWidgets import (
         | 
| 32 32 | 
             
                QAbstractItemView, QComboBox, QDialog, QDialogButtonBox, QGridLayout,
         | 
| 33 33 | 
             
                QLabel, QListWidget, QListWidgetItem, QVBoxLayout, QWidget
         | 
| @@ -36,15 +36,16 @@ from PyQt5.QtWidgets import ( | |
| 36 36 | 
             
            from novelwriter import CONFIG, SHARED
         | 
| 37 37 | 
             
            from novelwriter.extensions.switch import NSwitch
         | 
| 38 38 | 
             
            from novelwriter.extensions.configlayout import NColourLabel
         | 
| 39 | 
            +
            from novelwriter.types import QtDialogCancel, QtDialogOk, QtUserRole
         | 
| 39 40 |  | 
| 40 41 | 
             
            logger = logging.getLogger(__name__)
         | 
| 41 42 |  | 
| 42 43 |  | 
| 43 44 | 
             
            class GuiDocSplit(QDialog):
         | 
| 44 45 |  | 
| 45 | 
            -
                LINE_ROLE  =  | 
| 46 | 
            -
                LEVEL_ROLE =  | 
| 47 | 
            -
                LABEL_ROLE =  | 
| 46 | 
            +
                LINE_ROLE  = QtUserRole
         | 
| 47 | 
            +
                LEVEL_ROLE = QtUserRole + 1
         | 
| 48 | 
            +
                LABEL_ROLE = QtUserRole + 2
         | 
| 48 49 |  | 
| 49 50 | 
             
                def __init__(self, parent: QWidget, sHandle: str) -> None:
         | 
| 50 51 | 
             
                    super().__init__(parent=parent)
         | 
| @@ -57,14 +58,15 @@ class GuiDocSplit(QDialog): | |
| 57 58 |  | 
| 58 59 | 
             
                    self.setWindowTitle(self.tr("Split Document"))
         | 
| 59 60 |  | 
| 60 | 
            -
                    self.headLabel = QLabel( | 
| 61 | 
            +
                    self.headLabel = QLabel(self.tr("Document Headings"), self)
         | 
| 62 | 
            +
                    self.headLabel.setFont(SHARED.theme.guiFontB)
         | 
| 61 63 | 
             
                    self.helpLabel = NColourLabel(
         | 
| 62 64 | 
             
                        self.tr("Select the maximum level to split into files."),
         | 
| 63 65 | 
             
                        SHARED.theme.helpText, parent=self, wrap=True
         | 
| 64 66 | 
             
                    )
         | 
| 65 67 |  | 
| 66 68 | 
             
                    # Values
         | 
| 67 | 
            -
                    iPx = SHARED.theme. | 
| 69 | 
            +
                    iPx = SHARED.theme.baseIconHeight
         | 
| 68 70 | 
             
                    hSp = CONFIG.pxInt(12)
         | 
| 69 71 | 
             
                    vSp = CONFIG.pxInt(8)
         | 
| 70 72 | 
             
                    bSp = CONFIG.pxInt(12)
         | 
| @@ -75,8 +77,8 @@ class GuiDocSplit(QDialog): | |
| 75 77 | 
             
                    docHierarchy = pOptions.getBool("GuiDocSplit", "docHierarchy", True)
         | 
| 76 78 |  | 
| 77 79 | 
             
                    # Heading Selection
         | 
| 78 | 
            -
                    self.listBox = QListWidget()
         | 
| 79 | 
            -
                    self.listBox.setDragDropMode(QAbstractItemView.NoDragDrop)
         | 
| 80 | 
            +
                    self.listBox = QListWidget(self)
         | 
| 81 | 
            +
                    self.listBox.setDragDropMode(QAbstractItemView.DragDropMode.NoDragDrop)
         | 
| 80 82 | 
             
                    self.listBox.setMinimumWidth(CONFIG.pxInt(400))
         | 
| 81 83 | 
             
                    self.listBox.setMinimumHeight(CONFIG.pxInt(180))
         | 
| 82 84 |  | 
| @@ -91,15 +93,15 @@ class GuiDocSplit(QDialog): | |
| 91 93 | 
             
                    self.splitLevel.currentIndexChanged.connect(self._reloadList)
         | 
| 92 94 |  | 
| 93 95 | 
             
                    # Split Options
         | 
| 94 | 
            -
                    self.folderLabel = QLabel(self.tr("Split into a new folder"))
         | 
| 96 | 
            +
                    self.folderLabel = QLabel(self.tr("Split into a new folder"), self)
         | 
| 95 97 | 
             
                    self.folderSwitch = NSwitch(self, height=iPx)
         | 
| 96 98 | 
             
                    self.folderSwitch.setChecked(intoFolder)
         | 
| 97 99 |  | 
| 98 | 
            -
                    self.hierarchyLabel = QLabel(self.tr("Create document hierarchy"))
         | 
| 100 | 
            +
                    self.hierarchyLabel = QLabel(self.tr("Create document hierarchy"), self)
         | 
| 99 101 | 
             
                    self.hierarchySwitch = NSwitch(self, height=iPx)
         | 
| 100 102 | 
             
                    self.hierarchySwitch.setChecked(docHierarchy)
         | 
| 101 103 |  | 
| 102 | 
            -
                    self.trashLabel = QLabel(self.tr("Move split document to Trash"))
         | 
| 104 | 
            +
                    self.trashLabel = QLabel(self.tr("Move split document to Trash"), self)
         | 
| 103 105 | 
             
                    self.trashSwitch = NSwitch(self, height=iPx)
         | 
| 104 106 |  | 
| 105 107 | 
             
                    self.optBox = QGridLayout()
         | 
| @@ -114,7 +116,7 @@ class GuiDocSplit(QDialog): | |
| 114 116 | 
             
                    self.optBox.setColumnStretch(3, 1)
         | 
| 115 117 |  | 
| 116 118 | 
             
                    # Buttons
         | 
| 117 | 
            -
                    self.buttonBox = QDialogButtonBox( | 
| 119 | 
            +
                    self.buttonBox = QDialogButtonBox(QtDialogOk | QtDialogCancel, self)
         | 
| 118 120 | 
             
                    self.buttonBox.accepted.connect(self.accept)
         | 
| 119 121 | 
             
                    self.buttonBox.rejected.connect(self.reject)
         | 
| 120 122 |  | 
    
        novelwriter/dialogs/editlabel.py
    CHANGED
    
    | @@ -31,6 +31,7 @@ from PyQt5.QtWidgets import ( | |
| 31 31 | 
             
            )
         | 
| 32 32 |  | 
| 33 33 | 
             
            from novelwriter import CONFIG
         | 
| 34 | 
            +
            from novelwriter.types import QtDialogCancel, QtDialogOk
         | 
| 34 35 |  | 
| 35 36 | 
             
            logger = logging.getLogger(__name__)
         | 
| 36 37 |  | 
| @@ -55,13 +56,13 @@ class GuiEditLabel(QDialog): | |
| 55 56 | 
             
                    self.labelValue.selectAll()
         | 
| 56 57 |  | 
| 57 58 | 
             
                    # Buttons
         | 
| 58 | 
            -
                    self.buttonBox = QDialogButtonBox( | 
| 59 | 
            +
                    self.buttonBox = QDialogButtonBox(QtDialogOk | QtDialogCancel, self)
         | 
| 59 60 | 
             
                    self.buttonBox.accepted.connect(self.accept)
         | 
| 60 61 | 
             
                    self.buttonBox.rejected.connect(self.reject)
         | 
| 61 62 |  | 
| 62 63 | 
             
                    # Assemble
         | 
| 63 64 | 
             
                    self.innerBox = QHBoxLayout()
         | 
| 64 | 
            -
                    self.innerBox.addWidget(QLabel(self.tr("Label")), 0)
         | 
| 65 | 
            +
                    self.innerBox.addWidget(QLabel(self.tr("Label"), self), 0)
         | 
| 65 66 | 
             
                    self.innerBox.addWidget(self.labelValue, 1)
         | 
| 66 67 | 
             
                    self.innerBox.setSpacing(mSp)
         | 
| 67 68 |  | 
| @@ -88,9 +89,9 @@ class GuiEditLabel(QDialog): | |
| 88 89 | 
             
                def getLabel(cls, parent: QWidget, text: str) -> tuple[str, bool]:
         | 
| 89 90 | 
             
                    """Pop the dialog and return the result."""
         | 
| 90 91 | 
             
                    cls = GuiEditLabel(parent, text=text)
         | 
| 91 | 
            -
                    cls. | 
| 92 | 
            +
                    cls.exec()
         | 
| 92 93 | 
             
                    label = cls.itemLabel
         | 
| 93 | 
            -
                    accepted = cls.result() == QDialog.Accepted
         | 
| 94 | 
            +
                    accepted = cls.result() == QDialog.DialogCode.Accepted
         | 
| 94 95 | 
             
                    cls.deleteLater()
         | 
| 95 96 | 
             
                    return label, accepted
         | 
| 96 97 |  | 
| @@ -26,21 +26,25 @@ from __future__ import annotations | |
| 26 26 |  | 
| 27 27 | 
             
            import logging
         | 
| 28 28 |  | 
| 29 | 
            -
            from PyQt5.QtGui import QCloseEvent, QFont, QKeyEvent, QKeySequence
         | 
| 30 29 | 
             
            from PyQt5.QtCore import Qt, pyqtSignal, pyqtSlot
         | 
| 30 | 
            +
            from PyQt5.QtGui import QCloseEvent, QFont, QKeyEvent, QKeySequence
         | 
| 31 31 | 
             
            from PyQt5.QtWidgets import (
         | 
| 32 | 
            -
                QAbstractButton, QCompleter, QDialog, QDialogButtonBox, | 
| 33 | 
            -
                QFontDialog, QHBoxLayout, QLineEdit, QPushButton,  | 
| 34 | 
            -
                QWidget | 
| 32 | 
            +
                QAbstractButton, QApplication, QCompleter, QDialog, QDialogButtonBox,
         | 
| 33 | 
            +
                QFileDialog, QFontDialog, QHBoxLayout, QLineEdit, QPushButton, QVBoxLayout,
         | 
| 34 | 
            +
                QWidget
         | 
| 35 35 | 
             
            )
         | 
| 36 36 |  | 
| 37 37 | 
             
            from novelwriter import CONFIG, SHARED
         | 
| 38 38 | 
             
            from novelwriter.constants import nwConst, nwUnicode
         | 
| 39 39 | 
             
            from novelwriter.dialogs.quotes import GuiQuoteSelect
         | 
| 40 | 
            -
            from novelwriter.extensions.switch import NSwitch
         | 
| 41 | 
            -
            from novelwriter.extensions.modified import NComboBox, NDoubleSpinBox, NSpinBox
         | 
| 42 40 | 
             
            from novelwriter.extensions.configlayout import NColourLabel, NScrollableForm
         | 
| 41 | 
            +
            from novelwriter.extensions.modified import NComboBox, NDoubleSpinBox, NIconToolButton, NSpinBox
         | 
| 43 42 | 
             
            from novelwriter.extensions.pagedsidebar import NPagedSideBar
         | 
| 43 | 
            +
            from novelwriter.extensions.switch import NSwitch
         | 
| 44 | 
            +
            from novelwriter.types import (
         | 
| 45 | 
            +
                QtAlignCenter, QtDialogApply, QtDialogClose, QtDialogSave, QtRoleAccept,
         | 
| 46 | 
            +
                QtRoleApply, QtRoleReject
         | 
| 47 | 
            +
            )
         | 
| 44 48 |  | 
| 45 49 | 
             
            logger = logging.getLogger(__name__)
         | 
| 46 50 |  | 
| @@ -83,11 +87,7 @@ class GuiPreferences(QDialog): | |
| 83 87 | 
             
                    self.mainForm.setHelpTextStyle(SHARED.theme.helpText)
         | 
| 84 88 |  | 
| 85 89 | 
             
                    # Buttons
         | 
| 86 | 
            -
                    self.buttonBox = QDialogButtonBox(
         | 
| 87 | 
            -
                        QDialogButtonBox.StandardButton.Apply
         | 
| 88 | 
            -
                        | QDialogButtonBox.StandardButton.Save
         | 
| 89 | 
            -
                        | QDialogButtonBox.StandardButton.Close
         | 
| 90 | 
            -
                    )
         | 
| 90 | 
            +
                    self.buttonBox = QDialogButtonBox(QtDialogApply | QtDialogSave | QtDialogClose, self)
         | 
| 91 91 | 
             
                    self.buttonBox.clicked.connect(self._dialogButtonClicked)
         | 
| 92 92 |  | 
| 93 93 | 
             
                    # Assemble
         | 
| @@ -132,8 +132,8 @@ class GuiPreferences(QDialog): | |
| 132 132 | 
             
                def buildForm(self) -> None:
         | 
| 133 133 | 
             
                    """Build the settings form."""
         | 
| 134 134 | 
             
                    section = 0
         | 
| 135 | 
            +
                    iSz = SHARED.theme.baseIconSize
         | 
| 135 136 | 
             
                    minWidth = CONFIG.pxInt(200)
         | 
| 136 | 
            -
                    mIcon = SHARED.theme.getIcon("more")
         | 
| 137 137 |  | 
| 138 138 | 
             
                    # Label
         | 
| 139 139 | 
             
                    self.sidebar.addLabel(self.tr("General"))
         | 
| @@ -175,8 +175,7 @@ class GuiPreferences(QDialog): | |
| 175 175 | 
             
                    self.guiFont.setReadOnly(True)
         | 
| 176 176 | 
             
                    self.guiFont.setMinimumWidth(CONFIG.pxInt(162))
         | 
| 177 177 | 
             
                    self.guiFont.setText(CONFIG.guiFont)
         | 
| 178 | 
            -
                    self.guiFontButton =  | 
| 179 | 
            -
                    self.guiFontButton.setIcon(mIcon)
         | 
| 178 | 
            +
                    self.guiFontButton = NIconToolButton(self, iSz, "more")
         | 
| 180 179 | 
             
                    self.guiFontButton.clicked.connect(self._selectGuiFont)
         | 
| 181 180 | 
             
                    self.mainForm.addRow(
         | 
| 182 181 | 
             
                        self.tr("Application font family"), self.guiFont,
         | 
| @@ -236,8 +235,7 @@ class GuiPreferences(QDialog): | |
| 236 235 | 
             
                    self.textFont.setReadOnly(True)
         | 
| 237 236 | 
             
                    self.textFont.setMinimumWidth(CONFIG.pxInt(162))
         | 
| 238 237 | 
             
                    self.textFont.setText(CONFIG.textFont)
         | 
| 239 | 
            -
                    self.textFontButton =  | 
| 240 | 
            -
                    self.textFontButton.setIcon(mIcon)
         | 
| 238 | 
            +
                    self.textFontButton = NIconToolButton(self, iSz, "more")
         | 
| 241 239 | 
             
                    self.textFontButton.clicked.connect(self._selectTextFont)
         | 
| 242 240 | 
             
                    self.mainForm.addRow(
         | 
| 243 241 | 
             
                        self.tr("Document font family"), self.textFont,
         | 
| @@ -320,6 +318,7 @@ class GuiPreferences(QDialog): | |
| 320 318 | 
             
                    # Backup Path
         | 
| 321 319 | 
             
                    self.backupPath = CONFIG.backupPath()
         | 
| 322 320 | 
             
                    self.backupGetPath = QPushButton(SHARED.theme.getIcon("browse"), self.tr("Browse"), self)
         | 
| 321 | 
            +
                    self.backupGetPath.setIconSize(iSz)
         | 
| 323 322 | 
             
                    self.backupGetPath.clicked.connect(self._backupFolder)
         | 
| 324 323 | 
             
                    self.mainForm.addRow(
         | 
| 325 324 | 
             
                        self.tr("Backup storage location"), self.backupGetPath,
         | 
| @@ -675,10 +674,9 @@ class GuiPreferences(QDialog): | |
| 675 674 | 
             
                    self.quoteSym["SO"].setMaxLength(1)
         | 
| 676 675 | 
             
                    self.quoteSym["SO"].setReadOnly(True)
         | 
| 677 676 | 
             
                    self.quoteSym["SO"].setFixedWidth(qWidth)
         | 
| 678 | 
            -
                    self.quoteSym["SO"].setAlignment( | 
| 677 | 
            +
                    self.quoteSym["SO"].setAlignment(QtAlignCenter)
         | 
| 679 678 | 
             
                    self.quoteSym["SO"].setText(CONFIG.fmtSQuoteOpen)
         | 
| 680 | 
            -
                    self.btnSingleStyleO =  | 
| 681 | 
            -
                    self.btnSingleStyleO.setIcon(mIcon)
         | 
| 679 | 
            +
                    self.btnSingleStyleO = NIconToolButton(self, iSz, "more")
         | 
| 682 680 | 
             
                    self.btnSingleStyleO.clicked.connect(lambda: self._getQuote("SO"))
         | 
| 683 681 | 
             
                    self.mainForm.addRow(
         | 
| 684 682 | 
             
                        self.tr("Single quote open style"), self.quoteSym["SO"],
         | 
| @@ -690,10 +688,9 @@ class GuiPreferences(QDialog): | |
| 690 688 | 
             
                    self.quoteSym["SC"].setMaxLength(1)
         | 
| 691 689 | 
             
                    self.quoteSym["SC"].setReadOnly(True)
         | 
| 692 690 | 
             
                    self.quoteSym["SC"].setFixedWidth(qWidth)
         | 
| 693 | 
            -
                    self.quoteSym["SC"].setAlignment( | 
| 691 | 
            +
                    self.quoteSym["SC"].setAlignment(QtAlignCenter)
         | 
| 694 692 | 
             
                    self.quoteSym["SC"].setText(CONFIG.fmtSQuoteClose)
         | 
| 695 | 
            -
                    self.btnSingleStyleC =  | 
| 696 | 
            -
                    self.btnSingleStyleC.setIcon(mIcon)
         | 
| 693 | 
            +
                    self.btnSingleStyleC = NIconToolButton(self, iSz, "more")
         | 
| 697 694 | 
             
                    self.btnSingleStyleC.clicked.connect(lambda: self._getQuote("SC"))
         | 
| 698 695 | 
             
                    self.mainForm.addRow(
         | 
| 699 696 | 
             
                        self.tr("Single quote close style"), self.quoteSym["SC"],
         | 
| @@ -706,10 +703,9 @@ class GuiPreferences(QDialog): | |
| 706 703 | 
             
                    self.quoteSym["DO"].setMaxLength(1)
         | 
| 707 704 | 
             
                    self.quoteSym["DO"].setReadOnly(True)
         | 
| 708 705 | 
             
                    self.quoteSym["DO"].setFixedWidth(qWidth)
         | 
| 709 | 
            -
                    self.quoteSym["DO"].setAlignment( | 
| 706 | 
            +
                    self.quoteSym["DO"].setAlignment(QtAlignCenter)
         | 
| 710 707 | 
             
                    self.quoteSym["DO"].setText(CONFIG.fmtDQuoteOpen)
         | 
| 711 | 
            -
                    self.btnDoubleStyleO =  | 
| 712 | 
            -
                    self.btnDoubleStyleO.setIcon(mIcon)
         | 
| 708 | 
            +
                    self.btnDoubleStyleO = NIconToolButton(self, iSz, "more")
         | 
| 713 709 | 
             
                    self.btnDoubleStyleO.clicked.connect(lambda: self._getQuote("DO"))
         | 
| 714 710 | 
             
                    self.mainForm.addRow(
         | 
| 715 711 | 
             
                        self.tr("Double quote open style"), self.quoteSym["DO"],
         | 
| @@ -721,10 +717,9 @@ class GuiPreferences(QDialog): | |
| 721 717 | 
             
                    self.quoteSym["DC"].setMaxLength(1)
         | 
| 722 718 | 
             
                    self.quoteSym["DC"].setReadOnly(True)
         | 
| 723 719 | 
             
                    self.quoteSym["DC"].setFixedWidth(qWidth)
         | 
| 724 | 
            -
                    self.quoteSym["DC"].setAlignment( | 
| 720 | 
            +
                    self.quoteSym["DC"].setAlignment(QtAlignCenter)
         | 
| 725 721 | 
             
                    self.quoteSym["DC"].setText(CONFIG.fmtDQuoteClose)
         | 
| 726 | 
            -
                    self.btnDoubleStyleC =  | 
| 727 | 
            -
                    self.btnDoubleStyleC.setIcon(mIcon)
         | 
| 722 | 
            +
                    self.btnDoubleStyleC = NIconToolButton(self, iSz, "more")
         | 
| 728 723 | 
             
                    self.btnDoubleStyleC.clicked.connect(lambda: self._getQuote("DC"))
         | 
| 729 724 | 
             
                    self.mainForm.addRow(
         | 
| 730 725 | 
             
                        self.tr("Double quote close style"), self.quoteSym["DC"],
         | 
| @@ -746,7 +741,7 @@ class GuiPreferences(QDialog): | |
| 746 741 | 
             
                    logger.debug("Close: GuiPreferences")
         | 
| 747 742 | 
             
                    self._saveWindowSize()
         | 
| 748 743 | 
             
                    event.accept()
         | 
| 749 | 
            -
                     | 
| 744 | 
            +
                    QApplication.processEvents()
         | 
| 750 745 | 
             
                    self.done(nwConst.DLG_FINISHED)
         | 
| 751 746 | 
             
                    self.deleteLater()
         | 
| 752 747 | 
             
                    return
         | 
| @@ -766,12 +761,12 @@ class GuiPreferences(QDialog): | |
| 766 761 | 
             
                def _dialogButtonClicked(self, button: QAbstractButton) -> None:
         | 
| 767 762 | 
             
                    """Handle button clicks from the dialog button box."""
         | 
| 768 763 | 
             
                    role = self.buttonBox.buttonRole(button)
         | 
| 769 | 
            -
                    if role ==  | 
| 764 | 
            +
                    if role == QtRoleApply:
         | 
| 770 765 | 
             
                        self._saveValues()
         | 
| 771 | 
            -
                    elif role ==  | 
| 766 | 
            +
                    elif role == QtRoleAccept:
         | 
| 772 767 | 
             
                        self._saveValues()
         | 
| 773 768 | 
             
                        self.close()
         | 
| 774 | 
            -
                    elif role ==  | 
| 769 | 
            +
                    elif role == QtRoleReject:
         | 
| 775 770 | 
             
                        self.close()
         | 
| 776 771 | 
             
                    return
         | 
| 777 772 |  | 
| @@ -816,7 +811,7 @@ class GuiPreferences(QDialog): | |
| 816 811 | 
             
                    """Open a dialog to select the backup folder."""
         | 
| 817 812 | 
             
                    if path := QFileDialog.getExistingDirectory(
         | 
| 818 813 | 
             
                        self, self.tr("Backup Directory"), str(self.backupPath) or "",
         | 
| 819 | 
            -
                        options=QFileDialog.ShowDirsOnly
         | 
| 814 | 
            +
                        options=QFileDialog.Option.ShowDirsOnly
         | 
| 820 815 | 
             
                    ):
         | 
| 821 816 | 
             
                        self.backupPath = path
         | 
| 822 817 | 
             
                        self.mainForm.setHelpText("backupPath", self.tr("Path: {0}").format(path))
         | 
| @@ -26,20 +26,21 @@ from __future__ import annotations | |
| 26 26 |  | 
| 27 27 | 
             
            import logging
         | 
| 28 28 |  | 
| 29 | 
            -
            from PyQt5.QtGui import QCloseEvent, QColor, QIcon, QPixmap
         | 
| 30 29 | 
             
            from PyQt5.QtCore import Qt, pyqtSignal, pyqtSlot
         | 
| 30 | 
            +
            from PyQt5.QtGui import QCloseEvent, QColor, QIcon, QPixmap
         | 
| 31 31 | 
             
            from PyQt5.QtWidgets import (
         | 
| 32 | 
            -
                QColorDialog, QDialog, QDialogButtonBox, QHBoxLayout, | 
| 33 | 
            -
                QPushButton, QStackedWidget, QTreeWidget, QTreeWidgetItem, | 
| 34 | 
            -
                 | 
| 32 | 
            +
                QApplication, QColorDialog, QDialog, QDialogButtonBox, QHBoxLayout,
         | 
| 33 | 
            +
                QLineEdit, QPushButton, QStackedWidget, QTreeWidget, QTreeWidgetItem,
         | 
| 34 | 
            +
                QVBoxLayout, QWidget
         | 
| 35 35 | 
             
            )
         | 
| 36 36 |  | 
| 37 37 | 
             
            from novelwriter import CONFIG, SHARED
         | 
| 38 38 | 
             
            from novelwriter.common import simplified
         | 
| 39 | 
            -
            from novelwriter.extensions.switch import NSwitch
         | 
| 40 | 
            -
            from novelwriter.extensions.modified import NComboBox
         | 
| 41 39 | 
             
            from novelwriter.extensions.configlayout import NColourLabel, NFixedPage, NScrollableForm
         | 
| 40 | 
            +
            from novelwriter.extensions.modified import NComboBox, NIconToolButton
         | 
| 42 41 | 
             
            from novelwriter.extensions.pagedsidebar import NPagedSideBar
         | 
| 42 | 
            +
            from novelwriter.extensions.switch import NSwitch
         | 
| 43 | 
            +
            from novelwriter.types import QtDialogCancel, QtDialogSave, QtUserRole
         | 
| 43 44 |  | 
| 44 45 | 
             
            logger = logging.getLogger(__name__)
         | 
| 45 46 |  | 
| @@ -83,9 +84,7 @@ class GuiProjectSettings(QDialog): | |
| 83 84 | 
             
                    self.sidebar.buttonClicked.connect(self._sidebarClicked)
         | 
| 84 85 |  | 
| 85 86 | 
             
                    # Buttons
         | 
| 86 | 
            -
                    self.buttonBox = QDialogButtonBox(
         | 
| 87 | 
            -
                        QDialogButtonBox.StandardButton.Save | QDialogButtonBox.StandardButton.Cancel
         | 
| 88 | 
            -
                    )
         | 
| 87 | 
            +
                    self.buttonBox = QDialogButtonBox(QtDialogSave | QtDialogCancel, self)
         | 
| 89 88 | 
             
                    self.buttonBox.accepted.connect(self._doSave)
         | 
| 90 89 | 
             
                    self.buttonBox.rejected.connect(self.close)
         | 
| 91 90 |  | 
| @@ -195,7 +194,7 @@ class GuiProjectSettings(QDialog): | |
| 195 194 | 
             
                        project.data.setAutoReplace(newList)
         | 
| 196 195 |  | 
| 197 196 | 
             
                    self.newProjectSettingsReady.emit(rebuildTrees)
         | 
| 198 | 
            -
                     | 
| 197 | 
            +
                    QApplication.processEvents()
         | 
| 199 198 | 
             
                    self.close()
         | 
| 200 199 |  | 
| 201 200 | 
             
                    return
         | 
| @@ -305,9 +304,9 @@ class _StatusPage(NFixedPage): | |
| 305 304 | 
             
                COL_LABEL = 0
         | 
| 306 305 | 
             
                COL_USAGE = 1
         | 
| 307 306 |  | 
| 308 | 
            -
                KEY_ROLE =  | 
| 309 | 
            -
                COL_ROLE =  | 
| 310 | 
            -
                NUM_ROLE =  | 
| 307 | 
            +
                KEY_ROLE = QtUserRole
         | 
| 308 | 
            +
                COL_ROLE = QtUserRole + 1
         | 
| 309 | 
            +
                NUM_ROLE = QtUserRole + 2
         | 
| 311 310 |  | 
| 312 311 | 
             
                def __init__(self, parent: QWidget, isStatus: bool) -> None:
         | 
| 313 312 | 
             
                    super().__init__(parent=parent)
         | 
| @@ -329,7 +328,9 @@ class _StatusPage(NFixedPage): | |
| 329 328 | 
             
                    self._colDeleted = []
         | 
| 330 329 | 
             
                    self._selColour = QColor(100, 100, 100)
         | 
| 331 330 |  | 
| 332 | 
            -
                    self.iPx = SHARED.theme. | 
| 331 | 
            +
                    self.iPx = SHARED.theme.baseIconHeight
         | 
| 332 | 
            +
                    iSz = SHARED.theme.baseIconSize
         | 
| 333 | 
            +
                    bSz = SHARED.theme.buttonIconSize
         | 
| 333 334 |  | 
| 334 335 | 
             
                    # Title
         | 
| 335 336 | 
             
                    self.pageTitle = NColourLabel(
         | 
| @@ -348,16 +349,16 @@ class _StatusPage(NFixedPage): | |
| 348 349 | 
             
                        self._addItem(key, entry["name"], entry["cols"], entry["count"])
         | 
| 349 350 |  | 
| 350 351 | 
             
                    # List Controls
         | 
| 351 | 
            -
                    self.addButton =  | 
| 352 | 
            +
                    self.addButton = NIconToolButton(self, iSz, "add")
         | 
| 352 353 | 
             
                    self.addButton.clicked.connect(self._newItem)
         | 
| 353 354 |  | 
| 354 | 
            -
                    self.delButton =  | 
| 355 | 
            +
                    self.delButton = NIconToolButton(self, iSz, "remove")
         | 
| 355 356 | 
             
                    self.delButton.clicked.connect(self._delItem)
         | 
| 356 357 |  | 
| 357 | 
            -
                    self.upButton =  | 
| 358 | 
            +
                    self.upButton = NIconToolButton(self, iSz, "up")
         | 
| 358 359 | 
             
                    self.upButton.clicked.connect(lambda: self._moveItem(-1))
         | 
| 359 360 |  | 
| 360 | 
            -
                    self.dnButton =  | 
| 361 | 
            +
                    self.dnButton = NIconToolButton(self, iSz, "down")
         | 
| 361 362 | 
             
                    self.dnButton.clicked.connect(lambda: self._moveItem(1))
         | 
| 362 363 |  | 
| 363 364 | 
             
                    # Edit Form
         | 
| @@ -368,12 +369,12 @@ class _StatusPage(NFixedPage): | |
| 368 369 |  | 
| 369 370 | 
             
                    self.colPixmap = QPixmap(self.iPx, self.iPx)
         | 
| 370 371 | 
             
                    self.colPixmap.fill(QColor(100, 100, 100))
         | 
| 371 | 
            -
                    self.colButton = QPushButton(QIcon(self.colPixmap), self.tr("Colour"))
         | 
| 372 | 
            -
                    self.colButton.setIconSize( | 
| 372 | 
            +
                    self.colButton = QPushButton(QIcon(self.colPixmap), self.tr("Colour"), self)
         | 
| 373 | 
            +
                    self.colButton.setIconSize(bSz)
         | 
| 373 374 | 
             
                    self.colButton.setEnabled(False)
         | 
| 374 375 | 
             
                    self.colButton.clicked.connect(self._selectColour)
         | 
| 375 376 |  | 
| 376 | 
            -
                    self.saveButton = QPushButton(self.tr("Save"))
         | 
| 377 | 
            +
                    self.saveButton = QPushButton(self.tr("Save"), self)
         | 
| 377 378 | 
             
                    self.saveButton.setEnabled(False)
         | 
| 378 379 | 
             
                    self.saveButton.clicked.connect(self._saveItem)
         | 
| 379 380 |  | 
| @@ -589,6 +590,8 @@ class _ReplacePage(NFixedPage): | |
| 589 590 |  | 
| 590 591 | 
             
                    self._changed = False
         | 
| 591 592 |  | 
| 593 | 
            +
                    iSz = SHARED.theme.baseIconSize
         | 
| 594 | 
            +
             | 
| 592 595 | 
             
                    wCol0 = CONFIG.pxInt(
         | 
| 593 596 | 
             
                        SHARED.project.options.getInt("GuiProjectSettings", "replaceColW", 130)
         | 
| 594 597 | 
             
                    )
         | 
| @@ -600,7 +603,7 @@ class _ReplacePage(NFixedPage): | |
| 600 603 | 
             
                    )
         | 
| 601 604 |  | 
| 602 605 | 
             
                    # List Box
         | 
| 603 | 
            -
                    self.listBox = QTreeWidget()
         | 
| 606 | 
            +
                    self.listBox = QTreeWidget(self)
         | 
| 604 607 | 
             
                    self.listBox.setHeaderLabels([self.tr("Keyword"), self.tr("Replace With")])
         | 
| 605 608 | 
             
                    self.listBox.setColumnWidth(self.COL_KEY, wCol0)
         | 
| 606 609 | 
             
                    self.listBox.setIndentation(0)
         | 
| @@ -610,14 +613,14 @@ class _ReplacePage(NFixedPage): | |
| 610 613 | 
             
                        newItem = QTreeWidgetItem(["<%s>" % aKey, aVal])
         | 
| 611 614 | 
             
                        self.listBox.addTopLevelItem(newItem)
         | 
| 612 615 |  | 
| 613 | 
            -
                    self.listBox.sortByColumn(self.COL_KEY, Qt.AscendingOrder)
         | 
| 616 | 
            +
                    self.listBox.sortByColumn(self.COL_KEY, Qt.SortOrder.AscendingOrder)
         | 
| 614 617 | 
             
                    self.listBox.setSortingEnabled(True)
         | 
| 615 618 |  | 
| 616 619 | 
             
                    # List Controls
         | 
| 617 | 
            -
                    self.addButton =  | 
| 620 | 
            +
                    self.addButton = NIconToolButton(self, iSz, "add")
         | 
| 618 621 | 
             
                    self.addButton.clicked.connect(self._addEntry)
         | 
| 619 622 |  | 
| 620 | 
            -
                    self.delButton =  | 
| 623 | 
            +
                    self.delButton = NIconToolButton(self, iSz, "remove")
         | 
| 621 624 | 
             
                    self.delButton.clicked.connect(self._delEntry)
         | 
| 622 625 |  | 
| 623 626 | 
             
                    # Edit Form
         | 
| @@ -630,7 +633,7 @@ class _ReplacePage(NFixedPage): | |
| 630 633 | 
             
                    self.editValue.setEnabled(False)
         | 
| 631 634 | 
             
                    self.editValue.setMaxLength(80)
         | 
| 632 635 |  | 
| 633 | 
            -
                    self.saveButton = QPushButton(self.tr("Save"))
         | 
| 636 | 
            +
                    self.saveButton = QPushButton(self.tr("Save"), self)
         | 
| 634 637 | 
             
                    self.saveButton.clicked.connect(self._saveEntry)
         | 
| 635 638 |  | 
| 636 639 | 
             
                    # Assemble
         | 
    
        novelwriter/dialogs/quotes.py
    CHANGED
    
    | @@ -26,7 +26,7 @@ from __future__ import annotations | |
| 26 26 | 
             
            import logging
         | 
| 27 27 |  | 
| 28 28 | 
             
            from PyQt5.QtGui import QFontMetrics
         | 
| 29 | 
            -
            from PyQt5.QtCore import QSize,  | 
| 29 | 
            +
            from PyQt5.QtCore import QSize, pyqtSlot
         | 
| 30 30 | 
             
            from PyQt5.QtWidgets import (
         | 
| 31 31 | 
             
                QDialog, QDialogButtonBox, QFrame, QHBoxLayout, QLabel, QListWidget,
         | 
| 32 32 | 
             
                QListWidgetItem, QVBoxLayout, QWidget
         | 
| @@ -34,6 +34,7 @@ from PyQt5.QtWidgets import ( | |
| 34 34 |  | 
| 35 35 | 
             
            from novelwriter import CONFIG
         | 
| 36 36 | 
             
            from novelwriter.constants import trConst, nwQuotes
         | 
| 37 | 
            +
            from novelwriter.types import QtAlignCenter, QtAlignTop, QtDialogCancel, QtDialogOk, QtUserRole
         | 
| 37 38 |  | 
| 38 39 | 
             
            logger = logging.getLogger(__name__)
         | 
| 39 40 |  | 
| @@ -42,7 +43,7 @@ class GuiQuoteSelect(QDialog): | |
| 42 43 |  | 
| 43 44 | 
             
                _selected = ""
         | 
| 44 45 |  | 
| 45 | 
            -
                D_KEY =  | 
| 46 | 
            +
                D_KEY = QtUserRole
         | 
| 46 47 |  | 
| 47 48 | 
             
                def __init__(self, parent: QWidget, current: str = '"') -> None:
         | 
| 48 49 | 
             
                    super().__init__(parent=parent)
         | 
| @@ -65,14 +66,14 @@ class GuiQuoteSelect(QDialog): | |
| 65 66 | 
             
                    lblFont.setPointSizeF(4*lblFont.pointSizeF())
         | 
| 66 67 |  | 
| 67 68 | 
             
                    # Preview Label
         | 
| 68 | 
            -
                    self.previewLabel = QLabel(current)
         | 
| 69 | 
            +
                    self.previewLabel = QLabel(current, self)
         | 
| 69 70 | 
             
                    self.previewLabel.setFont(lblFont)
         | 
| 70 71 | 
             
                    self.previewLabel.setFixedSize(QSize(pxW, pxH))
         | 
| 71 | 
            -
                    self.previewLabel.setAlignment( | 
| 72 | 
            -
                    self.previewLabel.setFrameStyle(QFrame.Box | QFrame.Plain)
         | 
| 72 | 
            +
                    self.previewLabel.setAlignment(QtAlignCenter)
         | 
| 73 | 
            +
                    self.previewLabel.setFrameStyle(QFrame.Shape.Box | QFrame.Shadow.Plain)
         | 
| 73 74 |  | 
| 74 75 | 
             
                    # Quote Symbols
         | 
| 75 | 
            -
                    self.listBox = QListWidget()
         | 
| 76 | 
            +
                    self.listBox = QListWidget(self)
         | 
| 76 77 | 
             
                    self.listBox.itemSelectionChanged.connect(self._selectedSymbol)
         | 
| 77 78 |  | 
| 78 79 | 
             
                    minSize = 100
         | 
| @@ -89,12 +90,12 @@ class GuiQuoteSelect(QDialog): | |
| 89 90 | 
             
                    self.listBox.setMinimumHeight(CONFIG.pxInt(150))
         | 
| 90 91 |  | 
| 91 92 | 
             
                    # Buttons
         | 
| 92 | 
            -
                    self.buttonBox = QDialogButtonBox( | 
| 93 | 
            +
                    self.buttonBox = QDialogButtonBox(QtDialogOk | QtDialogCancel, self)
         | 
| 93 94 | 
             
                    self.buttonBox.accepted.connect(self.accept)
         | 
| 94 95 | 
             
                    self.buttonBox.rejected.connect(self.reject)
         | 
| 95 96 |  | 
| 96 97 | 
             
                    # Assemble
         | 
| 97 | 
            -
                    self.labelBox.addWidget(self.previewLabel, 0,  | 
| 98 | 
            +
                    self.labelBox.addWidget(self.previewLabel, 0, QtAlignTop)
         | 
| 98 99 | 
             
                    self.labelBox.addStretch(1)
         | 
| 99 100 |  | 
| 100 101 | 
             
                    self.innerBox.addLayout(self.labelBox)
         | 
| @@ -122,7 +123,7 @@ class GuiQuoteSelect(QDialog): | |
| 122 123 | 
             
                def getQuote(cls, parent: QWidget, current: str = "") -> tuple[str, bool]:
         | 
| 123 124 | 
             
                    """Pop the dialog and return the result."""
         | 
| 124 125 | 
             
                    cls = GuiQuoteSelect(parent, current=current)
         | 
| 125 | 
            -
                    cls. | 
| 126 | 
            +
                    cls.exec()
         | 
| 126 127 | 
             
                    quote = cls._selected
         | 
| 127 128 | 
             
                    accepted = cls.result() == QDialog.DialogCode.Accepted
         | 
| 128 129 | 
             
                    cls.deleteLater()
         |