From b927159f49104a8cb90f205d4b82d7ed89a7e1cc Mon Sep 17 00:00:00 2001 From: Talley Lambert Date: Wed, 8 Nov 2023 12:52:41 -0500 Subject: [PATCH] feat: add addKey method to QIconifyIcon (#218) * feat: addKey method to Iconify * style: [pre-commit.ci] auto fixes [...] * remove breakpoint --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- src/superqt/iconify/__init__.py | 71 ++++++++++++++++++++++++++------- tests/test_iconify.py | 6 +-- 2 files changed, 60 insertions(+), 17 deletions(-) diff --git a/src/superqt/iconify/__init__.py b/src/superqt/iconify/__init__.py index 8932270..7549cfe 100644 --- a/src/superqt/iconify/__init__.py +++ b/src/superqt/iconify/__init__.py @@ -2,6 +2,7 @@ from __future__ import annotations from typing import TYPE_CHECKING +from qtpy.QtCore import QSize from qtpy.QtGui import QIcon if TYPE_CHECKING: @@ -10,6 +11,11 @@ if TYPE_CHECKING: Flip = Literal["horizontal", "vertical", "horizontal,vertical"] Rotation = Literal["90", "180", "270", 90, 180, 270, "-90", 1, 2, 3] +try: + from pyconify import svg_path +except ModuleNotFoundError: # pragma: no cover + svg_path = None + class QIconifyIcon(QIcon): """QIcon backed by an iconify icon. @@ -27,6 +33,9 @@ class QIconifyIcon(QIcon): SVGs are cached to disk, and persist across sessions (until `pyconify.clear_cache()` is called). + Parameters are the same as `QIconifyIcon.addKey`, which can be used to add + additional icons for various modes and states to the same QIcon. + Parameters ---------- *key: str @@ -63,21 +72,55 @@ class QIconifyIcon(QIcon): rotate: Rotation | None = None, dir: str | None = None, ): - try: - from pyconify import svg_path - except ModuleNotFoundError as e: # pragma: no cover - raise ImportError( + if svg_path is None: # pragma: no cover + raise ModuleNotFoundError( "pyconify is required to use QIconifyIcon. " "Please install it with `pip install pyconify` or use the " "`pip install superqt[iconify]` extra." - ) from e - if len(key) == 1: - self._name = key[0] - else: - self._name = ":".join(key) - self.path = svg_path(*key, color=color, flip=flip, rotate=rotate, dir=dir) - super().__init__(str(self.path)) + ) + super().__init__() + self.addKey(*key, color=color, flip=flip, rotate=rotate, dir=dir) - def name(self) -> str: - """Return the iconify `prefix:icon` represented by this QIcon.""" - return self._name + def addKey( + self, + *key: str, + color: str | None = None, + flip: Flip | None = None, + rotate: Rotation | None = None, + dir: str | None = None, + size: QSize | None = None, + mode: QIcon.Mode = QIcon.Mode.Normal, + state: QIcon.State = QIcon.State.Off, + ) -> None: + """Add an icon to this QIcon. + + This is a variant of `QIcon.addFile` that uses an iconify icon keys and + arguments instead of a file path. + + Parameters + ---------- + *key: str + Icon set prefix and name. May be passed as a single string in the format + `"prefix:name"` or as two separate strings: `'prefix', 'name'`. + color : str, optional + Icon color. If not provided, the icon will appear black (the icon fill color + will be set to the string "currentColor"). + flip : str, optional + Flip icon. Must be one of "horizontal", "vertical", "horizontal,vertical" + rotate : str | int, optional + Rotate icon. Must be one of 0, 90, 180, 270, or 0, 1, 2, 3 (equivalent to 0, + 90, 180, 270, respectively) + dir : str, optional + If 'dir' is not None, the file will be created in that directory, otherwise + a default + [directory](https://docs.python.org/3/library/tempfile.html#tempfile.mkstemp) + is used. + size : QSize, optional + Size specified for the icon, passed to `QIcon.addFile`. + mode : QIcon.Mode, optional + Mode specified for the icon, passed to `QIcon.addFile`. + state : QIcon.State, optional + State specified for the icon, passed to `QIcon.addFile`. + """ + path = svg_path(*key, color=color, flip=flip, rotate=rotate, dir=dir) + self.addFile(str(path), size or QSize(), mode, state) diff --git a/tests/test_iconify.py b/tests/test_iconify.py index 3bcb167..4c5a2cc 100644 --- a/tests/test_iconify.py +++ b/tests/test_iconify.py @@ -1,6 +1,7 @@ from typing import TYPE_CHECKING import pytest +from qtpy.QtGui import QIcon from qtpy.QtWidgets import QPushButton from superqt import QIconifyIcon @@ -13,9 +14,8 @@ def test_qiconify(qtbot: "QtBot", monkeypatch: "pytest.MonkeyPatch") -> None: monkeypatch.setenv("PYCONIFY_CACHE", "0") pytest.importorskip("pyconify") - icon = QIconifyIcon("bi:alarm-fill", color="red", rotate=90) - assert icon.path.name.endswith(".svg") - assert icon.name() == "bi:alarm-fill" + icon = QIconifyIcon("bi:alarm-fill", color="red", flip="vertical") + icon.addKey("bi:alarm", color="blue", rotate=90, state=QIcon.State.On) btn = QPushButton() qtbot.addWidget(btn)