Compare commits

...

4 Commits

Author SHA1 Message Date
Talley Lambert
0fd25aa665 chore: changelog v0.6.1 2023-10-10 13:27:07 -04:00
Talley Lambert
a5740f0109 feat: add QIcon backed by iconify (#209)
* feat: add iconify

* update docs

* update docs

* rearrange

* update example

* update test deps

* importorskip

* Update src/superqt/iconify/__init__.py

Co-authored-by: Grzegorz Bokota <bokota+github@gmail.com>

* Update src/superqt/iconify/__init__.py

Co-authored-by: Grzegorz Bokota <bokota+github@gmail.com>

* merge

* change test

* bump dep

* change doc

* Update src/superqt/iconify/__init__.py

Co-authored-by: Grzegorz Bokota <bokota+github@gmail.com>

* pragma and bump version

---------

Co-authored-by: Grzegorz Bokota <bokota+github@gmail.com>
2023-10-09 09:20:42 -04:00
Talley Lambert
65a4a6e17c ci: test python 3.12 (#181)
* ci: test 3.12

* ci: try pyqt6

* update pyproject

* test: try macos
2023-10-08 14:15:49 -04:00
pre-commit-ci[bot]
6f74c6905e ci: [pre-commit.ci] autoupdate (#210)
* ci: [pre-commit.ci] autoupdate

updates:
- [github.com/psf/black: 23.7.0 → 23.9.1](https://github.com/psf/black/compare/23.7.0...23.9.1)
- [github.com/astral-sh/ruff-pre-commit: v0.0.287 → v0.0.292](https://github.com/astral-sh/ruff-pre-commit/compare/v0.0.287...v0.0.292)

* style: [pre-commit.ci] auto fixes [...]

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-10-03 18:35:12 +02:00
10 changed files with 141 additions and 5 deletions

View File

@@ -47,6 +47,10 @@ jobs:
platform: windows-latest
backend: pyside6
- python-version: "3.12"
platform: macos-latest
backend: pyqt6
# legacy Qt
- python-version: 3.8
platform: ubuntu-latest

View File

@@ -12,12 +12,12 @@ repos:
- id: trailing-whitespace
- repo: https://github.com/psf/black
rev: 23.7.0
rev: 23.9.1
hooks:
- id: black
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.0.287
rev: v0.0.292
hooks:
- id: ruff
args: ["--fix"]

View File

@@ -1,5 +1,17 @@
# Changelog
## [v0.6.1](https://github.com/pyapp-kit/superqt/tree/v0.6.1) (2023-10-10)
[Full Changelog](https://github.com/pyapp-kit/superqt/compare/v0.6.0...v0.6.1)
**Implemented enhancements:**
- feat: add QIcon backed by iconify [\#209](https://github.com/pyapp-kit/superqt/pull/209) ([tlambert03](https://github.com/tlambert03))
**Merged pull requests:**
- ci: test python 3.12 [\#181](https://github.com/pyapp-kit/superqt/pull/181) ([tlambert03](https://github.com/tlambert03))
## [v0.6.0](https://github.com/pyapp-kit/superqt/tree/v0.6.0) (2023-09-25)
[Full Changelog](https://github.com/pyapp-kit/superqt/compare/v0.5.4...v0.6.0)
@@ -370,13 +382,17 @@
## [v0.2.1](https://github.com/pyapp-kit/superqt/tree/v0.2.1) (2021-07-10)
[Full Changelog](https://github.com/pyapp-kit/superqt/compare/v0.2.0...v0.2.1)
[Full Changelog](https://github.com/pyapp-kit/superqt/compare/v0.2.0rc0...v0.2.1)
**Fixed bugs:**
- Fix QLabeledRangeSlider API \(fix slider proxy\) [\#10](https://github.com/pyapp-kit/superqt/pull/10) ([tlambert03](https://github.com/tlambert03))
- Fix range slider with negative min range [\#9](https://github.com/pyapp-kit/superqt/pull/9) ([tlambert03](https://github.com/tlambert03))
## [v0.2.0rc0](https://github.com/pyapp-kit/superqt/tree/v0.2.0rc0) (2021-06-26)
[Full Changelog](https://github.com/pyapp-kit/superqt/compare/v0.2.0...v0.2.0rc0)
\* *This Changelog was automatically generated by [github_changelog_generator](https://github.com/github-changelog-generator/github-changelog-generator)*

14
examples/iconify.py Normal file
View File

@@ -0,0 +1,14 @@
from qtpy.QtCore import QSize
from qtpy.QtWidgets import QApplication, QPushButton
from superqt import QIconifyIcon
app = QApplication([])
btn = QPushButton()
# search https://icon-sets.iconify.design for available icon keys
btn.setIcon(QIconifyIcon("fluent-emoji-flat:alarm-clock"))
btn.setIconSize(QSize(60, 60))
btn.show()
app.exec()

View File

@@ -32,6 +32,7 @@ classifiers = [
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Topic :: Desktop Environment",
"Topic :: Software Development :: User Interfaces",
"Topic :: Software Development :: Widget Sets",
@@ -47,7 +48,7 @@ dependencies = [
# extras
# https://peps.python.org/pep-0621/#dependencies-optional-dependencies
[project.optional-dependencies]
test = ["pint", "pytest", "pytest-cov", "pytest-qt", "numpy", "cmap"]
test = ["pint", "pytest", "pytest-cov", "pytest-qt", "numpy", "cmap", "pyconify"]
dev = [
"black",
"ipython",
@@ -73,6 +74,7 @@ font-fa5 = ["fonticon-fontawesome5"]
font-fa6 = ["fonticon-fontawesome6"]
font-mi6 = ["fonticon-materialdesignicons6"]
font-mi7 = ["fonticon-materialdesignicons7"]
iconify = ["pyconify >=0.1.4"]
[project.urls]
Documentation = "https://pyapp-kit.github.io/superqt/"

View File

@@ -10,6 +10,7 @@ except PackageNotFoundError:
from .collapsible import QCollapsible
from .combobox import QColorComboBox, QEnumComboBox, QSearchableComboBox
from .elidable import QElidingLabel, QElidingLineEdit
from .iconify import QIconifyIcon
from .selection import QSearchableListWidget, QSearchableTreeWidget
from .sliders import (
QDoubleRangeSlider,
@@ -35,6 +36,7 @@ __all__ = [
"QElidingLineEdit",
"QEnumComboBox",
"QLabeledDoubleRangeSlider",
"QIconifyIcon",
"QLabeledDoubleSlider",
"QLabeledRangeSlider",
"QLabeledSlider",

View File

@@ -10,6 +10,7 @@ __all__ = [
"IconFontMeta",
"IconOpts",
"pulse",
"QIconifyIcon",
"setTextIcon",
"spin",
]

View File

@@ -0,0 +1,75 @@
from __future__ import annotations
from typing import TYPE_CHECKING
from qtpy.QtGui import QIcon
if TYPE_CHECKING:
from typing import Literal
Flip = Literal["horizontal", "vertical", "horizontal,vertical"]
Rotation = Literal["90", "180", "270", 90, 180, 270, "-90", 1, 2, 3]
class QIconifyIcon(QIcon):
"""QIcon backed by an iconify icon.
Iconify includes 150,000+ icons from most major icon sets including Bootstrap,
FontAwesome, Material Design, and many more.
Search availble icons at https://icon-sets.iconify.design
Once you find one you like, use the key in the format `"prefix:name"` to create an
icon: `QIconifyIcon("bi:bell")`.
This class is a thin wrapper around the
[pyconify](https://github.com/pyapp-kit/pyconify) `svg_path` function. It pulls SVGs
from iconify, creates a temporary SVG file and uses it as the source for a QIcon.
SVGs are cached to disk, and persist across sessions (until `pyconify.clear_cache()`
is called).
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.
Examples
--------
>>> from qtpy.QtWidgets import QPushButton
>>> from superqt import QIconifyIcon
>>> btn = QPushButton()
>>> icon = QIconifyIcon("bi:alarm-fill", color="red", rotate=90)
>>> btn.setIcon(icon)
"""
def __init__(
self,
*key: str,
color: str | None = None,
flip: Flip | None = None,
rotate: Rotation | None = None,
dir: str | None = None,
):
try:
from pyconify import svg_path
except ModuleNotFoundError as e: # pragma: no cover
raise ImportError(
"pyconify is required to use QIconifyIcon. "
"Please install it with `pip install pyconify` or use the "
"`pip install superqt[iconify]` extra."
) from e
self.path = svg_path(*key, color=color, flip=flip, rotate=rotate, dir=dir)
super().__init__(str(self.path))

View File

@@ -187,5 +187,5 @@ def _run_in_thread(
f = CallCallable(func, args, kwargs)
f.moveToThread(thread)
f.finished.connect(future.set_result, Qt.ConnectionType.DirectConnection)
QMetaObject.invokeMethod(f, "call", Qt.ConnectionType.QueuedConnection) # type: ignore # noqa
QMetaObject.invokeMethod(f, "call", Qt.ConnectionType.QueuedConnection) # type: ignore
return future.result(timeout=timeout / 1000) if await_return else future

22
tests/test_iconify.py Normal file
View File

@@ -0,0 +1,22 @@
from typing import TYPE_CHECKING
import pytest
from qtpy.QtWidgets import QPushButton
from superqt import QIconifyIcon
if TYPE_CHECKING:
from pytestqt.qtbot import QtBot
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")
btn = QPushButton()
qtbot.addWidget(btn)
btn.setIcon(icon)
btn.show()