Use QIcon.ic for Qt standard pixmaps as well

DRYer and much simpler code
This commit is contained in:
Kovid Goyal 2022-07-19 18:55:24 +05:30
parent 2584edd461
commit 178e75a58e
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
5 changed files with 52 additions and 80 deletions

View File

@ -16,7 +16,7 @@ from qt.core import (
QFont, QFontDatabase, QFontInfo, QFontMetrics, QGuiApplication, QIcon, QIODevice,
QLocale, QNetworkProxyFactory, QObject, QPalette, QResource, QSettings,
QSocketNotifier, QStringListModel, Qt, QThread, QTimer, QTranslator,
QUrl, pyqtSignal
QUrl, pyqtSignal, pyqtSlot
)
from threading import Lock, RLock
@ -1161,6 +1161,10 @@ class Application(QApplication):
def is_dark_theme(self):
return self.palette_manager.is_dark_theme
@pyqtSlot(int, result=QIcon)
def get_qt_standard_icon(self, standard_pixmap):
return self.palette_manager.get_qt_standard_icon(standard_pixmap)
def safe_restore_geometry(self, widget, geom):
# See https://bugreports.qt.io/browse/QTBUG-77385
if not geom:

View File

@ -4,7 +4,6 @@
import os
import sys
from contextlib import contextmanager
from functools import lru_cache
from qt.core import (
QAbstractNativeEventFilter, QApplication, QColor, QIcon, QPalette, QSettings,
QStyle, Qt, QTimer, pyqtSlot, QObject, QDataStream, QByteArray, QIODeviceBase
@ -135,7 +134,7 @@ def dark_palette():
return p
def light_palette():
def light_palette(): # {{{
# generated by serializing the light palette on my Linux system
self = QPalette()
self.setColor(QPalette.ColorGroup.Active, QPalette.ColorRole.WindowText, QColor(0, 0, 0, 255))
@ -223,6 +222,40 @@ def light_palette():
self.setColor(QPalette.ColorGroup.Current, QPalette.ColorRole.PlaceholderText, QColor(0, 0, 0, 128))
self.setColor(QPalette.ColorGroup.Current, QPalette.ColorRole.NoRole, QColor(0, 0, 0, 255))
return self
# }}}
standard_pixmaps = { # {{{
QStyle.StandardPixmap.SP_DialogYesButton: 'ok.png',
QStyle.StandardPixmap.SP_DialogNoButton: 'window-close.png',
QStyle.StandardPixmap.SP_DialogCloseButton: 'close.png',
QStyle.StandardPixmap.SP_DialogOkButton: 'ok.png',
QStyle.StandardPixmap.SP_DialogCancelButton: 'window-close.png',
QStyle.StandardPixmap.SP_DialogHelpButton: 'help.png',
QStyle.StandardPixmap.SP_DialogOpenButton: 'document_open.png',
QStyle.StandardPixmap.SP_DialogSaveButton: 'save.png',
QStyle.StandardPixmap.SP_DialogApplyButton: 'ok.png',
QStyle.StandardPixmap.SP_DialogDiscardButton: 'trash.png',
QStyle.StandardPixmap.SP_MessageBoxInformation: 'dialog_information.png',
QStyle.StandardPixmap.SP_MessageBoxWarning: 'dialog_warning.png',
QStyle.StandardPixmap.SP_MessageBoxCritical: 'dialog_error.png',
QStyle.StandardPixmap.SP_MessageBoxQuestion: 'dialog_question.png',
QStyle.StandardPixmap.SP_BrowserReload: 'view-refresh.png',
QStyle.StandardPixmap.SP_LineEditClearButton: 'clear_left.png',
QStyle.StandardPixmap.SP_ToolBarHorizontalExtensionButton: 'v-ellipsis.png',
QStyle.StandardPixmap.SP_ToolBarVerticalExtensionButton: 'h-ellipsis.png',
QStyle.StandardPixmap.SP_FileDialogBack: 'back.png',
QStyle.StandardPixmap.SP_ArrowRight: 'forward.png',
QStyle.StandardPixmap.SP_ArrowLeft: 'back.png',
QStyle.StandardPixmap.SP_ArrowBack: 'back.png',
QStyle.StandardPixmap.SP_ArrowForward: 'forward.png',
QStyle.StandardPixmap.SP_ArrowUp: 'arrow-up.png',
QStyle.StandardPixmap.SP_ArrowDown: 'arrow-down.png',
QStyle.StandardPixmap.SP_FileDialogToParent: 'arrow-up.png',
QStyle.StandardPixmap.SP_FileDialogNewFolder: 'tb_folder.png',
QStyle.StandardPixmap.SP_FileDialogListView: 'format-list-unordered.png',
QStyle.StandardPixmap.SP_FileDialogDetailedView: 'format-list-ordered.png',
} # }}}
class PaletteManager(QObject):
@ -301,52 +334,15 @@ class PaletteManager(QObject):
self.load_calibre_style()
self.on_palette_change()
def get_qt_standard_icon(self, standard_pixmap):
from qt.core import QStyle
sp = QStyle.StandardPixmap(standard_pixmap)
val = standard_pixmaps.get(sp)
if val is None:
return QIcon()
return QIcon.ic(val)
def load_calibre_style(self):
icon_map = self.__icon_map_memory_ = {}
user_path = QIcon.ic.override_icon_path
if user_path:
user_path = os.path.join(user_path, 'images')
@lru_cache(maxsize=64)
def check_for_custom_icon(v):
if user_path:
q = os.path.join(user_path, v)
if os.path.exists(q):
return q
return v.rpartition('.')[0]
for k, v in {
'DialogYesButton': 'ok.png',
'DialogNoButton': 'window-close.png',
'DialogCloseButton': 'close.png',
'DialogOkButton': 'ok.png',
'DialogCancelButton': 'window-close.png',
'DialogHelpButton': 'help.png',
'DialogOpenButton': 'document_open.png',
'DialogSaveButton': 'save.png',
'DialogApplyButton': 'ok.png',
'DialogDiscardButton': 'trash.png',
'MessageBoxInformation': 'dialog_information.png',
'MessageBoxWarning': 'dialog_warning.png',
'MessageBoxCritical': 'dialog_error.png',
'MessageBoxQuestion': 'dialog_question.png',
'BrowserReload': 'view-refresh.png',
'LineEditClearButton': 'clear_left.png',
'ToolBarHorizontalExtensionButton': 'v-ellipsis.png',
'ToolBarVerticalExtensionButton': 'h-ellipsis.png',
'FileDialogBack': 'back.png',
'ArrowRight': 'forward.png',
'ArrowLeft': 'back.png',
'ArrowBack': 'back.png',
'ArrowForward': 'forward.png',
'ArrowUp': 'arrow-up.png',
'ArrowDown': 'arrow-down.png',
'FileDialogToParent': 'arrow-up.png',
'FileDialogNewFolder': 'tb_folder.png',
'FileDialogListView': 'format-list-unordered.png',
'FileDialogDetailedView': 'format-list-ordered.png',
}.items():
icon_map[getattr(QStyle.StandardPixmap, 'SP_'+k).value] = check_for_custom_icon(v)
transient_scroller = 0
if ismacos:
from calibre_extensions.cocoa import transient_scroller
@ -354,7 +350,6 @@ class PaletteManager(QObject):
app = QApplication.instance()
from calibre_extensions.progress_indicator import CalibreStyle
self.calibre_style = style = CalibreStyle(transient_scroller)
style.set_icon_map(icon_map)
app.setStyle(style)
def on_palette_change(self):

View File

@ -118,7 +118,7 @@ dpiScaled(qreal value) {
#endif
}
CalibreStyle::CalibreStyle(int transient_scroller) : QProxyStyle(QString::fromUtf8("Fusion")), icon_map(), transient_scroller(transient_scroller) {
CalibreStyle::CalibreStyle(int transient_scroller) : QProxyStyle(QString::fromUtf8("Fusion")), transient_scroller(transient_scroller) {
setObjectName(QString("calibre"));
desktop_environment = detectDesktopEnvironment();
button_layout = static_cast<QDialogButtonBox::ButtonLayout>(QProxyStyle::styleHint(SH_DialogButtonLayout));
@ -126,10 +126,6 @@ CalibreStyle::CalibreStyle(int transient_scroller) : QProxyStyle(QString::fromUt
button_layout = QDialogButtonBox::GnomeLayout;
}
void CalibreStyle::set_icon_map(QHash<unsigned long, QString> &ic) {
icon_map = ic;
}
int CalibreStyle::styleHint(StyleHint hint, const QStyleOption *option, const QWidget *widget, QStyleHintReturn *returnData) const {
switch (hint) {
case SH_DialogButtonBox_ButtonsHaveIcons:
@ -157,17 +153,9 @@ int CalibreStyle::styleHint(StyleHint hint, const QStyleOption *option, const QW
}
QIcon CalibreStyle::standardIcon(StandardPixmap standardIcon, const QStyleOption * option, const QWidget * widget) const {
if (icon_map.contains(standardIcon)) {
QString q = icon_map.value(standardIcon);
if (q.contains('.')) return QIcon(q);
QIcon ans = QIcon::fromTheme(icon_map.value(standardIcon));
if (ans.isNull() && QIcon::themeName().contains("user-any")) {
const bool is_dark_theme = QApplication::instance()->property("is_dark_theme").toBool();
QIcon q(QString(":/icons/calibre-default-%1/images/%2.png").arg(is_dark_theme ? "dark" : "light").arg(icon_map.value(standardIcon)));
if (!q.isNull()) ans = q;
}
return ans;
}
QIcon ret;
QMetaObject::invokeMethod(QApplication::instance(), "get_qt_standard_icon", Q_RETURN_ARG(QIcon, ret), Q_ARG(int, standardIcon));
if (!ret.isNull()) return ret;
return QProxyStyle::standardIcon(standardIcon, option, widget);
}

View File

@ -91,14 +91,12 @@ private:
class CalibreStyle : public QProxyStyle {
protected:
QHash<unsigned long, QString> icon_map;
QByteArray desktop_environment;
QDialogButtonBox::ButtonLayout button_layout;
int transient_scroller;
public:
CalibreStyle(int transient_scroller);
void set_icon_map(QHash<unsigned long, QString> &icon_map);
virtual int styleHint(StyleHint hint, const QStyleOption *option = 0, const QWidget *widget = 0, QStyleHintReturn *returnData = 0) const;
virtual QIcon standardIcon(StandardPixmap standardIcon, const QStyleOption * option = 0, const QWidget * widget = 0) const;
virtual int pixelMetric(PixelMetric metric, const QStyleOption * option = 0, const QWidget * widget = 0) const;

View File

@ -18,19 +18,6 @@ class CalibreStyle : QProxyStyle {
public:
CalibreStyle(int transient_scroller);
void set_icon_map(SIP_PYDICT icon_map_);
%MethodCode
QHash<unsigned long, QString> icon_map;
PyObject *key, *value;
Py_ssize_t pos = 0;
while (PyDict_Next(a0, &pos, &key, &value)) {
icon_map.insert(PyLong_AsUnsignedLong(key), QString::fromUtf8(PyUnicode_AsUTF8(value)));
}
sipCpp->set_icon_map(icon_map);
%End
};