Skip to content

Commit

Permalink
feat: working on qt
Browse files Browse the repository at this point in the history
  • Loading branch information
tlambert03 committed Sep 28, 2023
1 parent 0f0542f commit a8f0e4c
Show file tree
Hide file tree
Showing 4 changed files with 108 additions and 0 deletions.
13 changes: 13 additions & 0 deletions example.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
from pyconify.qt import QIconify
from qtpy.QtCore import QSize
from qtpy.QtWidgets import QApplication, QPushButton

app = QApplication([])

btn = QPushButton()
icon = QIconify("iconamoon:3d-fill", color="cornflowerblue")
btn.setIcon(icon)
btn.setIconSize(QSize(30, 30))
btn.show()

app.exec()
3 changes: 3 additions & 0 deletions src/pyconify/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,6 @@
__version__ = "uninstalled"
__author__ = "Talley Lambert"
__email__ = "talley.lambert@gmail.com"
__all__ = ["svg", "collection", "collections", "icon_data", "search"]

from .api import collection, collections, icon_data, search, svg
29 changes: 29 additions & 0 deletions src/pyconify/_util.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
from collections import defaultdict
from pathlib import Path


def update_type_hints():
from pyconify import api

collections = api.collections()
all_icons: defaultdict[str, set[str]] = defaultdict(set)

for prefix in list(collections)[:1]:
icons = api.collection(prefix)
for icon_list in icons.get("categories", {}).values():
all_icons[prefix].update(icon_list)
all_icons[prefix].update(icons.get("uncategorized", []))

module = "from typing import Literal\n\n"

keys = [
f'"{prefix}:{name}"'
for prefix, names in sorted(all_icons.items())
for name in sorted(names)
]
inner = ",\n ".join(keys)
module += f"IconName = Literal[\n {inner}\n]\n"
Path(__file__).parent.joinpath("_typing.py").write_text(module)


update_type_hints()
63 changes: 63 additions & 0 deletions src/pyconify/qt.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
"""A Class for generating QIcons from SVGs with arbitrary colors at runtime."""
from typing import Literal

from qtpy.QtCore import QByteArray, QPoint, QRect, QRectF, Qt
from qtpy.QtGui import QIcon, QIconEngine, QImage, QPainter, QPixmap
from qtpy.QtSvg import QSvgRenderer

from pyconify.api import svg


class QIconify(QIcon):
def __init__(
self,
*key: str,
color: str | None = None,
flip: Literal["horizontal", "vertical", "horizontal,vertical"] | None = None,
rotate: str | int | None = None,
) -> None:
if len(key) == 1:
if ":" in key[0]:
prefix, name = key[0].split(":")
else:
raise ValueError(
"If only one argument is passed, it must be in the format "
"'prefix:name'"
)
elif len(key) == 2:
prefix, name = key
else:
raise ValueError(
"QIconify must be initialized with either 1 or 2 arguments."
)
svg_bytes = svg(prefix, name, color=color, flip=flip, rotate=rotate)
super().__init__(SVGBufferIconEngine(svg_bytes))


class SVGBufferIconEngine(QIconEngine):
"""A custom QIconEngine that can render an SVG buffer."""

def __init__(self, xml: bytes | str | QByteArray) -> None:
if isinstance(xml, str):
xml = xml.encode("utf-8")
self._data = QByteArray(xml)
self._renderer = QSvgRenderer(self._data)
self._renderer.setFramesPerSecond(20)
super().__init__()

def paint(self, painter: QPainter, rect, mode, state):
"""Paint the icon in `rect` using `painter`."""
self._renderer.render(painter, QRectF(rect))

def clone(self):
"""Required to subclass abstract QIconEngine."""
return SVGBufferIconEngine(self._data)

def pixmap(self, size, mode, state):
"""Return the icon as a pixmap with requested size, mode, and state."""
img = QImage(size, QImage.Format.Format_ARGB32)
img.fill(Qt.GlobalColor.transparent)
pixmap = QPixmap.fromImage(img, Qt.ImageConversionFlag.NoFormatConversion)
painter = QPainter(pixmap)
self.paint(painter, QRect(QPoint(0, 0), size), mode, state)
return pixmap

0 comments on commit a8f0e4c

Please sign in to comment.