diff --git a/src/calibre/gui2/__init__.py b/src/calibre/gui2/__init__.py index ebd5cefe4b..27b80d03ae 100644 --- a/src/calibre/gui2/__init__.py +++ b/src/calibre/gui2/__init__.py @@ -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: diff --git a/src/calibre/gui2/palette.py b/src/calibre/gui2/palette.py index 8fcc67a241..0c9a9b377b 100644 --- a/src/calibre/gui2/palette.py +++ b/src/calibre/gui2/palette.py @@ -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): diff --git a/src/calibre/gui2/progress_indicator/QProgressIndicator.cpp b/src/calibre/gui2/progress_indicator/QProgressIndicator.cpp index 4f427d5721..f9fc699365 100644 --- a/src/calibre/gui2/progress_indicator/QProgressIndicator.cpp +++ b/src/calibre/gui2/progress_indicator/QProgressIndicator.cpp @@ -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(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 &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); } diff --git a/src/calibre/gui2/progress_indicator/QProgressIndicator.h b/src/calibre/gui2/progress_indicator/QProgressIndicator.h index 4df2f88c01..09cd667c8b 100644 --- a/src/calibre/gui2/progress_indicator/QProgressIndicator.h +++ b/src/calibre/gui2/progress_indicator/QProgressIndicator.h @@ -91,14 +91,12 @@ private: class CalibreStyle : public QProxyStyle { protected: - QHash icon_map; QByteArray desktop_environment; QDialogButtonBox::ButtonLayout button_layout; int transient_scroller; public: CalibreStyle(int transient_scroller); - void set_icon_map(QHash &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; diff --git a/src/calibre/gui2/progress_indicator/QProgressIndicator.sip b/src/calibre/gui2/progress_indicator/QProgressIndicator.sip index ac0d517032..5128685841 100644 --- a/src/calibre/gui2/progress_indicator/QProgressIndicator.sip +++ b/src/calibre/gui2/progress_indicator/QProgressIndicator.sip @@ -18,19 +18,6 @@ class CalibreStyle : QProxyStyle { public: CalibreStyle(int transient_scroller); - - void set_icon_map(SIP_PYDICT icon_map_); -%MethodCode - QHash 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 - - };