Tint the bar icon SVG directly instead of masking it
This commit is contained in:
+8
-5
@@ -87,11 +87,14 @@ and the root menu (Super + Alt + Space) are both wider. The two oversized menus
|
|||||||
`clonedFrom`, and the shell routes those calls here.
|
`clonedFrom`, and the shell routes those calls here.
|
||||||
|
|
||||||
`BarWidget.qml` swaps the stock `\ue900` glyph from the `omarchy` icon font for
|
`BarWidget.qml` swaps the stock `\ue900` glyph from the `omarchy` icon font for
|
||||||
`branding/blob_icon.svg`. Qt renders SVG through `qt6-svg`, but an `Image`
|
`branding/blob_icon.svg`. An SVG is text, so the fill is rewritten to the bar
|
||||||
cannot be recolored, so the icon is used as an alpha mask over a rectangle
|
foreground in QML and the result handed to `Image` as a base64 `data:` URL -
|
||||||
filled with the bar foreground. That keeps it following the theme and the bar's
|
the same trick the `theme-set` hook uses with `sed` for the fastfetch logo, so
|
||||||
own color animation the way a glyph did, and it means the black fill in the
|
both consumers of the icon work the same way. The color is read off
|
||||||
source file never matters.
|
`button.foreground` rather than the theme, which keeps the icon on the bar's own
|
||||||
|
foreground animation, and rebuilding the URL is what reloads the image, so there
|
||||||
|
is no image cache to bust. The glyph stays as the `text` fallback and is shown
|
||||||
|
whenever the SVG cannot be read or decoded, so the button is never blank.
|
||||||
|
|
||||||
`mergeMenuSources` in `MenuModel.js` reads the default menu first and the user
|
`mergeMenuSources` in `MenuModel.js` reads the default menu first and the user
|
||||||
extension second, so a row that only exists in `extensions/omarchy-menu.jsonc`
|
extension second, so a row that only exists in `extensions/omarchy-menu.jsonc`
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Effects
|
|
||||||
import Quickshell
|
import Quickshell
|
||||||
|
import Quickshell.Io
|
||||||
import qs.Commons
|
import qs.Commons
|
||||||
import qs.Ui
|
import qs.Ui
|
||||||
|
|
||||||
@@ -8,19 +8,43 @@ BarWidget {
|
|||||||
id: root
|
id: root
|
||||||
moduleName: "omarchy.menu"
|
moduleName: "omarchy.menu"
|
||||||
|
|
||||||
readonly property string iconPath: "file://" + Quickshell.env("HOME") + "/.config/omarchy/branding/blob_icon.svg"
|
readonly property string iconPath: Quickshell.env("HOME") + "/.config/omarchy/branding/blob_icon.svg"
|
||||||
readonly property int iconSize: Math.round(Style.font.body * 1.35)
|
readonly property int iconSize: Math.round(Style.font.body * 1.35)
|
||||||
|
|
||||||
|
property string iconSvg: ""
|
||||||
|
|
||||||
|
readonly property string iconColor: hexColor(button.foreground)
|
||||||
|
readonly property string tintedSvg: iconSvg.replace(/fill="#000000"/g, 'fill="' + iconColor + '"')
|
||||||
|
readonly property string iconUrl: iconSvg.length > 0 ? "data:image/svg+xml;base64," + Qt.btoa(tintedSvg) : ""
|
||||||
|
readonly property bool iconReady: icon.status === Image.Ready
|
||||||
|
|
||||||
|
function hexColor(value) {
|
||||||
|
function channel(fraction) {
|
||||||
|
return ("0" + Math.round(fraction * 255).toString(16)).slice(-2)
|
||||||
|
}
|
||||||
|
return "#" + channel(value.r) + channel(value.g) + channel(value.b)
|
||||||
|
}
|
||||||
|
|
||||||
implicitWidth: button.implicitWidth
|
implicitWidth: button.implicitWidth
|
||||||
implicitHeight: button.implicitHeight
|
implicitHeight: button.implicitHeight
|
||||||
|
|
||||||
|
FileView {
|
||||||
|
path: root.iconPath
|
||||||
|
watchChanges: true
|
||||||
|
printErrors: false
|
||||||
|
onLoaded: root.iconSvg = text()
|
||||||
|
onLoadFailed: root.iconSvg = ""
|
||||||
|
onFileChanged: reload()
|
||||||
|
}
|
||||||
|
|
||||||
WidgetButton {
|
WidgetButton {
|
||||||
id: button
|
id: button
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
bar: root.bar
|
bar: root.bar
|
||||||
labelVisible: false
|
text: "\ue900"
|
||||||
hasVisualContent: true
|
fontFamily: "omarchy"
|
||||||
fixedWidth: root.iconSize + Style.spaceReal(15)
|
labelVisible: !root.iconReady
|
||||||
|
fixedWidth: root.iconReady ? root.iconSize + Style.spaceReal(15) : -1
|
||||||
horizontalMargin: 7.5
|
horizontalMargin: 7.5
|
||||||
onPressed: function(button) {
|
onPressed: function(button) {
|
||||||
if (!root.bar) return
|
if (!root.bar) return
|
||||||
@@ -29,30 +53,15 @@ BarWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Image {
|
Image {
|
||||||
id: iconMask
|
id: icon
|
||||||
source: root.iconPath
|
|
||||||
visible: false
|
|
||||||
smooth: true
|
|
||||||
sourceSize.width: root.iconSize * 2
|
|
||||||
sourceSize.height: root.iconSize * 2
|
|
||||||
}
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
width: root.iconSize
|
width: root.iconSize
|
||||||
height: root.iconSize
|
height: root.iconSize
|
||||||
color: button.foreground
|
source: root.iconUrl
|
||||||
visible: iconMask.status === Image.Ready
|
sourceSize.width: root.iconSize * 2
|
||||||
layer.enabled: true
|
sourceSize.height: root.iconSize * 2
|
||||||
layer.effect: MultiEffect {
|
smooth: true
|
||||||
maskEnabled: true
|
visible: root.iconReady
|
||||||
maskSource: iconMask
|
|
||||||
}
|
|
||||||
|
|
||||||
Behavior on color {
|
|
||||||
enabled: !root.bar || root.bar.foregroundAnimationEnabled
|
|
||||||
ColorAnimation { duration: 160 }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user