75 lines
2.3 KiB
QML
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
|
|
}
|
|
}
|
|
}
|