feat: widget visibility toggles in the control panel#2
Conversation
Theme.qml already declared mod* enable flags labelled "controlled by ControlPanel", but nothing used them: the flags were dead and the panel had no toggles. This finishes that feature. - Each toggleable widget module gains a generic `shown` property and collapses (visible:false + implicitWidth:0) when off, matching the self-hiding pattern ClaudeWidget already used. - Bar.qml passes `shown: root.mod*` to every widget, gates the inline status cluster, and atomVisible() now reports emptied groups so no stray section pill or separator is drawn. - New reusable ToggleTile component; the SPLITS grid is converted onto it and the new WIDGETS section reuses it. - ControlPanel gains a WIDGETS section toggling all 13 bar modules. - Adds modClaude, the one bar widget the original flag list omitted. No persistence: flags default on and reset on reload, consistent with the existing splits / bar-color toggles.
HANCORE-linux
left a comment
There was a problem hiding this comment.
Thanks for this — the feature is genuinely useful and the implementation is clean (the ToggleTile extraction and finishing the dead mod* flags are both nice). I merged it locally against current main (clean auto-merge, no conflicts) and tested the result on the bar. One blocker on the reflow:
Partial hiding within a group leaves layout artifacts
When some but not all widgets in a section are hidden, the pills do not shrink correctly and stray remnants (leftover section-pill area / separators) stay on the bar.
Repro
- Open the control panel → WIDGETS.
- Hide a single widget in the middle of a group (e.g. CPU while Memory/Volume stay on), or hide a widget at a group edge (e.g. Memory).
- The widget disappears, but the surrounding section pill does not resize to the new content, and separator/pill remnants remain.
Toggling an entire group off is fine — that path is covered by the atomVisible() change. The gap is partial hiding.
Why
atomVisible() was updated to treat a fully-empty group as absent, but the pill/separator geometry is still computed from fixed widget positions — atomCL()/atomCR(), runLeftEdge()/runRightEdge() and the static separators (sepArch, sepMon, sepML, sepNet, …) reference specific widget ids and do not skip widgets whose width is now 0. So a hidden widget at a group boundary (or between visible ones) yields stale edges.
Suggestion
The content-edge helpers need to resolve to the first/last visible widget in a group rather than a hardcoded id, and the separators between groups should hide when the adjacent content collapses. That is the fiddliest part of Bar.qml, so it is worth handling explicitly with the partial-hide cases in mind.
Happy to pair on the geometry side if helpful. Everything else (per-widget shown, ToggleTile, modClaude) looks good to merge once the reflow handles partial hiding.
(Note: persistence — once added — should extend the existing ~/.cache/quickshell_splits mechanism on main rather than a separate FileView path, so there is a single source of truth.)
What
Finishes the half-built module-toggle feature.
Theme.qmlalready declares a block ofmod*flags commented "controlled by ControlPanel", but nothing referenced them and the panel had no UI, so they were effectively dead code. This wires them up.A new WIDGETS section in the control panel lets you show/hide individual bar modules: Workspaces, Status, Memory, CPU, Volume, Claude, Weather, Media, Battery, Brightness, Network, Power, Bluetooth.
Why
On dense or high-DPI / fractionally-scaled bars (for example a 2560x1600 panel at scale 1.6, which is 1600 logical px) the left content can run wide and crowd the centered clock. Letting people hide modules they do not use declutters the bar and relieves that crowding as a side effect. It also makes the bar feel personal: show only what you want.
How
shownproperty and hides itself when false (visible: shown,implicitWidth: 0). This is the same self-hiding patternClaudeWidgetalready used, so modules stay generic and do not reference the theme flags directly.Bar.qmlpassesshown: root.mod*to each widget instance and gates the inline status cluster.atomVisible()now reports a group as empty when all of its widgets are hidden, so no stray section pill or separator gets drawn.ToggleTilecomponent. The existing SPLITS grid is converted onto it (removing duplicated tile markup), and the new WIDGETS section reuses it.modClaude, the one bar widget the original flag list left out.Notes
FileViewplus a JSON adapter would be a natural follow-up. Happy to do that in a separate PR if you would want it.