1717from qtpy .QtGui import (
1818 QFont ,
1919 QFontMetrics ,
20+ QIcon ,
2021 QImage ,
2122 QKeyEvent ,
23+ QPalette ,
2224 QPixmap ,
2325 QResizeEvent ,
2426 QTextDocument ,
@@ -48,10 +50,13 @@ def _signals_blocked(obj: QtW.QWidget) -> Iterator[None]:
4850class EventFilter (QObject ):
4951 parentChanged = Signal ()
5052 valueChanged = Signal (object )
53+ paletteChanged = Signal ()
5154
5255 def eventFilter (self , obj : QObject , event : QEvent ) -> bool :
5356 if event .type () == QEvent .Type .ParentChange :
5457 self .parentChanged .emit ()
58+ if event .type () == QEvent .Type .PaletteChange :
59+ self .paletteChanged .emit ()
5560 return False
5661
5762
@@ -419,11 +424,15 @@ def _update_precision(self, **kwargs: Any) -> None:
419424# BUTTONS
420425
421426
422- class QBaseButtonWidget (QBaseValueWidget , protocols .SupportsText ):
427+ class QBaseButtonWidget (
428+ QBaseValueWidget , protocols .SupportsText , protocols .SupportsIcon
429+ ):
423430 _qwidget : QtW .QCheckBox | QtW .QPushButton | QtW .QRadioButton | QtW .QToolButton
424431
425- def __init__ (self , qwidg : type [QtW .QWidget ], ** kwargs : Any ) -> None :
432+ def __init__ (self , qwidg : type [QtW .QAbstractButton ], ** kwargs : Any ) -> None :
426433 super ().__init__ (qwidg , "isChecked" , "setChecked" , "toggled" , ** kwargs )
434+ self ._event_filter .paletteChanged .connect (self ._update_icon )
435+ self ._icon : tuple [str | None , str | None ] | None = None
427436
428437 def _mgui_set_text (self , value : str ) -> None :
429438 """Set text."""
@@ -433,12 +442,48 @@ def _mgui_get_text(self) -> str:
433442 """Get text."""
434443 return self ._qwidget .text ()
435444
445+ def _update_icon (self ) -> None :
446+ # Called when palette changes or icon is set
447+ if self ._icon :
448+ qicon = _get_qicon (* self ._icon , palette = self ._qwidget .palette ())
449+ if qicon is None :
450+ self ._icon = None # an error occurred don't try again
451+ self ._qwidget .setIcon (QIcon ())
452+ else :
453+ self ._qwidget .setIcon (qicon )
454+
455+ def _mgui_set_icon (self , value : str | None , color : str | None ) -> None :
456+ self ._icon = (value , color )
457+ self ._update_icon ()
458+
459+
460+ def _get_qicon (key : str | None , color : str | None , palette : QPalette ) -> QIcon | None :
461+ """Return a QIcon from iconify, or None if it fails."""
462+ if not key :
463+ return QIcon ()
464+
465+ if not color or color == "auto" :
466+ # use foreground color
467+ color = palette .color (QPalette .ColorRole .WindowText ).name ()
468+ # don't use full black or white
469+ color = {"#000000" : "#333333" , "#ffffff" : "#cccccc" }.get (color , color )
470+
471+ if ":" not in key :
472+ # for parity with the other backends, assume fontawesome
473+ # if no prefix is given.
474+ key = f"fa:{ key } "
475+
476+ try :
477+ return superqt .QIconifyIcon (key , color = color )
478+ except (OSError , ValueError ) as e :
479+ warnings .warn (f"Could not set iconify icon: { e } " , stacklevel = 2 )
480+ return None
481+
436482
437483class PushButton (QBaseButtonWidget ):
438484 def __init__ (self , ** kwargs : Any ) -> None :
439- QBaseValueWidget .__init__ (
440- self , QtW .QPushButton , "isChecked" , "setChecked" , "clicked" , ** kwargs
441- )
485+ super ().__init__ (QtW .QPushButton , ** kwargs )
486+ self ._onchange_name = "clicked"
442487 # make enter/return "click" the button when focused.
443488 self ._qwidget .setAutoDefault (True )
444489
0 commit comments