fixed some bugs
This commit is contained in:
@@ -1 +0,0 @@
|
|||||||
monitor=eDP-1, disable
|
|
||||||
@@ -20,7 +20,12 @@ M.external = {
|
|||||||
{ output = "desc:Samsung Electric Company LC27G7xT H4ZRA00734", mode = "2560x1440@240", position = "-2560x0", scale = 1 },
|
{ output = "desc:Samsung Electric Company LC27G7xT H4ZRA00734", mode = "2560x1440@240", position = "-2560x0", scale = 1 },
|
||||||
}
|
}
|
||||||
|
|
||||||
M.builtin = { output = M.laptop, mode = "1920x1080@60", position = "0x0", scale = 1 }
|
-- `disabled = false` is load-bearing, not decoration. hl.monitor() merges into
|
||||||
|
-- whatever rule the output already has, so a spec that simply omits the flag
|
||||||
|
-- leaves an earlier `disabled = true` in place: the panel stays dark and the
|
||||||
|
-- mode/position are applied to a monitor nobody can see. Opening the lid while
|
||||||
|
-- docked hit exactly that.
|
||||||
|
M.builtin = { output = M.laptop, mode = "1920x1080@60", position = "0x0", scale = 1, disabled = false }
|
||||||
|
|
||||||
-- Anything not declared above falls back to Hyprland's auto placement, so a
|
-- Anything not declared above falls back to Hyprland's auto placement, so a
|
||||||
-- borrowed projector or a monitor at the office still lights up.
|
-- borrowed projector or a monitor at the office still lights up.
|
||||||
|
|||||||
@@ -115,10 +115,17 @@ PanelWindow {
|
|||||||
implicitWidth: Theme.padM * 2
|
implicitWidth: Theme.padM * 2
|
||||||
implicitHeight: Theme.barHeight
|
implicitHeight: Theme.barHeight
|
||||||
|
|
||||||
|
// A leaning hairline needs a box wide enough to hold the lean: at 20px
|
||||||
|
// tall the top edge sits 20 * skew ≈ 5px right of the bottom one, so a
|
||||||
|
// 1px-wide Skew folded into a bowtie instead. Width is the lean plus the
|
||||||
|
// stroke the rule should actually read as.
|
||||||
|
readonly property real ruleWeight: 1.5
|
||||||
|
readonly property real ruleHeight: 20
|
||||||
|
|
||||||
Skew {
|
Skew {
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
width: 1
|
width: parent.ruleHeight * Theme.skew + parent.ruleWeight
|
||||||
height: 20
|
height: parent.ruleHeight
|
||||||
color: Theme.alpha(Theme.outline, 0.9)
|
color: Theme.alpha(Theme.outline, 0.9)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,9 +37,15 @@ Item {
|
|||||||
// crimson line struck through its bottom edge on hover. Reserving the band
|
// crimson line struck through its bottom edge on hover. Reserving the band
|
||||||
// and centring content in what is left is what keeps the rule under the
|
// and centring content in what is left is what keeps the rule under the
|
||||||
// module instead of across it.
|
// module instead of across it.
|
||||||
|
// The band reserved the full rule plus its inset — 7px off a 40px module,
|
||||||
|
// all of it taken from the bottom — so every module's content was centred
|
||||||
|
// 3.5px above the slab's own centre and the whole bar read as top-heavy.
|
||||||
|
// The rule is pushed closer to the edge now and the band keeps only enough
|
||||||
|
// clearance to stop the tallest content (the media pill's 24px art) from
|
||||||
|
// touching it, so content sits within a pixel of the slab's centre line.
|
||||||
readonly property real ruleHeight: 2
|
readonly property real ruleHeight: 2
|
||||||
readonly property real ruleInset: 5
|
readonly property real ruleInset: 3
|
||||||
readonly property real ruleBand: root.standalone ? 0 : root.ruleHeight + root.ruleInset
|
readonly property real ruleBand: root.standalone ? 0 : 2
|
||||||
|
|
||||||
// Modules with a notion of progress (the player's track position) draw it in
|
// Modules with a notion of progress (the player's track position) draw it in
|
||||||
// the same band, so it can never be struck through the content. A module
|
// the same band, so it can never be struck through the content. A module
|
||||||
|
|||||||
@@ -50,18 +50,54 @@ BarPill {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Declared with room for its own lean, so the slash sits inside the box
|
||||||
|
// the Row gave it instead of hanging several px into the date column.
|
||||||
Skew {
|
Skew {
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
width: 2
|
width: 22 * Theme.skew + 3
|
||||||
height: 22
|
height: 22
|
||||||
color: Theme.alpha(Theme.accent, 0.6)
|
color: Theme.alpha(Theme.accent, 0.6)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Archivo Black's digits are not all the same width, so a clock sized to
|
||||||
|
// its own text changed width as the minutes rolled over — 11:11 is
|
||||||
|
// several px narrower than 08:48 — and shoved the rest of the bar
|
||||||
|
// around. Reserve the widest possible reading and centre inside it.
|
||||||
|
TextMetrics {
|
||||||
|
id: timeMetrics
|
||||||
|
text: "88:88"
|
||||||
|
font.family: Theme.fontDisplay
|
||||||
|
font.pixelSize: Theme.fsTitle
|
||||||
|
font.weight: Theme.weightDisplay
|
||||||
|
font.italic: true
|
||||||
|
font.letterSpacing: 0.5
|
||||||
|
}
|
||||||
|
|
||||||
|
// Archivo Black reserves descender room the time never uses — "12:04"
|
||||||
|
// is all cap height — so centring the line box left the digits sitting
|
||||||
|
// above everything beside them. Centre the ink instead.
|
||||||
|
// `tightBoundingRect` is measured from the baseline, so the ink's top
|
||||||
|
// inside the line box is `ascent + ink.y`.
|
||||||
|
readonly property real timeInkOffset: {
|
||||||
|
const ink = timeMetrics.tightBoundingRect;
|
||||||
|
if (ink.height <= 0) return 0;
|
||||||
|
const inkCentre = timeFont.ascent + ink.y + ink.height / 2;
|
||||||
|
return Math.round(timeMetrics.boundingRect.height / 2 - inkCentre);
|
||||||
|
}
|
||||||
|
|
||||||
|
FontMetrics {
|
||||||
|
id: timeFont
|
||||||
|
font: timeMetrics.font
|
||||||
|
}
|
||||||
|
|
||||||
SplitText {
|
SplitText {
|
||||||
id: timeText
|
id: timeText
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
anchors.verticalCenterOffset: layout.timeInkOffset
|
||||||
|
width: timeMetrics.advanceWidth
|
||||||
text: Qt.formatDateTime(clock.date, "HH:mm")
|
text: Qt.formatDateTime(clock.date, "HH:mm")
|
||||||
pixelSize: Theme.fsTitle
|
pixelSize: Theme.fsTitle
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
split: 1.4
|
split: 1.4
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+11
-2
@@ -89,6 +89,7 @@ PanelWindow {
|
|||||||
id: volIcon
|
id: volIcon
|
||||||
icon: Audio.icon
|
icon: Audio.icon
|
||||||
readout: Audio.muted ? "" : Audio.volumePercent + "%"
|
readout: Audio.muted ? "" : Audio.volumePercent + "%"
|
||||||
|
reserveReadout: true
|
||||||
label: "Volume"
|
label: "Volume"
|
||||||
statusText: Audio.muted ? "Muted" : Audio.volumePercent + "% · " + Audio.sinkName
|
statusText: Audio.muted ? "Muted" : Audio.volumePercent + "% · " + Audio.sinkName
|
||||||
hint: "Scroll to adjust"
|
hint: "Scroll to adjust"
|
||||||
@@ -162,6 +163,7 @@ PanelWindow {
|
|||||||
readout: Notifs.unread > 0
|
readout: Notifs.unread > 0
|
||||||
? (Notifs.unread > 9 ? "9+" : String(Notifs.unread))
|
? (Notifs.unread > 9 ? "9+" : String(Notifs.unread))
|
||||||
: ""
|
: ""
|
||||||
|
reserveReadout: true
|
||||||
dim: Notifs.dnd
|
dim: Notifs.dnd
|
||||||
alert: Notifs.hasUnread && !Notifs.dnd
|
alert: Notifs.hasUnread && !Notifs.dnd
|
||||||
suppressTooltip: notifPopout.detailActive
|
suppressTooltip: notifPopout.detailActive
|
||||||
@@ -187,10 +189,17 @@ PanelWindow {
|
|||||||
implicitWidth: Theme.railWidth
|
implicitWidth: Theme.railWidth
|
||||||
implicitHeight: Theme.padM + 4
|
implicitHeight: Theme.padM + 4
|
||||||
|
|
||||||
|
// Same correction as the bar's divider, on the other axis: a 22px rule
|
||||||
|
// rises 22 * skew ≈ 5px across its run, so the box has to be that tall
|
||||||
|
// plus the weight of the stroke. At height 1 the polygon inverted and
|
||||||
|
// the rule rendered as a stubby wedge sitting left of centre.
|
||||||
|
readonly property real ruleWeight: 1.5
|
||||||
|
readonly property real ruleWidth: 22
|
||||||
|
|
||||||
Skew {
|
Skew {
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
width: 22
|
width: parent.ruleWidth
|
||||||
height: 1
|
height: parent.ruleWidth * Theme.skew + parent.ruleWeight
|
||||||
vertical: true
|
vertical: true
|
||||||
color: Theme.alpha(Theme.outline, 0.9)
|
color: Theme.alpha(Theme.outline, 0.9)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,13 @@ Item {
|
|||||||
property bool dim: false
|
property bool dim: false
|
||||||
property bool pulsing: false
|
property bool pulsing: false
|
||||||
|
|
||||||
|
// Hold the readout line open even while there is nothing to put in it.
|
||||||
|
// Volume drops its percentage when muted and the bell only carries a count
|
||||||
|
// when something is unread, so without this the slot collapsed from 42px to
|
||||||
|
// 32px and every icon below it jumped a third of its own height.
|
||||||
|
property bool reserveReadout: false
|
||||||
|
|
||||||
|
readonly property bool hasReadout: root.readout !== "" || root.reserveReadout
|
||||||
readonly property bool hovered: hover.hovered
|
readonly property bool hovered: hover.hovered
|
||||||
|
|
||||||
// Clearance between the wipe and the rail's left edge, chosen so the bar
|
// Clearance between the wipe and the rail's left edge, chosen so the bar
|
||||||
@@ -31,16 +38,42 @@ Item {
|
|||||||
signal scrolled(real delta)
|
signal scrolled(real delta)
|
||||||
|
|
||||||
implicitWidth: Theme.railWidth
|
implicitWidth: Theme.railWidth
|
||||||
implicitHeight: root.readout !== "" ? 42 : 32
|
implicitHeight: root.hasReadout ? root.glyphBand + readoutLine.height + 1 : root.glyphBand
|
||||||
|
|
||||||
Column {
|
// The glyph always sits centred in a fixed band at the top of the slot and
|
||||||
|
// the readout hangs below it, rather than the pair being centred together.
|
||||||
|
// Centring the pair meant the icon slid up and down by a few px whenever its
|
||||||
|
// number appeared or vanished — the icons stopped lining up with each other
|
||||||
|
// exactly when something was changing and you were looking at them.
|
||||||
|
readonly property real glyphBand: 32
|
||||||
|
|
||||||
|
// Nerd Font's status glyphs are not all centred inside their own advance —
|
||||||
|
// the muted-speaker and muted-mic marks carry their cross out to the right,
|
||||||
|
// so centring the advance box left them visibly off-axis next to the wifi
|
||||||
|
// and bluetooth glyphs. Centre the ink instead, capped so a glyph with an
|
||||||
|
// odd bounding box cannot slide far off the rail's axis.
|
||||||
|
readonly property real opticalShift: {
|
||||||
|
const ink = glyphMetrics.tightBoundingRect;
|
||||||
|
if (ink.width <= 0) return 0;
|
||||||
|
const off = glyphMetrics.advanceWidth / 2 - (ink.x + ink.width / 2);
|
||||||
|
return Math.max(-4, Math.min(4, off));
|
||||||
|
}
|
||||||
|
|
||||||
|
TextMetrics {
|
||||||
|
id: glyphMetrics
|
||||||
|
text: root.icon
|
||||||
|
font.family: Theme.fontIcon
|
||||||
|
font.pixelSize: Theme.fsLarge
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
id: layout
|
id: layout
|
||||||
anchors.centerIn: parent
|
anchors.fill: parent
|
||||||
spacing: 1
|
|
||||||
|
|
||||||
Icon {
|
Icon {
|
||||||
id: glyph
|
id: glyph
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
x: (root.width - width) / 2 + root.opticalShift
|
||||||
|
y: (root.glyphBand - height) / 2
|
||||||
text: root.icon
|
text: root.icon
|
||||||
pulsing: root.pulsing
|
pulsing: root.pulsing
|
||||||
font.pixelSize: Theme.fsLarge
|
font.pixelSize: Theme.fsLarge
|
||||||
@@ -57,7 +90,10 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
id: readoutLine
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.topMargin: root.glyphBand + 1
|
||||||
visible: root.readout !== ""
|
visible: root.readout !== ""
|
||||||
text: root.readout
|
text: root.readout
|
||||||
color: root.dim ? Theme.muted : Theme.subtext
|
color: root.dim ? Theme.muted : Theme.subtext
|
||||||
@@ -88,7 +124,7 @@ Item {
|
|||||||
anchors.leftMargin: root.wipeInset
|
anchors.leftMargin: root.wipeInset
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
width: 2
|
width: 2
|
||||||
height: root.hovered ? layout.implicitHeight : 0
|
height: root.hovered ? root.height - 4 : 0
|
||||||
color: Theme.glow
|
color: Theme.glow
|
||||||
|
|
||||||
Behavior on height {
|
Behavior on height {
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ BarPill {
|
|||||||
label: "CPU"
|
label: "CPU"
|
||||||
value: Sys.cpuUsage
|
value: Sys.cpuUsage
|
||||||
readout: Math.round(Sys.cpuUsage) + "%"
|
readout: Math.round(Sys.cpuUsage) + "%"
|
||||||
|
widest: "100%"
|
||||||
}
|
}
|
||||||
|
|
||||||
Divider {}
|
Divider {}
|
||||||
@@ -37,6 +38,7 @@ BarPill {
|
|||||||
label: "MEM"
|
label: "MEM"
|
||||||
value: Sys.memPercent
|
value: Sys.memPercent
|
||||||
readout: Sys.memUsed.toFixed(1) + "G"
|
readout: Sys.memUsed.toFixed(1) + "G"
|
||||||
|
widest: "88.8G"
|
||||||
}
|
}
|
||||||
|
|
||||||
Divider { visible: Sys.gpuAvailable }
|
Divider { visible: Sys.gpuAvailable }
|
||||||
@@ -46,15 +48,24 @@ BarPill {
|
|||||||
label: "GPU"
|
label: "GPU"
|
||||||
value: Sys.gpuUsage
|
value: Sys.gpuUsage
|
||||||
readout: Math.round(Sys.gpuUsage) + "%"
|
readout: Math.round(Sys.gpuUsage) + "%"
|
||||||
|
widest: "100%"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
component Divider: Skew {
|
component Divider: Item {
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
width: 1
|
implicitWidth: rule.width
|
||||||
height: 18
|
implicitHeight: 18
|
||||||
|
|
||||||
|
// Sized to hold its own lean — see the note on the bar's divider.
|
||||||
|
Skew {
|
||||||
|
id: rule
|
||||||
|
anchors.centerIn: parent
|
||||||
|
width: parent.height * Theme.skew + 1
|
||||||
|
height: parent.height
|
||||||
color: Theme.alpha(Theme.outline, 0.8)
|
color: Theme.alpha(Theme.outline, 0.8)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// A tiny fixed label makes every number self-describing without turning the
|
// A tiny fixed label makes every number self-describing without turning the
|
||||||
// compact meter cluster back into three separate cards.
|
// compact meter cluster back into three separate cards.
|
||||||
@@ -65,14 +76,35 @@ BarPill {
|
|||||||
property real value: 0
|
property real value: 0
|
||||||
property string readout: ""
|
property string readout: ""
|
||||||
|
|
||||||
|
// The widest reading this metric will ever show. The number column is
|
||||||
|
// sized from this rather than from the live text, because sizing to the
|
||||||
|
// live text is what made the whole right-hand group breathe in and out:
|
||||||
|
// "9%" and "100%" are ~14px apart in Archivo Black, so every tick of the
|
||||||
|
// CPU sampler nudged the metrics, the media pill and the clock sideways.
|
||||||
|
// Reserving the maximum costs a few px of blank and buys a bar that
|
||||||
|
// never moves.
|
||||||
|
property string widest: "100%"
|
||||||
|
|
||||||
|
readonly property real numberWidth: Math.max(gauge.width, metrics.advanceWidth)
|
||||||
|
readonly property real headWidth: labelText.implicitWidth + head.spacing + numberWidth
|
||||||
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
spacing: 2
|
spacing: 2
|
||||||
|
width: Math.max(headWidth, 44)
|
||||||
|
|
||||||
|
TextMetrics {
|
||||||
|
id: metrics
|
||||||
|
text: metric.widest
|
||||||
|
font: gauge.font
|
||||||
|
}
|
||||||
|
|
||||||
Row {
|
Row {
|
||||||
|
id: head
|
||||||
spacing: 4
|
spacing: 4
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
anchors.baseline: readoutText.baseline
|
id: labelText
|
||||||
|
anchors.baseline: gauge.baseline
|
||||||
text: metric.label
|
text: metric.label
|
||||||
color: Theme.muted
|
color: Theme.muted
|
||||||
font.family: Theme.fontMono
|
font.family: Theme.fontMono
|
||||||
@@ -83,7 +115,7 @@ BarPill {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
id: readoutText
|
id: gauge
|
||||||
text: metric.readout
|
text: metric.readout
|
||||||
color: Theme.heat(metric.value)
|
color: Theme.heat(metric.value)
|
||||||
font.family: Theme.fontDisplay
|
font.family: Theme.fontDisplay
|
||||||
@@ -99,12 +131,15 @@ BarPill {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Ends flush with the reading above it instead of stopping short at a
|
||||||
|
// fixed 43px, so each metric reads as one block.
|
||||||
MeterBar {
|
MeterBar {
|
||||||
value: metric.value
|
value: metric.value
|
||||||
segments: 9
|
segments: 9
|
||||||
segmentWidth: 3
|
|
||||||
spacing: 2
|
spacing: 2
|
||||||
height: 5
|
height: 5
|
||||||
|
width: metric.width
|
||||||
|
segmentWidth: (width - 8 * spacing) / 9
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -31,6 +31,20 @@ Shape {
|
|||||||
// rail slab.
|
// rail slab.
|
||||||
property bool vertical: false
|
property bool vertical: false
|
||||||
|
|
||||||
|
// NOTE ON SIZING. The lean shifts one edge by `lean * height` (or by
|
||||||
|
// `lean * width` when vertical), and the piece that actually gets painted is
|
||||||
|
// what is left: a Skew declared 1px wide and 20px tall does not draw a 1px
|
||||||
|
// rule at an angle, it draws a rule |1 - 20 * 0.249| = 4px thick that hangs
|
||||||
|
// 4px to the *left* of the box it was given. That is why the bar's and the
|
||||||
|
// rail's hairlines came out fat and off-centre. A thin leaning rule has to be
|
||||||
|
// declared with room for its own lean — `height * Theme.skew + weight` — and
|
||||||
|
// the call sites that draw one now do exactly that.
|
||||||
|
//
|
||||||
|
// Zero-sized pieces still have a lean offset, so a collapsed hover wipe or a
|
||||||
|
// meter at 0 drew a sub-pixel wedge of pure accent — the stray red dot under
|
||||||
|
// the metrics. Nothing with no extent should paint at all.
|
||||||
|
visible: root.width > 0 && root.height > 0
|
||||||
|
|
||||||
preferredRendererType: Shape.CurveRenderer
|
preferredRendererType: Shape.CurveRenderer
|
||||||
asynchronous: false
|
asynchronous: false
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user