Normalize bar icon size and alignment
This commit is contained in:
17 files changed
+540
-116
No files matched your search
@@ -353,6 +353,7 @@ QtObject {
|
||||
readonly property int iconSlot: root.barToken("icon-slot", 27)
|
||||
readonly property int iconCanvas: root.barToken("icon-canvas", 16)
|
||||
readonly property int iconFont: root.barToken("icon-font", 13)
|
||||
readonly property int iconSize: Math.min(iconCanvas, root.barToken("icon-size", 12))
|
||||
readonly property int statusSlot: root.barToken("status-slot", 21)
|
||||
}
|
||||
|
||||
@@ -424,7 +425,9 @@ QtObject {
|
||||
} else if (section === "bar") {
|
||||
if (key === "scale-with-font") {
|
||||
nextBarScaleWithFont = boolToken(raw, nextBarScaleWithFont)
|
||||
} else if (key === "size-horizontal" || key === "size-vertical" || key === "notch-height") {
|
||||
} else if (key === "size-horizontal" || key === "size-vertical" || key === "notch-height"
|
||||
|| key === "icon-slot" || key === "icon-canvas" || key === "icon-font"
|
||||
|| key === "icon-size" || key === "status-slot") {
|
||||
var b = parseInt(raw, 10)
|
||||
if (isFinite(b)) barOut[key] = b
|
||||
}
|
||||
|
||||
+66
-28
@@ -8,52 +8,90 @@ WidgetButton {
|
||||
property Component iconComponent: null
|
||||
property real slotSize: Style.bar.iconSlot
|
||||
property real opticalSize: Style.bar.iconCanvas
|
||||
property real iconSize: Math.min(Style.bar.iconSize, opticalSize)
|
||||
readonly property real visualIconSize: Style.bar.iconSize
|
||||
readonly property real canvasSize: Math.max(visualIconSize, opticalSize)
|
||||
property string labelText: ""
|
||||
property bool debugOpticalBounds: Quickshell.env("OMARCHY_DEBUG_BAR_ICONS") === "1"
|
||||
// Measured against the slot, which the open-panel underline centers on.
|
||||
readonly property real opticalCenterErrorX: glyph.visible ? opticalCanvas.x + glyph.paintedCenterX - root.width / 2 : 0
|
||||
readonly property real glyphPaintedWidth: glyph.visible ? glyph.tightWidth : 0
|
||||
// A label shifts the icon within the centered group.
|
||||
readonly property real opticalCenterErrorX:
|
||||
content.x + opticalCanvas.x + (glyph.visible ? glyph.paintedCenterX : customIcon.width / 2 + customIcon.centerErrorX) - root.width / 2
|
||||
- (label.visible ? (label.implicitWidth + Style.space(4)) / 2 : 0)
|
||||
readonly property real opticalCenterErrorY:
|
||||
content.y + (glyph.visible ? glyph.paintedCenterY : customIcon.height / 2 + customIcon.centerErrorY) - root.height / 2
|
||||
readonly property real glyphPaintedWidth: glyph.visible ? glyph.paintedWidth : 0
|
||||
readonly property real glyphPaintedHeight: glyph.visible ? glyph.paintedHeight : 0
|
||||
readonly property real glyphBaselineY: glyph.visible ? glyph.baselineY : 0
|
||||
readonly property int glyphFontSize: glyph.visible ? glyph.renderedFontSize : 0
|
||||
readonly property real componentPaintedWidth: customIcon.visible ? customIcon.paintedWidth : 0
|
||||
readonly property real componentPaintedHeight: customIcon.visible ? customIcon.paintedHeight : 0
|
||||
|
||||
labelVisible: false
|
||||
hasVisualContent: text !== "" || iconComponent !== null
|
||||
hasVisualContent: text !== "" || iconComponent !== null || labelText !== ""
|
||||
fontSize: Style.bar.iconFont
|
||||
fixedWidth: vertical ? -1 : slotSize
|
||||
fixedHeight: vertical ? slotSize : -1
|
||||
|
||||
Item {
|
||||
id: opticalCanvas
|
||||
// Placed exactly, not anchored: centerIn snaps an even canvas in an odd slot
|
||||
// to a whole pixel, pulling every glyph off the open-panel underline.
|
||||
id: content
|
||||
// Exact coordinates preserve the center of odd-width slots.
|
||||
x: (root.width - width) / 2
|
||||
y: (root.height - height) / 2
|
||||
width: root.opticalSize
|
||||
height: root.opticalSize
|
||||
width: root.canvasSize + (label.visible ? label.implicitWidth + Style.space(4) : 0)
|
||||
height: root.canvasSize
|
||||
|
||||
OpticalGlyph {
|
||||
id: glyph
|
||||
anchors.fill: parent
|
||||
visible: root.iconComponent === null
|
||||
text: root.text
|
||||
fontFamily: root.fontFamily
|
||||
fontSize: root.fontSize
|
||||
Text {
|
||||
id: label
|
||||
visible: root.labelText !== ""
|
||||
textFormat: Text.PlainText
|
||||
text: root.labelText
|
||||
font.family: root.fontFamily
|
||||
font.pixelSize: root.fontSize
|
||||
color: root.active && root.useActiveColor ? root.activeColor : root.foreground
|
||||
rotation: root.textRotation
|
||||
debugBounds: root.debugOpticalBounds
|
||||
y: (parent.height - height) / 2
|
||||
+ (labelMetrics.descent - labelMetrics.ascent + labelMetrics.tightBoundingRect("0").height) / 2
|
||||
renderType: Text.NativeRendering
|
||||
}
|
||||
|
||||
Loader {
|
||||
anchors.fill: parent
|
||||
visible: root.iconComponent !== null
|
||||
sourceComponent: root.iconComponent
|
||||
FontMetrics {
|
||||
id: labelMetrics
|
||||
font: label.font
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
visible: root.debugOpticalBounds && root.iconComponent !== null
|
||||
anchors.fill: parent
|
||||
color: "transparent"
|
||||
border.width: 1
|
||||
border.color: "#4488ff"
|
||||
Item {
|
||||
id: opticalCanvas
|
||||
x: label.visible ? label.implicitWidth + Style.space(4) : 0
|
||||
width: root.canvasSize
|
||||
height: root.canvasSize
|
||||
|
||||
OpticalGlyph {
|
||||
id: glyph
|
||||
anchors.fill: parent
|
||||
visible: root.iconComponent === null
|
||||
text: root.text
|
||||
fontFamily: root.fontFamily
|
||||
fontSize: root.fontSize
|
||||
paintedSize: root.visualIconSize
|
||||
color: root.active && root.useActiveColor ? root.activeColor : root.foreground
|
||||
rotation: root.textRotation
|
||||
debugBounds: root.debugOpticalBounds
|
||||
}
|
||||
|
||||
BarIconContent {
|
||||
id: customIcon
|
||||
anchors.fill: parent
|
||||
visible: root.iconComponent !== null
|
||||
sourceComponent: root.iconComponent
|
||||
sourceSize: root.opticalSize
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
visible: root.debugOpticalBounds && root.iconComponent !== null
|
||||
anchors.fill: parent
|
||||
color: "transparent"
|
||||
border.width: 1
|
||||
border.color: "#4488ff"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
import QtQuick
|
||||
import qs.Commons
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
property Component sourceComponent: null
|
||||
property real sourceSize: Style.bar.iconCanvas
|
||||
readonly property rect sourceBounds: bounds.mappedBounds
|
||||
readonly property real contentScale: sourceBounds.width > 0 && sourceBounds.height > 0
|
||||
? Style.bar.iconSize / Math.max(sourceBounds.width, sourceBounds.height) : 1
|
||||
readonly property real paintedWidth: sourceBounds.width * contentScale
|
||||
readonly property real paintedHeight: sourceBounds.height * contentScale
|
||||
readonly property real centerErrorX: content.x + (sourceBounds.x + sourceBounds.width / 2) * contentScale - width / 2
|
||||
readonly property real centerErrorY: content.y + (sourceBounds.y + sourceBounds.height / 2) * contentScale - height / 2
|
||||
|
||||
Loader {
|
||||
id: content
|
||||
sourceComponent: root.sourceComponent
|
||||
onLoaded: {
|
||||
// Keep declared dimensions. Empty wrapper items receive a source canvas.
|
||||
if (!(item instanceof Image)) {
|
||||
if (item.width <= 0) item.width = Qt.binding(function() { return root.sourceSize })
|
||||
if (item.height <= 0) item.height = Qt.binding(function() { return root.sourceSize })
|
||||
}
|
||||
}
|
||||
transformOrigin: Item.TopLeft
|
||||
scale: root.contentScale
|
||||
x: root.width / 2 - (root.sourceBounds.x + root.sourceBounds.width / 2) * scale
|
||||
y: root.height / 2 - (root.sourceBounds.y + root.sourceBounds.height / 2) * scale
|
||||
}
|
||||
|
||||
IconContentBounds {
|
||||
id: bounds
|
||||
sourceItem: content.item
|
||||
boundsParent: content
|
||||
}
|
||||
}
|
||||
@@ -46,7 +46,6 @@ BarIconButton {
|
||||
useActiveColor: false
|
||||
maintainIndicatorReveal: indicatorBlock === "inactive"
|
||||
revealHost: indicatorHost
|
||||
fontSize: Style.font.caption
|
||||
horizontalMargin: 5
|
||||
verticalPadding: 5
|
||||
fixedWidth: vertical ? -1 : Style.bar.statusSlot
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
import QtQuick
|
||||
import QtQuick.Shapes
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
property Item sourceItem: null
|
||||
property Item boundsParent: null
|
||||
property rect mappedBounds: Qt.rect(0, 0, 0, 0)
|
||||
visible: false
|
||||
|
||||
readonly property bool textItem: sourceItem instanceof Text
|
||||
readonly property bool imageItem: sourceItem instanceof Image
|
||||
readonly property bool boxItem: sourceItem instanceof Rectangle
|
||||
|| sourceItem instanceof Shape || sourceItem instanceof Canvas || sourceItem instanceof ShaderEffect
|
||||
|
||||
function unionBounds(a, b) {
|
||||
if (b.width <= 0 || b.height <= 0) return a
|
||||
if (a.width <= 0 || a.height <= 0) return b
|
||||
var x = Math.min(a.x, b.x)
|
||||
var y = Math.min(a.y, b.y)
|
||||
return Qt.rect(x, y, Math.max(a.x + a.width, b.x + b.width) - x,
|
||||
Math.max(a.y + a.height, b.y + b.height) - y)
|
||||
}
|
||||
|
||||
readonly property rect paintedBounds: {
|
||||
var item = sourceItem
|
||||
var bounds = Qt.rect(0, 0, 0, 0)
|
||||
if (!item || !item.visible || item.opacity <= 0) return bounds
|
||||
if (textItem) {
|
||||
var ink = textMetrics.tightBoundingRect
|
||||
bounds = Qt.rect(ink.x, item.baselineOffset + ink.y, ink.width, ink.height)
|
||||
} else if (imageItem) {
|
||||
var w = item.paintedWidth
|
||||
var h = item.paintedHeight
|
||||
var x = item.horizontalAlignment === Image.AlignLeft ? 0
|
||||
: (item.horizontalAlignment === Image.AlignRight ? item.width - w : (item.width - w) / 2)
|
||||
var y = item.verticalAlignment === Image.AlignTop ? 0
|
||||
: (item.verticalAlignment === Image.AlignBottom ? item.height - h : (item.height - h) / 2)
|
||||
if (item.fillMode === Image.PreserveAspectFit) {
|
||||
bounds = Qt.rect(x, y, w, h)
|
||||
} else if (item.fillMode === Image.Pad) {
|
||||
var left = Math.max(0, x)
|
||||
var top = Math.max(0, y)
|
||||
bounds = Qt.rect(left, top, Math.max(0, Math.min(item.width, x + w) - left),
|
||||
Math.max(0, Math.min(item.height, y + h) - top))
|
||||
} else {
|
||||
bounds = Qt.rect(0, 0, item.width, item.height)
|
||||
}
|
||||
} else if (boxItem) {
|
||||
bounds = Qt.rect(0, 0, item.width, item.height)
|
||||
}
|
||||
for (var i = 0; i < childrenBounds.count; i++) {
|
||||
var child = childrenBounds.itemAt(i)
|
||||
if (child) bounds = unionBounds(bounds, child.mappedBounds)
|
||||
}
|
||||
if (item.clip && bounds.width > 0 && bounds.height > 0) {
|
||||
var left = Math.max(0, bounds.x)
|
||||
var top = Math.max(0, bounds.y)
|
||||
bounds = Qt.rect(left, top,
|
||||
Math.max(0, Math.min(item.width, bounds.x + bounds.width) - left),
|
||||
Math.max(0, Math.min(item.height, bounds.y + bounds.height) - top))
|
||||
}
|
||||
return bounds
|
||||
}
|
||||
|
||||
function updateMappedBounds() {
|
||||
var b = paintedBounds
|
||||
mappedBounds = sourceItem && boundsParent && b.width > 0 && b.height > 0
|
||||
? sourceItem.mapToItem(boundsParent, b.x, b.y, b.width, b.height)
|
||||
: b
|
||||
}
|
||||
|
||||
function configureSource() {
|
||||
if (sourceItem instanceof Text) sourceItem.renderType = Text.CurveRendering
|
||||
updateMappedBounds()
|
||||
}
|
||||
|
||||
onPaintedBoundsChanged: updateMappedBounds()
|
||||
onSourceItemChanged: configureSource()
|
||||
onBoundsParentChanged: updateMappedBounds()
|
||||
Component.onCompleted: updateMappedBounds()
|
||||
|
||||
TextMetrics {
|
||||
id: textMetrics
|
||||
font: root.textItem ? root.sourceItem.font : Qt.font({ pixelSize: 12 })
|
||||
text: root.textItem ? root.sourceItem.text : ""
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: root.sourceItem
|
||||
function onXChanged() { root.updateMappedBounds() }
|
||||
function onYChanged() { root.updateMappedBounds() }
|
||||
function onWidthChanged() { root.updateMappedBounds() }
|
||||
function onHeightChanged() { root.updateMappedBounds() }
|
||||
function onScaleChanged() { root.updateMappedBounds() }
|
||||
function onRotationChanged() { root.updateMappedBounds() }
|
||||
function onTransformOriginChanged() { root.updateMappedBounds() }
|
||||
}
|
||||
|
||||
Repeater {
|
||||
id: childrenBounds
|
||||
model: root.sourceItem ? root.sourceItem.children : []
|
||||
delegate: Loader {
|
||||
id: childLoader
|
||||
required property var modelData
|
||||
readonly property rect mappedBounds: item ? item.mappedBounds : Qt.rect(0, 0, 0, 0)
|
||||
source: Qt.resolvedUrl("IconContentBounds.qml")
|
||||
onLoaded: {
|
||||
item.sourceItem = Qt.binding(function() { return childLoader.modelData })
|
||||
item.boundsParent = Qt.binding(function() { return root.sourceItem })
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,14 +8,22 @@ Item {
|
||||
property string text: ""
|
||||
property string fontFamily: Style.font.family
|
||||
property real fontSize: Style.font.body
|
||||
property real paintedSize: 0
|
||||
property color color: Commons.Color.foreground
|
||||
property bool debugBounds: false
|
||||
|
||||
readonly property int renderedFontSize: Math.max(1, Math.round(fontSize))
|
||||
readonly property real tightWidth: Math.max(1, glyphMetrics.tightBoundingRect.width)
|
||||
readonly property real tightHeight: Math.max(1, glyphMetrics.tightBoundingRect.height)
|
||||
readonly property real paintedScale: paintedSize > 0
|
||||
? Math.min(paintedSize, width, height) / Math.max(tightWidth, tightHeight)
|
||||
: 1
|
||||
readonly property real paintedWidth: tightWidth * paintedScale
|
||||
readonly property real paintedHeight: tightHeight * paintedScale
|
||||
readonly property real horizontalCorrection: glyph.implicitWidth / 2 - (glyphMetrics.tightBoundingRect.x + tightWidth / 2)
|
||||
readonly property real paintedCenterX: glyph.x + glyphMetrics.tightBoundingRect.x + tightWidth / 2
|
||||
readonly property real baselineY: glyph.y + glyph.baselineOffset
|
||||
readonly property real paintedCenterX: glyph.x + (glyphMetrics.tightBoundingRect.x + tightWidth / 2) * paintedScale
|
||||
readonly property real paintedCenterY: glyph.y + (glyph.baselineOffset + glyphMetrics.tightBoundingRect.y + tightHeight / 2) * paintedScale
|
||||
readonly property real baselineY: glyph.y + glyph.baselineOffset * paintedScale
|
||||
|
||||
TextMetrics {
|
||||
id: glyphMetrics
|
||||
@@ -27,17 +35,18 @@ Item {
|
||||
Text {
|
||||
id: glyph
|
||||
textFormat: Text.PlainText
|
||||
// Keep the shared line box and baseline intact. Correcting only the
|
||||
// horizontal painted bounds avoids per-glyph vertical drift.
|
||||
// The correction is fractional, so x is set exactly: centerIn would snap it
|
||||
// to a whole pixel and undo it. y still snaps, keeping the baseline crisp.
|
||||
x: (root.width - width) / 2 + root.horizontalCorrection
|
||||
y: Math.round((root.height - height) / 2)
|
||||
// Bar icons fit their painted bounds. Text labels retain their line box.
|
||||
x: root.width / 2 - (glyphMetrics.tightBoundingRect.x + root.tightWidth / 2) * root.paintedScale
|
||||
y: root.paintedSize > 0
|
||||
? root.height / 2 - (baselineOffset + glyphMetrics.tightBoundingRect.y + root.tightHeight / 2) * root.paintedScale
|
||||
: Math.round((root.height - height) / 2)
|
||||
text: root.text
|
||||
color: root.color
|
||||
font.family: root.fontFamily
|
||||
font.pixelSize: root.renderedFontSize
|
||||
renderType: Text.NativeRendering
|
||||
transformOrigin: Item.TopLeft
|
||||
scale: root.paintedScale
|
||||
renderType: root.paintedSize > 0 ? Text.CurveRendering : Text.NativeRendering
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
|
||||
@@ -65,11 +65,31 @@ Item {
|
||||
// Width of the painted label, for bar chrome that wants to line up with the
|
||||
// text rather than with the slot it sits in. Zero on icon-only buttons.
|
||||
readonly property real labelWidth: label.visible ? label.implicitWidth : 0
|
||||
readonly property bool iconLabel: labelVisible && isIconGlyph(text)
|
||||
readonly property real iconPaintedWidth: iconLabel && iconLoader.item ? iconLoader.item.paintedWidth : 0
|
||||
readonly property real iconPaintedHeight: iconLabel && iconLoader.item ? iconLoader.item.paintedHeight : 0
|
||||
readonly property real iconCenterErrorX: iconLabel && iconLoader.item
|
||||
? iconLoader.x + iconLoader.item.paintedCenterX - width / 2 : 0
|
||||
readonly property real iconCenterErrorY: iconLabel && iconLoader.item
|
||||
? iconLoader.y + iconLoader.item.paintedCenterY - height / 2 : 0
|
||||
|
||||
function isIconGlyph(value) {
|
||||
var text = String(value || "")
|
||||
if (!text) return false
|
||||
var code = text.codePointAt(0)
|
||||
if (text.length !== (code > 0xffff ? 2 : 1)) return false
|
||||
return (code >= 0xe000 && code <= 0xf8ff)
|
||||
|| (code >= 0xf0000 && code <= 0xffffd)
|
||||
|| (code >= 0x100000 && code <= 0x10fffd)
|
||||
|| (code >= 0x2190 && code <= 0x2bff)
|
||||
}
|
||||
|
||||
visible: hasVisualContent || keepSpace
|
||||
opacity: !hasVisualContent || concealed ? 0 : (dimmed ? 0.45 : 1)
|
||||
implicitWidth: fixedWidth > 0 ? fixedWidth : (vertical ? barSize : Math.max(12, label.implicitWidth + scaledHorizontalMargin * 2))
|
||||
implicitHeight: fixedHeight > 0 ? fixedHeight : (vertical ? Math.max(12, label.implicitHeight + scaledVerticalPadding * 2) : barSize)
|
||||
implicitWidth: fixedWidth > 0 ? fixedWidth
|
||||
: (vertical ? barSize : (iconLabel ? Style.bar.iconSlot : Math.max(12, label.implicitWidth + scaledHorizontalMargin * 2)))
|
||||
implicitHeight: fixedHeight > 0 ? fixedHeight
|
||||
: (vertical ? (iconLabel ? Style.bar.iconSlot : Math.max(12, label.implicitHeight + scaledVerticalPadding * 2)) : barSize)
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation { duration: Style.duration(140); easing.type: Easing.OutCubic }
|
||||
@@ -78,7 +98,7 @@ Item {
|
||||
Text {
|
||||
id: label
|
||||
textFormat: Text.PlainText
|
||||
visible: root.labelVisible
|
||||
visible: root.labelVisible && !root.iconLabel
|
||||
anchors.centerIn: parent
|
||||
// Centering the line box puts the figures above the bar's middle, since
|
||||
// the box keeps room for descenders. Center the figure height instead, so
|
||||
@@ -106,6 +126,25 @@ Item {
|
||||
font: label.font
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: iconLoader
|
||||
active: root.iconLabel
|
||||
width: Style.bar.iconCanvas
|
||||
height: Style.bar.iconCanvas
|
||||
x: (root.width - width) / 2
|
||||
y: (root.height - height) / 2
|
||||
sourceComponent: Component {
|
||||
OpticalGlyph {
|
||||
text: root.text
|
||||
fontFamily: root.fontFamily
|
||||
fontSize: root.fontSize
|
||||
paintedSize: Style.bar.iconSize
|
||||
color: root.active && root.useActiveColor ? root.activeColor : root.foreground
|
||||
rotation: root.textRotation
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: mouseArea
|
||||
anchors.fill: parent
|
||||
|
||||
@@ -2,6 +2,7 @@ module qs.Ui
|
||||
|
||||
BarIndicator 1.0 BarIndicator.qml
|
||||
BarIconButton 1.0 BarIconButton.qml
|
||||
BarIconContent 1.0 BarIconContent.qml
|
||||
BarWidget 1.0 BarWidget.qml
|
||||
BackgroundMedia 1.0 BackgroundMedia.qml
|
||||
BorderOverlay 1.0 BorderOverlay.qml
|
||||
@@ -11,6 +12,7 @@ ButtonGroup 1.0 ButtonGroup.qml
|
||||
ConfirmDialog 1.0 ConfirmDialog.qml
|
||||
CursorSurface 1.0 CursorSurface.qml
|
||||
Dropdown 1.0 Dropdown.qml
|
||||
IconContentBounds 1.0 IconContentBounds.qml
|
||||
KeyboardPanel 1.0 KeyboardPanel.qml
|
||||
MultiSelect 1.0 MultiSelect.qml
|
||||
NumberField 1.0 NumberField.qml
|
||||
|
||||
@@ -78,6 +78,16 @@ The `omarchy.indicators` widget loads individual bar indicators from `indicators
|
||||
|
||||
All widgets work in `top`, `bottom`, `left`, and `right` positions. Popups anchor on the side opposite the bar edge, sliding into the workspace. Vertical bars use 28px width; widgets that show text fall back to compact icon-only forms (e.g. `media` hides its scrolling label).
|
||||
|
||||
## Icon geometry
|
||||
|
||||
Use `BarIconButton` from `qs.Ui` for bar icons. It fits the visible glyph bounds to `Style.bar.iconSize` and centers them on both axes. It preserves each glyph's aspect ratio. Set `labelText` for an adjacent text label, such as the battery percentage.
|
||||
|
||||
The `[bar]` section of a theme's `shell.toml` supplies the shared dimensions. `icon-size` sets the visual target, with a default of 12 logical pixels. `icon-canvas` sets the canvas, with a default of 16 logical pixels. `icon-slot` and `status-slot` set the button extent. These dimensions follow the font scale unless `scale-with-font` is false.
|
||||
|
||||
Custom `iconComponent` content also fits the shared target. Its source dimensions can be 15px or another size. The bar measures its glyph, image, or vector bounds and applies one scale without changing its aspect ratio. A source `iconSize` override does not change the rendered target. Image padding remains part of an application's tray asset.
|
||||
|
||||
`WidgetButton` also uses the shared renderer for a single icon glyph. This covers custom command widgets and existing plugins that use `WidgetButton` with a different `fontSize`. Text labels retain their text size. Custom widgets must use `WidgetButton` or `BarIconButton` for this icon contract.
|
||||
|
||||
## Custom user modules
|
||||
|
||||
The schema accepts arbitrary module ids that you provide. Set `type` to `command` for shell-driven output or `qml` for a custom QML widget. Both still go under `bar.layout.<section>` in `shell.json`.
|
||||
|
||||
@@ -58,7 +58,6 @@ BarWidget {
|
||||
bar: root.bar
|
||||
text: "\uf021"
|
||||
slotSize: Style.bar.statusSlot
|
||||
fontSize: Style.font.caption
|
||||
tooltipText: "Pending Omarchy Updates"
|
||||
onPressed: root.runUpdate()
|
||||
}
|
||||
|
||||
@@ -810,9 +810,10 @@ BarWidget {
|
||||
}
|
||||
|
||||
TrayIcon {
|
||||
anchors.centerIn: parent
|
||||
width: Style.space(12)
|
||||
height: Style.space(12)
|
||||
x: (parent.width - width) / 2
|
||||
y: (parent.height - height) / 2
|
||||
width: Style.bar.iconSize
|
||||
height: Style.bar.iconSize
|
||||
icon: trayItemRoot.modelData.icon
|
||||
}
|
||||
|
||||
|
||||
@@ -8,14 +8,12 @@ BarWidget {
|
||||
implicitWidth: button.implicitWidth
|
||||
implicitHeight: button.implicitHeight
|
||||
|
||||
WidgetButton {
|
||||
BarIconButton {
|
||||
id: button
|
||||
anchors.fill: parent
|
||||
bar: root.bar
|
||||
text: "\ue900"
|
||||
fontFamily: "omarchy"
|
||||
centerFigures: false
|
||||
horizontalMargin: 7.5
|
||||
onPressed: function(button) {
|
||||
if (!root.bar) return
|
||||
if (button === Qt.RightButton) root.bar.run("xdg-terminal-exec")
|
||||
|
||||
@@ -7,11 +7,13 @@ Item {
|
||||
id: root
|
||||
|
||||
property real iconSize: Style.font.icon
|
||||
readonly property real aspectRatio: 1.18
|
||||
property real artworkScale: 0.95
|
||||
property color color: Commons.Color.foreground
|
||||
|
||||
width: iconSize * 1.18
|
||||
width: iconSize * aspectRatio
|
||||
height: iconSize
|
||||
implicitWidth: iconSize * 1.18
|
||||
implicitWidth: iconSize * aspectRatio
|
||||
implicitHeight: iconSize
|
||||
|
||||
Shape {
|
||||
@@ -19,7 +21,7 @@ Item {
|
||||
antialiasing: true
|
||||
layer.enabled: true
|
||||
layer.samples: 4
|
||||
scale: 0.95
|
||||
scale: root.artworkScale
|
||||
|
||||
Tile { cx: root.width * 0.25; cy: root.height * 0.188 }
|
||||
Tile { cx: root.width * 0.75; cy: root.height * 0.188 }
|
||||
|
||||
@@ -175,8 +175,10 @@ Panel {
|
||||
iconComponent: Component {
|
||||
Item {
|
||||
DropboxIcon {
|
||||
anchors.centerIn: parent
|
||||
iconSize: Style.space(12)
|
||||
x: (parent.width - width) / 2
|
||||
y: (parent.height - height) / 2
|
||||
iconSize: button.iconSize / aspectRatio
|
||||
artworkScale: 1
|
||||
color: root.barIconColor
|
||||
opacity: dropbox.active ? 1.0 : 0.6
|
||||
}
|
||||
|
||||
@@ -278,9 +278,8 @@ Panel {
|
||||
id: button
|
||||
anchors.fill: parent
|
||||
bar: root.bar
|
||||
text: root.showPercentage && !vertical
|
||||
? Math.round(root.batteryFraction * 100) + "% " + root.batteryIcon()
|
||||
: root.batteryIcon()
|
||||
text: root.batteryIcon()
|
||||
labelText: root.showPercentage && !vertical ? Math.round(root.batteryFraction * 100) + "%" : ""
|
||||
slotSize: Style.bar.iconSlot * (root.showPercentage && !vertical ? 2 : 1)
|
||||
tooltipText: ""
|
||||
onPressed: function(b) {
|
||||
|
||||
@@ -385,8 +385,9 @@ Panel {
|
||||
iconComponent: Component {
|
||||
Item {
|
||||
TailscaleIcon {
|
||||
anchors.centerIn: parent
|
||||
iconSize: Style.space(11)
|
||||
x: (parent.width - width) / 2
|
||||
y: (parent.height - height) / 2
|
||||
iconSize: button.iconSize
|
||||
color: root.barIconColor
|
||||
badgeColor: root.urgent
|
||||
crossed: !tailscale.active && !tailscale.needsLogin
|
||||
|
||||
Reference in new issue
Block a user