Qt6 theming changes and editor search issue fixes (#2204)
This commit is contained in:
@@ -38,7 +38,7 @@ from urllib.parse import urljoin
|
|||||||
from urllib.request import pathname2url
|
from urllib.request import pathname2url
|
||||||
|
|
||||||
from PyQt6.QtCore import QCoreApplication, QMimeData, QUrl
|
from PyQt6.QtCore import QCoreApplication, QMimeData, QUrl
|
||||||
from PyQt6.QtGui import QAction, QColor, QDesktopServices, QFont, QFontDatabase, QFontInfo
|
from PyQt6.QtGui import QAction, QDesktopServices, QFont, QFontDatabase, QFontInfo
|
||||||
from PyQt6.QtWidgets import QMenu, QMenuBar, QWidget
|
from PyQt6.QtWidgets import QMenu, QMenuBar, QWidget
|
||||||
|
|
||||||
from novelwriter.constants import nwConst, nwLabels, nwUnicode, trConst
|
from novelwriter.constants import nwConst, nwLabels, nwUnicode, trConst
|
||||||
@@ -417,11 +417,6 @@ def numberToRoman(value: int, toLower: bool = False) -> str:
|
|||||||
# Qt Helpers
|
# Qt Helpers
|
||||||
##
|
##
|
||||||
|
|
||||||
def cssCol(col: QColor, alpha: int | None = None) -> str:
|
|
||||||
"""Convert a QColor object to an rgba entry to use in CSS."""
|
|
||||||
return f"rgba({col.red()}, {col.green()}, {col.blue()}, {alpha or col.alpha()})"
|
|
||||||
|
|
||||||
|
|
||||||
def describeFont(font: QFont) -> str:
|
def describeFont(font: QFont) -> str:
|
||||||
"""Describe a font in a way that can be displayed on the GUI."""
|
"""Describe a font in a way that can be displayed on the GUI."""
|
||||||
if isinstance(font, QFont):
|
if isinstance(font, QFont):
|
||||||
|
|||||||
@@ -31,11 +31,11 @@ from PyQt6.QtWidgets import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
from novelwriter import CONFIG, SHARED
|
from novelwriter import CONFIG, SHARED
|
||||||
from novelwriter.common import cssCol, readTextFile
|
from novelwriter.common import readTextFile
|
||||||
from novelwriter.extensions.configlayout import NColorLabel
|
from novelwriter.extensions.configlayout import NColorLabel
|
||||||
from novelwriter.extensions.modified import NDialog
|
from novelwriter.extensions.modified import NDialog
|
||||||
from novelwriter.extensions.versioninfo import VersionInfoWidget
|
from novelwriter.extensions.versioninfo import VersionInfoWidget
|
||||||
from novelwriter.types import QtAlignRightTop, QtDialogClose
|
from novelwriter.types import QtAlignRightTop, QtDialogClose, QtHexArgb
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@@ -135,7 +135,7 @@ class GuiAbout(NDialog):
|
|||||||
|
|
||||||
def _setStyleSheet(self) -> None:
|
def _setStyleSheet(self) -> None:
|
||||||
"""Set stylesheet text document."""
|
"""Set stylesheet text document."""
|
||||||
baseCol = cssCol(self.palette().window().color())
|
baseCol = self.palette().window().color().name(QtHexArgb)
|
||||||
self.txtCredits.setStyleSheet(
|
self.txtCredits.setStyleSheet(
|
||||||
f"QTextBrowser {{border: none; background: {baseCol};}} "
|
f"QTextBrowser {{border: none; background: {baseCol};}} "
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -42,9 +42,9 @@ from PyQt6.QtCore import (
|
|||||||
pyqtSlot
|
pyqtSlot
|
||||||
)
|
)
|
||||||
from PyQt6.QtGui import (
|
from PyQt6.QtGui import (
|
||||||
QAction, QColor, QCursor, QDragEnterEvent, QDragMoveEvent, QDropEvent,
|
QAction, QCursor, QDragEnterEvent, QDragMoveEvent, QDropEvent, QKeyEvent,
|
||||||
QKeyEvent, QKeySequence, QMouseEvent, QPalette, QPixmap, QResizeEvent,
|
QKeySequence, QMouseEvent, QPalette, QPixmap, QResizeEvent, QShortcut,
|
||||||
QShortcut, QTextBlock, QTextCursor, QTextDocument, QTextOption
|
QTextBlock, QTextCursor, QTextDocument, QTextOption
|
||||||
)
|
)
|
||||||
from PyQt6.QtWidgets import (
|
from PyQt6.QtWidgets import (
|
||||||
QApplication, QFrame, QGridLayout, QHBoxLayout, QLabel, QLineEdit, QMenu,
|
QApplication, QFrame, QGridLayout, QHBoxLayout, QLabel, QLineEdit, QMenu,
|
||||||
@@ -100,6 +100,7 @@ class GuiDocEditor(QPlainTextEdit):
|
|||||||
Qt.Key.Key_Left, Qt.Key.Key_Right, Qt.Key.Key_Up, Qt.Key.Key_Down,
|
Qt.Key.Key_Left, Qt.Key.Key_Right, Qt.Key.Key_Up, Qt.Key.Key_Down,
|
||||||
Qt.Key.Key_PageUp, Qt.Key.Key_PageDown
|
Qt.Key.Key_PageUp, Qt.Key.Key_PageDown
|
||||||
)
|
)
|
||||||
|
ENTER_KEYS = (Qt.Key.Key_Return, Qt.Key.Key_Enter)
|
||||||
|
|
||||||
# Custom Signals
|
# Custom Signals
|
||||||
closeEditorRequest = pyqtSignal()
|
closeEditorRequest = pyqtSignal()
|
||||||
@@ -927,7 +928,7 @@ class GuiDocEditor(QPlainTextEdit):
|
|||||||
* We also handle automatic scrolling here.
|
* We also handle automatic scrolling here.
|
||||||
"""
|
"""
|
||||||
self._lastActive = time()
|
self._lastActive = time()
|
||||||
if self.docSearch.anyFocus() and event.key() in (Qt.Key.Key_Return, Qt.Key.Key_Enter):
|
if self.docSearch.anyFocus() and event.key() in self.ENTER_KEYS:
|
||||||
return
|
return
|
||||||
elif event == QKeySequence.StandardKey.Redo:
|
elif event == QKeySequence.StandardKey.Redo:
|
||||||
self.docAction(nwDocAction.REDO)
|
self.docAction(nwDocAction.REDO)
|
||||||
@@ -1325,6 +1326,7 @@ class GuiDocEditor(QPlainTextEdit):
|
|||||||
self.beginSearch()
|
self.beginSearch()
|
||||||
return
|
return
|
||||||
|
|
||||||
|
prevFocus = QApplication.focusWidget() or self
|
||||||
resS, resE = self.findAllOccurences()
|
resS, resE = self.findAllOccurences()
|
||||||
if len(resS) == 0 and self._docHandle:
|
if len(resS) == 0 and self._docHandle:
|
||||||
self.docSearch.setResultCount(0, 0)
|
self.docSearch.setResultCount(0, 0)
|
||||||
@@ -1333,7 +1335,7 @@ class GuiDocEditor(QPlainTextEdit):
|
|||||||
self.requestNextDocument.emit(self._docHandle, CONFIG.searchLoop)
|
self.requestNextDocument.emit(self._docHandle, CONFIG.searchLoop)
|
||||||
QApplication.processEvents()
|
QApplication.processEvents()
|
||||||
self.beginSearch()
|
self.beginSearch()
|
||||||
self.setFocus()
|
prevFocus.setFocus()
|
||||||
return
|
return
|
||||||
|
|
||||||
cursor = self.textCursor()
|
cursor = self.textCursor()
|
||||||
@@ -1353,7 +1355,7 @@ class GuiDocEditor(QPlainTextEdit):
|
|||||||
self.requestNextDocument.emit(self._docHandle, CONFIG.searchLoop)
|
self.requestNextDocument.emit(self._docHandle, CONFIG.searchLoop)
|
||||||
QApplication.processEvents()
|
QApplication.processEvents()
|
||||||
self.beginSearch()
|
self.beginSearch()
|
||||||
self.setFocus()
|
prevFocus.setFocus()
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
resIdx = 0 if doLoop else maxIdx
|
resIdx = 0 if doLoop else maxIdx
|
||||||
@@ -2662,10 +2664,11 @@ class GuiDocEditSearch(QFrame):
|
|||||||
|
|
||||||
def updateTheme(self) -> None:
|
def updateTheme(self) -> None:
|
||||||
"""Update theme elements."""
|
"""Update theme elements."""
|
||||||
qPalette = QApplication.palette()
|
palette = QApplication.palette()
|
||||||
self.setPalette(qPalette)
|
|
||||||
self.searchBox.setPalette(qPalette)
|
self.setPalette(palette)
|
||||||
self.replaceBox.setPalette(qPalette)
|
self.searchBox.setPalette(palette)
|
||||||
|
self.replaceBox.setPalette(palette)
|
||||||
|
|
||||||
# Set icons
|
# Set icons
|
||||||
self.toggleCase.setIcon(SHARED.theme.getIcon("search_case"))
|
self.toggleCase.setIcon(SHARED.theme.getIcon("search_case"))
|
||||||
@@ -2682,24 +2685,6 @@ class GuiDocEditSearch(QFrame):
|
|||||||
self.searchOpt.setStyleSheet("QToolBar {padding: 0;}")
|
self.searchOpt.setStyleSheet("QToolBar {padding: 0;}")
|
||||||
self.showReplace.setStyleSheet("QToolButton {border: none; background: transparent;}")
|
self.showReplace.setStyleSheet("QToolButton {border: none; background: transparent;}")
|
||||||
|
|
||||||
# Construct Box Colours
|
|
||||||
qPalette = self.searchBox.palette()
|
|
||||||
baseCol = qPalette.base().color()
|
|
||||||
rCol = baseCol.redF() + 0.1
|
|
||||||
gCol = baseCol.greenF() - 0.1
|
|
||||||
bCol = baseCol.blueF() - 0.1
|
|
||||||
|
|
||||||
mCol = max(rCol, gCol, bCol, 1.0)
|
|
||||||
errCol = QColor()
|
|
||||||
errCol.setRedF(rCol/mCol)
|
|
||||||
errCol.setGreenF(gCol/mCol)
|
|
||||||
errCol.setBlueF(bCol/mCol)
|
|
||||||
|
|
||||||
self.rxCol = {
|
|
||||||
True: baseCol,
|
|
||||||
False: errCol
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
def cycleFocus(self) -> bool:
|
def cycleFocus(self) -> bool:
|
||||||
@@ -2716,7 +2701,7 @@ class GuiDocEditSearch(QFrame):
|
|||||||
|
|
||||||
def anyFocus(self) -> bool:
|
def anyFocus(self) -> bool:
|
||||||
"""Return True if any of the input boxes have focus."""
|
"""Return True if any of the input boxes have focus."""
|
||||||
return self.searchBox.hasFocus() or self.replaceBox.hasFocus()
|
return self.hasFocus() or self.isAncestorOf(QApplication.focusWidget())
|
||||||
|
|
||||||
##
|
##
|
||||||
# Public Slots
|
# Public Slots
|
||||||
@@ -2800,9 +2785,12 @@ class GuiDocEditSearch(QFrame):
|
|||||||
"""Highlight the search box to indicate the search string is or
|
"""Highlight the search box to indicate the search string is or
|
||||||
isn't valid. Take the colour from the replace box.
|
isn't valid. Take the colour from the replace box.
|
||||||
"""
|
"""
|
||||||
qPalette = self.replaceBox.palette()
|
palette = self.replaceBox.palette()
|
||||||
qPalette.setColor(QPalette.ColorRole.Base, self.rxCol[isValid])
|
palette.setColor(
|
||||||
self.searchBox.setPalette(qPalette)
|
QPalette.ColorRole.Text,
|
||||||
|
palette.text().color() if isValid else SHARED.theme.errorText
|
||||||
|
)
|
||||||
|
self.searchBox.setPalette(palette)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -201,6 +201,7 @@ class GuiNovelToolBar(QWidget):
|
|||||||
iSz = SHARED.theme.baseIconSize
|
iSz = SHARED.theme.baseIconSize
|
||||||
|
|
||||||
self.setContentsMargins(0, 0, 0, 0)
|
self.setContentsMargins(0, 0, 0, 0)
|
||||||
|
self.setBackgroundRole(QPalette.ColorRole.Base)
|
||||||
self.setAutoFillBackground(True)
|
self.setAutoFillBackground(True)
|
||||||
|
|
||||||
# Novel Selector
|
# Novel Selector
|
||||||
@@ -270,10 +271,6 @@ class GuiNovelToolBar(QWidget):
|
|||||||
self.tbRefresh.setThemeIcon("refresh", "green")
|
self.tbRefresh.setThemeIcon("refresh", "green")
|
||||||
self.tbMore.setThemeIcon("more_vertical")
|
self.tbMore.setThemeIcon("more_vertical")
|
||||||
|
|
||||||
qPalette = self.palette()
|
|
||||||
qPalette.setBrush(QPalette.ColorRole.Window, qPalette.base())
|
|
||||||
self.setPalette(qPalette)
|
|
||||||
|
|
||||||
# StyleSheets
|
# StyleSheets
|
||||||
buttonStyle = SHARED.theme.getStyleSheet(STYLES_MIN_TOOLBUTTON)
|
buttonStyle = SHARED.theme.getStyleSheet(STYLES_MIN_TOOLBUTTON)
|
||||||
self.tbNovel.setStyleSheet(buttonStyle)
|
self.tbNovel.setStyleSheet(buttonStyle)
|
||||||
|
|||||||
@@ -245,6 +245,7 @@ class GuiProjectToolBar(QWidget):
|
|||||||
iSz = SHARED.theme.baseIconSize
|
iSz = SHARED.theme.baseIconSize
|
||||||
|
|
||||||
self.setContentsMargins(0, 0, 0, 0)
|
self.setContentsMargins(0, 0, 0, 0)
|
||||||
|
self.setBackgroundRole(QPalette.ColorRole.Base)
|
||||||
self.setAutoFillBackground(True)
|
self.setAutoFillBackground(True)
|
||||||
|
|
||||||
# Widget Label
|
# Widget Label
|
||||||
@@ -351,10 +352,6 @@ class GuiProjectToolBar(QWidget):
|
|||||||
|
|
||||||
def updateTheme(self) -> None:
|
def updateTheme(self) -> None:
|
||||||
"""Update theme elements."""
|
"""Update theme elements."""
|
||||||
qPalette = self.palette()
|
|
||||||
qPalette.setBrush(QPalette.ColorRole.Window, qPalette.base())
|
|
||||||
self.setPalette(qPalette)
|
|
||||||
|
|
||||||
buttonStyle = SHARED.theme.getStyleSheet(STYLES_MIN_TOOLBUTTON)
|
buttonStyle = SHARED.theme.getStyleSheet(STYLES_MIN_TOOLBUTTON)
|
||||||
self.tbQuick.setStyleSheet(buttonStyle)
|
self.tbQuick.setStyleSheet(buttonStyle)
|
||||||
self.tbMoveU.setStyleSheet(buttonStyle)
|
self.tbMoveU.setStyleSheet(buttonStyle)
|
||||||
|
|||||||
@@ -35,12 +35,12 @@ from PyQt6.QtWidgets import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
from novelwriter import CONFIG, SHARED
|
from novelwriter import CONFIG, SHARED
|
||||||
from novelwriter.common import checkInt, cssCol, qtAddAction
|
from novelwriter.common import checkInt, qtAddAction
|
||||||
from novelwriter.core.coretools import DocSearch
|
from novelwriter.core.coretools import DocSearch
|
||||||
from novelwriter.core.item import NWItem
|
from novelwriter.core.item import NWItem
|
||||||
from novelwriter.types import (
|
from novelwriter.types import (
|
||||||
QtAlignMiddle, QtAlignRight, QtHeaderStretch, QtHeaderToContents,
|
QtAlignMiddle, QtAlignRight, QtHeaderStretch, QtHeaderToContents,
|
||||||
QtUserRole
|
QtHexArgb, QtUserRole
|
||||||
)
|
)
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
@@ -71,6 +71,10 @@ class GuiProjectSearch(QWidget):
|
|||||||
self._blocked = False
|
self._blocked = False
|
||||||
self._map: dict[str, tuple[int, float]] = {}
|
self._map: dict[str, tuple[int, float]] = {}
|
||||||
|
|
||||||
|
self.setContentsMargins(0, 0, 0, 0)
|
||||||
|
self.setBackgroundRole(QPalette.ColorRole.Base)
|
||||||
|
self.setAutoFillBackground(True)
|
||||||
|
|
||||||
# Header
|
# Header
|
||||||
self.viewLabel = QLabel(self.tr("Project Search"), self)
|
self.viewLabel = QLabel(self.tr("Project Search"), self)
|
||||||
self.viewLabel.setFont(SHARED.theme.guiFontB)
|
self.viewLabel.setFont(SHARED.theme.guiFontB)
|
||||||
@@ -138,7 +142,6 @@ class GuiProjectSearch(QWidget):
|
|||||||
self.outerBox.setContentsMargins(0, 0, 0, 0)
|
self.outerBox.setContentsMargins(0, 0, 0, 0)
|
||||||
self.outerBox.setSpacing(2)
|
self.outerBox.setSpacing(2)
|
||||||
|
|
||||||
self.setAutoFillBackground(True)
|
|
||||||
self.setLayout(self.outerBox)
|
self.setLayout(self.outerBox)
|
||||||
self.updateTheme()
|
self.updateTheme()
|
||||||
|
|
||||||
@@ -152,12 +155,9 @@ class GuiProjectSearch(QWidget):
|
|||||||
|
|
||||||
def updateTheme(self) -> None:
|
def updateTheme(self) -> None:
|
||||||
"""Update theme elements."""
|
"""Update theme elements."""
|
||||||
|
palette = QApplication.palette()
|
||||||
qPalette = self.palette()
|
colBase = palette.base().color().name(QtHexArgb)
|
||||||
colBase = cssCol(qPalette.base().color())
|
colFocus = palette.highlight().color().name(QtHexArgb)
|
||||||
colFocus = cssCol(qPalette.highlight().color())
|
|
||||||
qPalette.setBrush(QPalette.ColorRole.Window, qPalette.base())
|
|
||||||
self.setPalette(qPalette)
|
|
||||||
|
|
||||||
self.setStyleSheet(
|
self.setStyleSheet(
|
||||||
"QToolBar {padding: 0; background: none;} "
|
"QToolBar {padding: 0; background: none;} "
|
||||||
|
|||||||
@@ -28,7 +28,6 @@ import logging
|
|||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
from PyQt6.QtCore import QEvent, QPoint, QSize, pyqtSignal
|
from PyQt6.QtCore import QEvent, QPoint, QSize, pyqtSignal
|
||||||
from PyQt6.QtGui import QPalette
|
|
||||||
from PyQt6.QtWidgets import QMenu, QVBoxLayout, QWidget
|
from PyQt6.QtWidgets import QMenu, QVBoxLayout, QWidget
|
||||||
|
|
||||||
from novelwriter import SHARED
|
from novelwriter import SHARED
|
||||||
@@ -125,10 +124,6 @@ class GuiSideBar(QWidget):
|
|||||||
|
|
||||||
def updateTheme(self) -> None:
|
def updateTheme(self) -> None:
|
||||||
"""Initialise GUI elements that depend on specific settings."""
|
"""Initialise GUI elements that depend on specific settings."""
|
||||||
qPalette = self.palette()
|
|
||||||
qPalette.setBrush(QPalette.ColorRole.Window, qPalette.base())
|
|
||||||
self.setPalette(qPalette)
|
|
||||||
|
|
||||||
buttonStyle = SHARED.theme.getStyleSheet(STYLES_BIG_TOOLBUTTON)
|
buttonStyle = SHARED.theme.getStyleSheet(STYLES_BIG_TOOLBUTTON)
|
||||||
|
|
||||||
self.tbProject.setStyleSheet(buttonStyle)
|
self.tbProject.setStyleSheet(buttonStyle)
|
||||||
|
|||||||
@@ -37,12 +37,12 @@ from PyQt6.QtGui import (
|
|||||||
from PyQt6.QtWidgets import QApplication
|
from PyQt6.QtWidgets import QApplication
|
||||||
|
|
||||||
from novelwriter import CONFIG
|
from novelwriter import CONFIG
|
||||||
from novelwriter.common import NWConfigParser, cssCol, minmax
|
from novelwriter.common import NWConfigParser, minmax
|
||||||
from novelwriter.config import DEF_GUI, DEF_ICONS, DEF_SYNTAX
|
from novelwriter.config import DEF_GUI, DEF_ICONS, DEF_SYNTAX
|
||||||
from novelwriter.constants import nwLabels
|
from novelwriter.constants import nwLabels
|
||||||
from novelwriter.enum import nwItemClass, nwItemLayout, nwItemType
|
from novelwriter.enum import nwItemClass, nwItemLayout, nwItemType
|
||||||
from novelwriter.error import logException
|
from novelwriter.error import logException
|
||||||
from novelwriter.types import QtBlack, QtPaintAntiAlias, QtTransparent
|
from novelwriter.types import QtBlack, QtHexArgb, QtPaintAntiAlias, QtTransparent
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@@ -528,27 +528,29 @@ class GuiTheme:
|
|||||||
"""Build default style sheets."""
|
"""Build default style sheets."""
|
||||||
self._styleSheets = {}
|
self._styleSheets = {}
|
||||||
|
|
||||||
tCol = palette.text().color()
|
text = palette.text().color()
|
||||||
hCol = palette.highlight().color()
|
text.setAlpha(48)
|
||||||
|
tCol = text.name(QtHexArgb)
|
||||||
|
hCol = palette.highlight().color().name(QtHexArgb)
|
||||||
|
|
||||||
# Flat Tab Widget and Tab Bar:
|
# Flat Tab Widget and Tab Bar:
|
||||||
self._styleSheets[STYLES_FLAT_TABS] = (
|
self._styleSheets[STYLES_FLAT_TABS] = (
|
||||||
"QTabWidget::pane {border: 0;} "
|
"QTabWidget::pane {border: 0;} "
|
||||||
"QTabWidget QTabBar::tab {border: 0; padding: 4px 8px;} "
|
"QTabWidget QTabBar::tab {border: 0; padding: 4px 8px;} "
|
||||||
f"QTabWidget QTabBar::tab:selected {{color: {cssCol(hCol)};}} "
|
f"QTabWidget QTabBar::tab:selected {{color: {hCol};}} "
|
||||||
)
|
)
|
||||||
|
|
||||||
# Minimal Tool Button
|
# Minimal Tool Button
|
||||||
self._styleSheets[STYLES_MIN_TOOLBUTTON] = (
|
self._styleSheets[STYLES_MIN_TOOLBUTTON] = (
|
||||||
"QToolButton {padding: 2px; margin: 0; border: none; background: transparent;} "
|
"QToolButton {padding: 2px; margin: 0; border: none; background: transparent;} "
|
||||||
f"QToolButton:hover {{border: none; background: {cssCol(tCol, 48)};}} "
|
f"QToolButton:hover {{border: none; background: {tCol};}} "
|
||||||
"QToolButton::menu-indicator {image: none;} "
|
"QToolButton::menu-indicator {image: none;} "
|
||||||
)
|
)
|
||||||
|
|
||||||
# Big Tool Button
|
# Big Tool Button
|
||||||
self._styleSheets[STYLES_BIG_TOOLBUTTON] = (
|
self._styleSheets[STYLES_BIG_TOOLBUTTON] = (
|
||||||
"QToolButton {padding: 6px; margin: 0; border: none; background: transparent;} "
|
"QToolButton {padding: 6px; margin: 0; border: none; background: transparent;} "
|
||||||
f"QToolButton:hover {{border: none; background: {cssCol(tCol, 48)};}} "
|
f"QToolButton:hover {{border: none; background: {tCol};}} "
|
||||||
"QToolButton::menu-indicator {image: none;} "
|
"QToolButton::menu-indicator {image: none;} "
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -1046,8 +1046,6 @@ class GuiMain(QMainWindow):
|
|||||||
SHARED.project.tree.refreshAllItems()
|
SHARED.project.tree.refreshAllItems()
|
||||||
|
|
||||||
if theme:
|
if theme:
|
||||||
# We are doing this manually instead of connecting to
|
|
||||||
# paletteChanged since the processing order matters
|
|
||||||
SHARED.theme.loadTheme()
|
SHARED.theme.loadTheme()
|
||||||
self.setPalette(QApplication.palette())
|
self.setPalette(QApplication.palette())
|
||||||
self.docEditor.updateTheme()
|
self.docEditor.updateTheme()
|
||||||
|
|||||||
@@ -36,10 +36,10 @@ from PyQt6.QtWidgets import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
from novelwriter import CONFIG, SHARED
|
from novelwriter import CONFIG, SHARED
|
||||||
from novelwriter.common import cssCol, formatFileFilter, formatInt, getFileSize, openExternalPath
|
from novelwriter.common import formatFileFilter, formatInt, getFileSize, openExternalPath
|
||||||
from novelwriter.error import formatException
|
from novelwriter.error import formatException
|
||||||
from novelwriter.extensions.modified import NIconToolButton, NNonBlockingDialog
|
from novelwriter.extensions.modified import NIconToolButton, NNonBlockingDialog
|
||||||
from novelwriter.types import QtDialogClose
|
from novelwriter.types import QtDialogClose, QtHexArgb
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@@ -101,7 +101,6 @@ class GuiDictionaries(NNonBlockingDialog):
|
|||||||
# Info Box
|
# Info Box
|
||||||
self.infoBox = QPlainTextEdit(self)
|
self.infoBox = QPlainTextEdit(self)
|
||||||
self.infoBox.setReadOnly(True)
|
self.infoBox.setReadOnly(True)
|
||||||
self.infoBox.setFixedHeight(4*SHARED.theme.fontPixelSize)
|
|
||||||
self.infoBox.setFrameStyle(QFrame.Shape.NoFrame)
|
self.infoBox.setFrameStyle(QFrame.Shape.NoFrame)
|
||||||
|
|
||||||
# Buttons
|
# Buttons
|
||||||
@@ -109,21 +108,16 @@ class GuiDictionaries(NNonBlockingDialog):
|
|||||||
self.buttonBox.rejected.connect(self.reject)
|
self.buttonBox.rejected.connect(self.reject)
|
||||||
|
|
||||||
# Assemble
|
# Assemble
|
||||||
self.innerBox = QVBoxLayout()
|
|
||||||
self.innerBox.addWidget(self.huInfo)
|
|
||||||
self.innerBox.addLayout(self.huPathBox)
|
|
||||||
self.innerBox.addLayout(self.huAddBox)
|
|
||||||
self.innerBox.addSpacing(8)
|
|
||||||
self.innerBox.addWidget(self.inInfo)
|
|
||||||
self.innerBox.addLayout(self.inBox)
|
|
||||||
self.innerBox.addWidget(self.infoBox)
|
|
||||||
self.innerBox.setSpacing(4)
|
|
||||||
|
|
||||||
self.outerBox = QVBoxLayout()
|
self.outerBox = QVBoxLayout()
|
||||||
self.outerBox.addLayout(self.innerBox, 0)
|
self.outerBox.addWidget(self.huInfo, 0)
|
||||||
self.outerBox.addStretch(1)
|
self.outerBox.addLayout(self.huPathBox, 0)
|
||||||
|
self.outerBox.addLayout(self.huAddBox, 0)
|
||||||
|
self.outerBox.addSpacing(8)
|
||||||
|
self.outerBox.addWidget(self.inInfo, 0)
|
||||||
|
self.outerBox.addLayout(self.inBox, 0)
|
||||||
|
self.outerBox.addWidget(self.infoBox, 1)
|
||||||
|
self.outerBox.addSpacing(8)
|
||||||
self.outerBox.addWidget(self.buttonBox, 0)
|
self.outerBox.addWidget(self.buttonBox, 0)
|
||||||
self.outerBox.setSpacing(16)
|
|
||||||
|
|
||||||
self.setLayout(self.outerBox)
|
self.setLayout(self.outerBox)
|
||||||
|
|
||||||
@@ -248,8 +242,8 @@ class GuiDictionaries(NNonBlockingDialog):
|
|||||||
cursor.movePosition(QTextCursor.MoveOperation.End)
|
cursor.movePosition(QTextCursor.MoveOperation.End)
|
||||||
if cursor.position() > 0:
|
if cursor.position() > 0:
|
||||||
cursor.insertText("\n")
|
cursor.insertText("\n")
|
||||||
textCol = cssCol(SHARED.theme.errorText if err else self.palette().text().color())
|
textCol = SHARED.theme.errorText if err else self.palette().text().color()
|
||||||
cursor.insertHtml(f"<font style='color: {textCol}'>{text}</font>")
|
cursor.insertHtml(f"<font style='color: {textCol.name(QtHexArgb)}'>{text}</font>")
|
||||||
cursor.movePosition(QTextCursor.MoveOperation.End)
|
cursor.movePosition(QTextCursor.MoveOperation.End)
|
||||||
cursor.deleteChar()
|
cursor.deleteChar()
|
||||||
self.infoBox.setTextCursor(cursor)
|
self.infoBox.setTextCursor(cursor)
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ from PyQt6.QtWidgets import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
from novelwriter import CONFIG, SHARED
|
from novelwriter import CONFIG, SHARED
|
||||||
from novelwriter.common import cssCol, formatInt, makeFileNameSafe, qtAddAction, qtLambda
|
from novelwriter.common import formatInt, makeFileNameSafe, qtAddAction, qtLambda
|
||||||
from novelwriter.constants import nwFiles
|
from novelwriter.constants import nwFiles
|
||||||
from novelwriter.core.coretools import ProjectBuilder
|
from novelwriter.core.coretools import ProjectBuilder
|
||||||
from novelwriter.enum import nwItemClass
|
from novelwriter.enum import nwItemClass
|
||||||
@@ -48,7 +48,7 @@ from novelwriter.extensions.configlayout import NWrappedWidgetBox
|
|||||||
from novelwriter.extensions.modified import NDialog, NIconToolButton, NSpinBox
|
from novelwriter.extensions.modified import NDialog, NIconToolButton, NSpinBox
|
||||||
from novelwriter.extensions.switch import NSwitch
|
from novelwriter.extensions.switch import NSwitch
|
||||||
from novelwriter.extensions.versioninfo import VersionInfoWidget
|
from novelwriter.extensions.versioninfo import VersionInfoWidget
|
||||||
from novelwriter.types import QtAlignLeft, QtAlignRightTop, QtScrollAsNeeded, QtSelected
|
from novelwriter.types import QtAlignLeft, QtAlignRightTop, QtHexArgb, QtScrollAsNeeded, QtSelected
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@@ -301,7 +301,9 @@ class _OpenProjectPage(QWidget):
|
|||||||
|
|
||||||
self._selectFirstItem()
|
self._selectFirstItem()
|
||||||
|
|
||||||
baseCol = cssCol(self.palette().base().color(), PANEL_ALPHA)
|
base = self.palette().base().color()
|
||||||
|
base.setAlpha(PANEL_ALPHA)
|
||||||
|
baseCol = base.name(QtHexArgb)
|
||||||
self.setStyleSheet(
|
self.setStyleSheet(
|
||||||
f"QListView {{border: none; background: {baseCol};}} "
|
f"QListView {{border: none; background: {baseCol};}} "
|
||||||
f"QLineEdit {{border: none; background: {baseCol}; padding: 4px;}} "
|
f"QLineEdit {{border: none; background: {baseCol}; padding: 4px;}} "
|
||||||
@@ -507,7 +509,9 @@ class _NewProjectPage(QWidget):
|
|||||||
# Styles
|
# Styles
|
||||||
# ======
|
# ======
|
||||||
|
|
||||||
baseCol = cssCol(self.palette().base().color(), PANEL_ALPHA)
|
base = self.palette().base().color()
|
||||||
|
base.setAlpha(PANEL_ALPHA)
|
||||||
|
baseCol = base.name(QtHexArgb)
|
||||||
self.setStyleSheet(
|
self.setStyleSheet(
|
||||||
f"QScrollArea {{border: none; background: {baseCol};}} "
|
f"QScrollArea {{border: none; background: {baseCol};}} "
|
||||||
f"_NewProjectForm {{border: none; background: {baseCol};}} "
|
f"_NewProjectForm {{border: none; background: {baseCol};}} "
|
||||||
|
|||||||
@@ -70,6 +70,7 @@ QtSelected = QStyle.StateFlag.State_Selected
|
|||||||
# Qt Colour Types
|
# Qt Colour Types
|
||||||
|
|
||||||
QtHexRgb = QColor.NameFormat.HexRgb
|
QtHexRgb = QColor.NameFormat.HexRgb
|
||||||
|
QtHexArgb = QColor.NameFormat.HexArgb
|
||||||
|
|
||||||
# Qt Tree and Table Types
|
# Qt Tree and Table Types
|
||||||
|
|
||||||
|
|||||||
@@ -28,18 +28,17 @@ from xml.etree import ElementTree as ET
|
|||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from PyQt6.QtCore import QMimeData, QUrl
|
from PyQt6.QtCore import QMimeData, QUrl
|
||||||
from PyQt6.QtGui import QColor, QDesktopServices, QFont, QFontDatabase, QFontInfo
|
from PyQt6.QtGui import QDesktopServices, QFont, QFontDatabase, QFontInfo
|
||||||
|
|
||||||
from novelwriter.common import (
|
from novelwriter.common import (
|
||||||
NWConfigParser, checkBool, checkFloat, checkInt, checkIntTuple, checkPath,
|
NWConfigParser, checkBool, checkFloat, checkInt, checkIntTuple, checkPath,
|
||||||
checkString, checkStringNone, checkUuid, compact, cssCol,
|
checkString, checkStringNone, checkUuid, compact, decodeMimeHandles,
|
||||||
decodeMimeHandles, describeFont, elide, encodeMimeHandles, firstFloat,
|
describeFont, elide, encodeMimeHandles, firstFloat, fontMatcher,
|
||||||
fontMatcher, formatFileFilter, formatInt, formatTime, formatTimeStamp,
|
formatFileFilter, formatInt, formatTime, formatTimeStamp, formatVersion,
|
||||||
formatVersion, fuzzyTime, getFileSize, hexToInt, isHandle, isItemClass,
|
fuzzyTime, getFileSize, hexToInt, isHandle, isItemClass, isItemLayout,
|
||||||
isItemLayout, isItemType, isListInstance, isTitleTag, jsonEncode,
|
isItemType, isListInstance, isTitleTag, jsonEncode, makeFileNameSafe,
|
||||||
makeFileNameSafe, minmax, numberToRoman, openExternalPath, readTextFile,
|
minmax, numberToRoman, openExternalPath, readTextFile, simplified,
|
||||||
simplified, transferCase, uniqueCompact, xmlElement, xmlIndent, xmlSubElem,
|
transferCase, uniqueCompact, xmlElement, xmlIndent, xmlSubElem, yesNo
|
||||||
yesNo
|
|
||||||
)
|
)
|
||||||
|
|
||||||
from tests.mocked import causeOSError
|
from tests.mocked import causeOSError
|
||||||
@@ -512,13 +511,6 @@ def testBaseCommon_numberToRoman():
|
|||||||
assert numberToRoman(999, True) == "cmxcix"
|
assert numberToRoman(999, True) == "cmxcix"
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.base
|
|
||||||
def testBaseCommon_cssCol():
|
|
||||||
"""Test the cssCol function."""
|
|
||||||
assert cssCol(QColor(0, 0, 0, 0)) == "rgba(0, 0, 0, 0)"
|
|
||||||
assert cssCol(QColor(10, 20, 30, 40)) == "rgba(10, 20, 30, 40)"
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.base
|
@pytest.mark.base
|
||||||
def testBaseCommon_describeFont():
|
def testBaseCommon_describeFont():
|
||||||
"""Test the describeFont function."""
|
"""Test the describeFont function."""
|
||||||
|
|||||||
Reference in New Issue
Block a user