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 },
|
||||
}
|
||||
|
||||
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
|
||||
-- borrowed projector or a monitor at the office still lights up.
|
||||
|
||||
@@ -115,10 +115,17 @@ PanelWindow {
|
||||
implicitWidth: Theme.padM * 2
|
||||
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 {
|
||||
anchors.centerIn: parent
|
||||
width: 1
|
||||
height: 20
|
||||
width: parent.ruleHeight * Theme.skew + parent.ruleWeight
|
||||
height: parent.ruleHeight
|
||||
color: Theme.alpha(Theme.outline, 0.9)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,9 +37,15 @@ Item {
|
||||
// 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
|
||||
// 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 ruleInset: 5
|
||||
readonly property real ruleBand: root.standalone ? 0 : root.ruleHeight + root.ruleInset
|
||||
readonly property real ruleInset: 3
|
||||
readonly property real ruleBand: root.standalone ? 0 : 2
|
||||
|
||||
// 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
|
||||
|
||||
@@ -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 {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
width: 2
|
||||
width: 22 * Theme.skew + 3
|
||||
height: 22
|
||||
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 {
|
||||
id: timeText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.verticalCenterOffset: layout.timeInkOffset
|
||||
width: timeMetrics.advanceWidth
|
||||
text: Qt.formatDateTime(clock.date, "HH:mm")
|
||||
pixelSize: Theme.fsTitle
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
split: 1.4
|
||||
}
|
||||
|
||||
|
||||
+11
-2
@@ -89,6 +89,7 @@ PanelWindow {
|
||||
id: volIcon
|
||||
icon: Audio.icon
|
||||
readout: Audio.muted ? "" : Audio.volumePercent + "%"
|
||||
reserveReadout: true
|
||||
label: "Volume"
|
||||
statusText: Audio.muted ? "Muted" : Audio.volumePercent + "% · " + Audio.sinkName
|
||||
hint: "Scroll to adjust"
|
||||
@@ -162,6 +163,7 @@ PanelWindow {
|
||||
readout: Notifs.unread > 0
|
||||
? (Notifs.unread > 9 ? "9+" : String(Notifs.unread))
|
||||
: ""
|
||||
reserveReadout: true
|
||||
dim: Notifs.dnd
|
||||
alert: Notifs.hasUnread && !Notifs.dnd
|
||||
suppressTooltip: notifPopout.detailActive
|
||||
@@ -187,10 +189,17 @@ PanelWindow {
|
||||
implicitWidth: Theme.railWidth
|
||||
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 {
|
||||
anchors.centerIn: parent
|
||||
width: 22
|
||||
height: 1
|
||||
width: parent.ruleWidth
|
||||
height: parent.ruleWidth * Theme.skew + parent.ruleWeight
|
||||
vertical: true
|
||||
color: Theme.alpha(Theme.outline, 0.9)
|
||||
}
|
||||
|
||||
@@ -21,6 +21,13 @@ Item {
|
||||
property bool dim: 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
|
||||
|
||||
// Clearance between the wipe and the rail's left edge, chosen so the bar
|
||||
@@ -31,16 +38,42 @@ Item {
|
||||
signal scrolled(real delta)
|
||||
|
||||
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
|
||||
anchors.centerIn: parent
|
||||
spacing: 1
|
||||
anchors.fill: parent
|
||||
|
||||
Icon {
|
||||
id: glyph
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
x: (root.width - width) / 2 + root.opticalShift
|
||||
y: (root.glyphBand - height) / 2
|
||||
text: root.icon
|
||||
pulsing: root.pulsing
|
||||
font.pixelSize: Theme.fsLarge
|
||||
@@ -57,7 +90,10 @@ Item {
|
||||
}
|
||||
|
||||
Text {
|
||||
id: readoutLine
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: root.glyphBand + 1
|
||||
visible: root.readout !== ""
|
||||
text: root.readout
|
||||
color: root.dim ? Theme.muted : Theme.subtext
|
||||
@@ -88,7 +124,7 @@ Item {
|
||||
anchors.leftMargin: root.wipeInset
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
width: 2
|
||||
height: root.hovered ? layout.implicitHeight : 0
|
||||
height: root.hovered ? root.height - 4 : 0
|
||||
color: Theme.glow
|
||||
|
||||
Behavior on height {
|
||||
|
||||
@@ -29,6 +29,7 @@ BarPill {
|
||||
label: "CPU"
|
||||
value: Sys.cpuUsage
|
||||
readout: Math.round(Sys.cpuUsage) + "%"
|
||||
widest: "100%"
|
||||
}
|
||||
|
||||
Divider {}
|
||||
@@ -37,6 +38,7 @@ BarPill {
|
||||
label: "MEM"
|
||||
value: Sys.memPercent
|
||||
readout: Sys.memUsed.toFixed(1) + "G"
|
||||
widest: "88.8G"
|
||||
}
|
||||
|
||||
Divider { visible: Sys.gpuAvailable }
|
||||
@@ -46,15 +48,24 @@ BarPill {
|
||||
label: "GPU"
|
||||
value: Sys.gpuUsage
|
||||
readout: Math.round(Sys.gpuUsage) + "%"
|
||||
widest: "100%"
|
||||
}
|
||||
}
|
||||
|
||||
component Divider: Skew {
|
||||
component Divider: Item {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
width: 1
|
||||
height: 18
|
||||
implicitWidth: rule.width
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
// A tiny fixed label makes every number self-describing without turning the
|
||||
// compact meter cluster back into three separate cards.
|
||||
@@ -65,14 +76,35 @@ BarPill {
|
||||
property real value: 0
|
||||
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
|
||||
spacing: 2
|
||||
width: Math.max(headWidth, 44)
|
||||
|
||||
TextMetrics {
|
||||
id: metrics
|
||||
text: metric.widest
|
||||
font: gauge.font
|
||||
}
|
||||
|
||||
Row {
|
||||
id: head
|
||||
spacing: 4
|
||||
|
||||
Text {
|
||||
anchors.baseline: readoutText.baseline
|
||||
id: labelText
|
||||
anchors.baseline: gauge.baseline
|
||||
text: metric.label
|
||||
color: Theme.muted
|
||||
font.family: Theme.fontMono
|
||||
@@ -83,7 +115,7 @@ BarPill {
|
||||
}
|
||||
|
||||
Text {
|
||||
id: readoutText
|
||||
id: gauge
|
||||
text: metric.readout
|
||||
color: Theme.heat(metric.value)
|
||||
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 {
|
||||
value: metric.value
|
||||
segments: 9
|
||||
segmentWidth: 3
|
||||
spacing: 2
|
||||
height: 5
|
||||
width: metric.width
|
||||
segmentWidth: (width - 8 * spacing) / 9
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -31,6 +31,20 @@ Shape {
|
||||
// rail slab.
|
||||
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
|
||||
asynchronous: false
|
||||
|
||||
|
||||
Reference in New Issue
Block a user