from __future__ import annotations
import os
from types import SimpleNamespace
from typing import TYPE_CHECKING, Any
from pathlib import Path
from qtpy.QtWidgets import QStyle, QApplication
from qtpy.QtGui import QIcon, QImage, QPixmap
from qtpy.QtCore import Qt, QSize
if TYPE_CHECKING:
from .mgui_ext import PushButtonPlus, AbstractAction
from magicgui.widgets import Widget
class _IconBase:
_source: Any
def __repr__(self) -> str:
return f"{type(self).__name__}({self._source!r})"
def get_qicon(self, dst: Widget | AbstractAction) -> QIcon:
raise NotImplementedError()
def install(self, dst: PushButtonPlus | AbstractAction) -> None:
icon = self.get_qicon(dst)
dst.native.setIcon(icon)
class StandardIcon(_IconBase):
"""An object of a standard icon."""
def __init__(self, source: Any):
if isinstance(source, str):
source = getattr(Icon, source)
self._source = source
def get_qicon(self, dst) -> QIcon:
return QApplication.style().standardIcon(self._source)
class IconPath(_IconBase):
"""An object of an icon from a path."""
def __init__(self, source: Any):
self._source = str(source)
def __str__(self) -> str:
return self._source
def get_qicon(self, dst) -> QIcon:
return QIcon(self._source)
class ArrayIcon(_IconBase):
"""An object of an icon from numpy array."""
_source: QImage
def __init__(self, source: Any):
import numpy as np
arr = np.asarray(source)
from magicclass._magicgui_compat import _mpl_image
img = _mpl_image.Image()
img.set_data(arr)
val: np.ndarray = img.make_image()
h, w, _ = val.shape
self._source = QImage(val, w, h, QImage.Format.Format_RGBA8888)
def get_qicon(self, dst) -> QIcon:
if hasattr(dst.native, "size"):
qsize = dst.native.size()
else:
qsize = QSize(32, 32)
qimg = self._source.scaled(
qsize,
Qt.AspectRatioMode.KeepAspectRatio,
Qt.TransformationMode.SmoothTransformation,
)
qpix = QPixmap.fromImage(qimg)
return QIcon(qpix)
def get_icon(val: Any) -> _IconBase:
"""Get a proper icon object from a value."""
if isinstance(val, _IconBase):
icon = val
elif isinstance(val, int):
icon = StandardIcon(val)
elif isinstance(val, Path) or os.path.exists(val):
icon = IconPath(val)
elif hasattr(val, "__array__"):
icon = ArrayIcon(val)
elif isinstance(val, str) and hasattr(Icon, val):
icon = StandardIcon(val)
else:
raise TypeError(f"Input {val!r} cannot be converted to an icon.")
return icon
class _StandardPixmap:
"""To avoid version dependency."""
def __getattr__(self, name):
return getattr(QStyle.StandardPixmap, name, None)
sp = _StandardPixmap()
[docs]class Icon(SimpleNamespace):
"""
Namespace of icons.
.. code-block:: python
from magicclass import magicclass, set_design, Icon
@magicclass
class A:
@set_design(icon=Icon.FileIcon)
def func(self):
...
"""
# fmt: off
TitleBarMenuButton = sp.SP_TitleBarMenuButton
TitleBarMinButton = sp.SP_TitleBarMinButton
TitleBarMaxButton = sp.SP_TitleBarMaxButton
TitleBarCloseButton = sp.SP_TitleBarCloseButton
TitleBarNormalButton = sp.SP_TitleBarNormalButton
TitleBarShadeButton = sp.SP_TitleBarShadeButton
TitleBarUnshadeButton = sp.SP_TitleBarUnshadeButton
TitleBarContextHelpButton = sp.SP_TitleBarContextHelpButton
MessageBoxInformation = sp.SP_MessageBoxInformation
MessageBoxWarning = sp.SP_MessageBoxWarning
MessageBoxCritical = sp.SP_MessageBoxCritical
MessageBoxQuestion = sp.SP_MessageBoxQuestion
DockWidgetCloseButton = sp.SP_DockWidgetCloseButton
DesktopIcon = sp.SP_DesktopIcon
TrashIcon = sp.SP_TrashIcon
ComputerIcon = sp.SP_ComputerIcon
DriveFDIcon = sp.SP_DriveFDIcon
DriveHDIcon = sp.SP_DriveHDIcon
DriveCDIcon = sp.SP_DriveCDIcon
DriveDVDIcon = sp.SP_DriveDVDIcon
DriveNetIcon = sp.SP_DriveNetIcon
DirOpenIcon = sp.SP_DirOpenIcon
DirClosedIcon = sp.SP_DirClosedIcon
DirLinkIcon = sp.SP_DirLinkIcon
FileIcon = sp.SP_FileIcon
FileLinkIcon = sp.SP_FileLinkIcon
ToolBarHorizontalExtensionButton = sp.SP_ToolBarHorizontalExtensionButton
ToolBarVerticalExtensionButton = sp.SP_ToolBarVerticalExtensionButton
FileDialogStart = sp.SP_FileDialogStart
FileDialogEnd = sp.SP_FileDialogEnd
FileDialogToParent = sp.SP_FileDialogToParent
FileDialogNewFolder = sp.SP_FileDialogNewFolder
FileDialogDetailedView = sp.SP_FileDialogDetailedView
FileDialogInfoView = sp.SP_FileDialogInfoView
FileDialogContentsView = sp.SP_FileDialogContentsView
FileDialogListView = sp.SP_FileDialogListView
FileDialogBack = sp.SP_FileDialogBack
DirIcon = sp.SP_DirIcon
DialogOkButton = sp.SP_DialogOkButton
DialogCancelButton = sp.SP_DialogCancelButton
DialogHelpButton = sp.SP_DialogHelpButton
DialogOpenButton = sp.SP_DialogOpenButton
DialogSaveButton = sp.SP_DialogSaveButton
DialogCloseButton = sp.SP_DialogCloseButton
DialogApplyButton = sp.SP_DialogApplyButton
DialogResetButton = sp.SP_DialogResetButton
DialogDiscardButton = sp.SP_DialogDiscardButton
DialogYesButton = sp.SP_DialogYesButton
DialogNoButton = sp.SP_DialogNoButton
ArrowUp = sp.SP_ArrowUp
ArrowDown = sp.SP_ArrowDown
ArrowLeft = sp.SP_ArrowLeft
ArrowRight = sp.SP_ArrowRight
ArrowBack = sp.SP_ArrowBack
ArrowForward = sp.SP_ArrowForward
DirHomeIcon = sp.SP_DirHomeIcon
CommandLink = sp.SP_CommandLink
VistaShield = sp.SP_VistaShield
BrowserReload = sp.SP_BrowserReload
BrowserStop = sp.SP_BrowserStop
MediaPlay = sp.SP_MediaPlay
MediaStop = sp.SP_MediaStop
MediaPause = sp.SP_MediaPause
MediaSkipForward = sp.SP_MediaSkipForward
MediaSkipBackward = sp.SP_MediaSkipBackward
MediaSeekForward = sp.SP_MediaSeekForward
MediaSeekBackward = sp.SP_MediaSeekBackward
MediaVolume = sp.SP_MediaVolume
MediaVolumeMuted = sp.SP_MediaVolumeMuted
DirLinkOpenIcon = sp.SP_DirLinkOpenIcon
LineEditClearButton = sp.SP_LineEditClearButton
DialogYesToAllButton = sp.SP_DialogYesToAllButton
DialogNoToAllButton = sp.SP_DialogNoToAllButton
DialogSaveAllButton = sp.SP_DialogSaveAllButton
DialogAbortButton = sp.SP_DialogAbortButton
DialogRetryButton = sp.SP_DialogRetryButton
DialogIgnoreButton = sp.SP_DialogIgnoreButton
RestoreDefaultsButton = sp.SP_RestoreDefaultsButton
CustomBase = sp.SP_CustomBase
# fmt: on