Icons¶
Use fxicons¶
fxicons is a module that provides a way to use library icons in your applications. It comes with 5 libraries by default: "material", "fontawesome", "simple", "brands", and "beacon". You can add your own libraries by using the add_library function.
"brands" holds the logos of the tools a studio uses: DCCs, renderers, trackers, file formats and dev tools. It used to be called "dcc", and that name still works.
Basic Usage¶
from qtpy.QtWidgets import QPushButton
from fxgui import fxicons
button = QPushButton()
button.setIcon(fxicons.get_icon("home"))
Add a Custom Library¶
from pathlib import Path
from qtpy.QtWidgets import QPushButton
from fxgui import fxicons
# Add the houdini library
fxicons.add_library(
library="houdini",
pattern="{root}/{library}/{style}/{icon_name}.{extension}",
defaults={
"extension": "svg",
"style": "CROWDS",
"color": None,
"width": 48,
"height": 48,
},
root=str(Path.home() / "Pictures" / "Icons"),
)
# Ask for an icon of that library by name
button = QPushButton()
button.setIcon(fxicons.get_icon("crowd", library="houdini"))
The defaults you pass are that library's size, colour, style and
extension: a get_icon call that leaves one out takes it from there.
Name the library, the size and the colour per call¶
Without library, get_icon looks in "material". Every other default can
be overridden on the call itself:
from fxgui import fxicons
icon = fxicons.get_icon("houdini", library="brands")
small_red = fxicons.get_icon("home", width=32, height=32, color="red")
A Name the Library Does Not Carry¶
get_icon raises FileNotFoundError for a name no library has. When the
name comes from your own data rather than from your own code, that is an
ordinary answer rather than an exceptional one, so name a fallback
instead of wrapping the call:
from fxgui import fxicons
tool = "my_inhouse_tool" # a name read from your tracker
# A tool the "brands" library carries a logo for gets it; anything
# else gets the general-purpose icon rather than no icon at all.
icon = fxicons.get_icon(tool, library="brands", fallback="apps")
A fallback name is looked up in the default library, not in the one you asked for. That is deliberate: the library that just failed to carry the name is the least likely place for the stand-in, and the general-purpose set is where it lives. Size and colour carry over, so a row that falls back does not change shape.
Pass a QIcon instead of a name to be answered with it as it is, and
QIcon() to ask for a blank rather than a picture of something else:
from qtpy.QtGui import QIcon
from fxgui import fxicons
icon = fxicons.get_icon("my_inhouse_tool", library="brands", fallback=QIcon())
A fallback that is not in the default library either still raises, since a second silent stand-in would hide a mistake in your code rather than in your data.
Badge an icon¶
badged returns a copy of an icon with a filled dot at its lower right,
for work in flight, such as a tray icon while a job runs. The dot is a
theme token or a colour:
Icons Follow the Theme When Drawn¶
An fxgui icon is not a picture baked once. It names its colours, and it looks them up each time Qt draws it, so a theme switch reaches every icon with no code of yours.
from qtpy.QtWidgets import QPushButton
from fxgui import fxicons
button = QPushButton("Save")
fxicons.set_icon(button, "save")
set_icon(widget, name) works on anything with setIcon(): buttons,
actions, FXIconLabel. It is widget.setIcon(get_icon(name)).
Name the colour by token¶
color is the icon's colour in its resting state. Give it a theme token
name (any key of fxstyle.colors(), such as "text_muted" or
"feedback_error_foreground") and it follows the theme. Give it a colour
("#ff0000", "red") and it keeps that colour in every theme.
from fxgui import fxicons, fxwidgets
indicator = fxwidgets.FXIconLabel()
# Follows the theme: the error colour of whichever theme is on.
fxicons.set_icon(indicator, "error", color="feedback_error_foreground")
# Stays red in every theme.
fxicons.set_icon(indicator, "error", color="#ff0000")
The other states¶
Qt draws an icon in one of four modes. inks names the colour of the
three that are not the resting one, each a token or a colour:
| Mode | When Qt uses it | Default ink |
|---|---|---|
color (Normal) |
At rest | The library's default, "icon" for material, fontawesome and simple |
"active" |
A hovered tool button or toolbar button, a focused push button, a menu's highlighted row | The resting ink; "icon_on_accent_primary" on a menu's highlighted row, which is the accent |
"selected" |
A selected item-view row | "icon_on_accent_primary" |
"disabled" |
A disabled widget | "text_disabled" |
from fxgui import fxicons
icon = fxicons.get_icon(
"send",
color="icon_on_accent_primary",
inks={"active": "icon_on_accent_secondary"},
)
Any other key in inks raises ValueError. Name an "active" ink only
for a button that hovers on a coloured fill, as the send button above
does: a hovered button sits on the grey hover fill, so by default its
icon keeps the resting ink.
A full-colour library (brands, or one added with recolor=False) keeps its
own pixels in every mode, whatever colour you ask for.
Where icons share one ink, as the rows of a command palette do, ask for a
DCC's one-colour mark: its name plus _mark, such as houdini_mark. It is
drawn in the theme's icon ink, like a material icon. Marks exist for
Houdini, Maya, Nuke, Blender, Cinema 4D, DaVinci Resolve, Unreal Engine,
After Effects, Photoshop and Substance Painter.
An FXCommand names one as brands:houdini_mark.
An icon in a label¶
A QLabel pixmap is baked once. FXIconLabel holds a QIcon instead
and draws it when painted, so it follows the theme too. A disabled label
draws the icon's Disabled mode.
from fxgui import fxicons, fxwidgets
label = fxwidgets.FXIconLabel(size=18)
fxicons.set_icon(label, "info", color="feedback_info_foreground")
get_pixmap is a snapshot¶
fxicons.get_pixmap() returns a pixmap drawn now. A token colour is read
once, at the call. Use it for something you redraw yourself; use
get_icon or set_icon for anything that should follow the theme.
Using set_icon with Actions¶
For menu and toolbar actions, use the icon_name parameter in fxutils.create_action():
from fxgui import fxutils, fxwidgets
window = fxwidgets.FXMainWindow(title="Editor")
save_action = fxutils.create_action(
window,
"Save",
trigger=lambda: print("saved"),
icon_name="save",
)
QtAwesome (Optional)¶
QtAwesome is not bundled with fxgui; install it separately for features such as animated icons. First, install it:
Then you can use it like this:
import qtawesome as qta
from qtpy.QtWidgets import QPushButton
from fxgui import fxwidgets
application = fxwidgets.FXApplication()
window = fxwidgets.FXMainWindow(title="QtAwesome Example")
button = QPushButton("Network")
button.setIcon(qta.icon("mdi.access-point-network"))
window.setCentralWidget(button)
window.show()
application.exec()
And the very cool features from this package, such as animated icons:
import qtawesome as qta
from qtpy.QtWidgets import QPushButton
from fxgui import fxwidgets
application = fxwidgets.FXApplication()
window = fxwidgets.FXMainWindow(title="Animated Icon")
button = QPushButton("Loading...")
animation = qta.Spin(button)
spin_icon = qta.icon("fa5s.spinner", color="red", animation=animation)
button.setIcon(spin_icon)
window.setCentralWidget(button)
window.show()
application.exec()
Warning
The QtAwesome package doesn't work properly within Houdini, so you should use the fxicons module instead.