Files
att_menu/components/AppIcon.qml
T
2026-07-26 21:16:55 +02:00

75 lines
2.3 KiB
QML

import Quickshell
import Quickshell.Widgets
import QtQuick
import qs.config
// Renders a desktop-entry icon, which may be either an icon-theme name or an
// absolute path. Falls back to a lettered tile so an entry with a broken or
// missing icon still gets something clickable.
Item {
id: root
property string icon: ""
property string fallbackLabel: ""
// When set, shown instead of the lettered tile if the icon cannot resolve.
property string fallbackGlyph: ""
property color glyphColor: Theme.text
property int size: Theme.iconSize
implicitWidth: size
implicitHeight: size
readonly property string resolved: root.resolveIcon(root.icon)
function resolveIcon(name: string): string {
if (!name)
return "";
if (name.startsWith("file://") || name.startsWith("image://"))
return name;
if (name.startsWith("/"))
return "file://" + name;
// iconPath with checkExists returns "" when the theme has no such icon,
// so these can be chained as fallbacks. The last segment of a
// reverse-DNS app id ("org.qutebrowser.qutebrowser") is very often the
// real icon name, so try that before giving up.
const lower = name.toLowerCase();
const tail = lower.split(".").pop();
return Quickshell.iconPath(name, true) || Quickshell.iconPath(lower, true) || (tail !== lower ? Quickshell.iconPath(tail, true) : "");
}
IconImage {
id: image
anchors.fill: parent
source: root.resolved
visible: root.resolved !== "" && image.status !== Image.Error
}
Text {
anchors.centerIn: parent
visible: !image.visible && root.fallbackGlyph !== ""
text: root.fallbackGlyph
color: root.glyphColor
font.family: Theme.fontFamily
font.pixelSize: Math.max(10, root.size * 0.8)
}
Rectangle {
anchors.fill: parent
visible: !image.visible && root.fallbackGlyph === ""
radius: Math.max(2, root.size / 5)
color: Theme.surfaceActive
Text {
anchors.centerIn: parent
text: (root.fallbackLabel || "?").charAt(0).toUpperCase()
color: Theme.textDim
font.family: Theme.fontFamily
font.pixelSize: Math.max(8, root.size * 0.55)
font.bold: true
}
}
}