Promote bar/common to qs.Ui kit module

This commit is contained in:
Ryan Hughes
2026-05-17 22:33:08 -04:00
parent 408dada45d
commit 6b915926b2
25 changed files with 110 additions and 98 deletions
@@ -3,7 +3,7 @@ import QtQuick.Controls
import Quickshell
import Quickshell.Io
import Quickshell.Services.Pipewire
import "../common" as Common
import qs.Ui
Item {
id: root
@@ -90,7 +90,7 @@ Item {
// selectedIndex semantics within a section:
// -1 → on the slider row (h/l adjusts volume, m/Enter mute)
// 0..N-1 → on the Nth device/stream row
// Visuals derive from hasCursor/current via Common.CursorSurface, never
// Visuals derive from hasCursor/current via CursorSurface, never
// from containsMouse — that's what keeps the highlight unique across
// keyboard + mouse like wifi does.
property string focusSection: "output"
@@ -348,7 +348,7 @@ Item {
function hide(): void { root.closePopout() }
}
Common.WidgetButton {
WidgetButton {
id: button
anchors.fill: parent
bar: root.bar
@@ -366,7 +366,7 @@ Item {
}
}
Common.KeyboardPanel {
KeyboardPanel {
id: panel
anchorItem: button
owner: root
@@ -440,7 +440,7 @@ Item {
width: parent.width
spacing: 8
Common.PanelSectionHeader {
PanelSectionHeader {
text: "Output"
foreground: root.bar.foreground
fontFamily: root.bar.fontFamily
@@ -462,7 +462,7 @@ Item {
// Output slider row — itself a cursor target (selectedIndex === -1
// when focusSection === "output"). h/l adjust the value via
// root.adjustVolume; m / Enter toggle mute.
Common.CursorSurface {
CursorSurface {
id: outputSliderRow
width: parent.width
height: outputSliderInner.implicitHeight + 8
@@ -496,7 +496,7 @@ Item {
}
}
Common.Slider {
PanelSlider {
id: outputSlider
bar: root.bar
width: parent.width - outputIconText.width - outputPercent.width - 16
@@ -559,7 +559,7 @@ Item {
width: parent.width
spacing: 8
Common.PanelSectionHeader {
PanelSectionHeader {
text: "Input"
foreground: root.bar.foreground
fontFamily: root.bar.fontFamily
@@ -578,7 +578,7 @@ Item {
}
}
Common.CursorSurface {
CursorSurface {
id: inputSliderRow
visible: !!root.source
width: parent.width
@@ -613,7 +613,7 @@ Item {
}
}
Common.Slider {
PanelSlider {
id: inputSlider
bar: root.bar
width: parent.width - inputIconText.width - inputPercent.width - 16
@@ -672,7 +672,7 @@ Item {
spacing: 6
visible: root.audioStreams.length > 0
Common.PanelSectionHeader {
PanelSectionHeader {
text: "Playing"
foreground: root.bar.foreground
fontFamily: root.bar.fontFamily
@@ -701,7 +701,7 @@ Item {
// Output device row — cursor target inside the "output" section. Mouse
// hover updates the panel cursor at the root; visuals come entirely
// from hasCursor/current via CursorSurface, never from containsMouse.
component SinkRow: Common.CursorSurface {
component SinkRow: CursorSurface {
id: sinkRow
required property var node
required property int rowIndex
@@ -767,7 +767,7 @@ Item {
}
// Input device row — sibling of SinkRow for the "input" section.
component SourceRow: Common.CursorSurface {
component SourceRow: CursorSurface {
id: sourceRow
required property var node
required property int rowIndex
@@ -836,7 +836,7 @@ Item {
// The stream has its own slider inline, so h/l from the keyboard
// adjusts THIS stream's volume (not the global output) when the cursor
// sits on this row. Enter/Space mutes the stream.
component StreamRow: Common.CursorSurface {
component StreamRow: CursorSurface {
id: streamRow
required property var node
required property int rowIndex
@@ -906,7 +906,7 @@ Item {
}
}
Common.Slider {
PanelSlider {
bar: root.bar
width: parent.width
minimum: 0
@@ -3,7 +3,7 @@ import QtQuick.Controls
import Quickshell
import Quickshell.Io
import Quickshell.Bluetooth
import "../common" as Common
import qs.Ui
Item {
id: root
@@ -71,7 +71,7 @@ Item {
// them, Enter activates.
// "known" — paired/known device rows; Enter toggles connect.
// "discovered" — unpaired devices visible while scanning; Enter pairs.
// Visuals always come from Common.CursorSurface (hasCursor / current),
// Visuals always come from CursorSurface (hasCursor / current),
// never from containsMouse. Mouse hover updates root cursor state too,
// guaranteeing one highlight on screen.
property string focusSection: "header"
@@ -310,7 +310,7 @@ Item {
function hide(): void { root.closePopout() }
}
Common.WidgetButton {
WidgetButton {
id: button
anchors.fill: parent
bar: root.bar
@@ -322,7 +322,7 @@ Item {
}
}
Common.KeyboardPanel {
KeyboardPanel {
id: panel
anchorItem: button
owner: root
@@ -445,7 +445,7 @@ Item {
}
// Discovered (unpaired) devices, only shown while scanning.
Common.PanelSectionHeader {
PanelSectionHeader {
visible: root.adapter && root.adapter.discovering && root.discoveredDevices.length > 0
text: "Discovered"
foreground: root.bar.foreground
@@ -483,11 +483,11 @@ Item {
}
}
// Header pill — wraps Common.PillButton with cursor-state binding so it
// Header pill — wraps PillButton with cursor-state binding so it
// participates in the same single-cursor model as device rows. We don't
// use Common.CursorSurface here because the pill already provides its
// use CursorSurface here because the pill already provides its
// own active/hover visuals and we want them to layer correctly.
component HeaderPill: Common.PillButton {
component HeaderPill: PillButton {
id: pill
required property int pillIndex
property bool pillEnabled: true
@@ -528,7 +528,7 @@ Item {
// connect that drops back to Disconnected within 10s surfaces as "Failed".
// Now a cursor target: hasCursor binds to root state, mouse hover updates
// root state. The X button on the right is a PanelActionButton.
component DeviceRow: Common.CursorSurface {
component DeviceRow: CursorSurface {
id: row
required property var dev
required property int rowIndex
@@ -660,7 +660,7 @@ Item {
// Explicit close button on any known device. Action depends on state:
// connected -> disconnect, otherwise -> forget the pairing entirely.
Common.PanelActionButton {
PanelActionButton {
id: disconnectBtn
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
@@ -1,7 +1,7 @@
import QtQuick
import QtQuick.Layouts
import Quickshell
import "../common" as Common
import qs.Ui
Item {
id: root
@@ -57,7 +57,7 @@ Item {
onDateChanged: root.now = clockTimer.date
}
Common.WidgetButton {
WidgetButton {
id: button
anchors.fill: parent
bar: root.bar
@@ -76,7 +76,7 @@ Item {
}
}
Common.PopupCard {
PopupCard {
id: popup
anchorItem: button
bar: root.bar
@@ -94,7 +94,7 @@ Item {
width: parent.width
implicitHeight: 28
Common.PillButton {
PillButton {
id: prevButton
anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter
@@ -114,7 +114,7 @@ Item {
font.bold: true
}
Common.PillButton {
PillButton {
id: nextButton
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
@@ -1,7 +1,7 @@
import QtQuick
import Quickshell
import Quickshell.Io
import "../common" as Common
import qs.Ui
Item {
id: root
@@ -53,7 +53,7 @@ Item {
implicitWidth: button.implicitWidth
implicitHeight: button.implicitHeight
Common.WidgetButton {
WidgetButton {
id: button
anchors.fill: parent
bar: root.bar
@@ -2,7 +2,7 @@ import QtQuick
import Quickshell
import Quickshell.Hyprland
import Quickshell.Io
import "../common" as Common
import qs.Ui
Item {
id: root
@@ -71,7 +71,7 @@ Item {
implicitWidth: button.implicitWidth
implicitHeight: button.implicitHeight
Common.WidgetButton {
WidgetButton {
id: button
anchors.fill: parent
bar: root.bar
@@ -1,7 +1,7 @@
import QtQuick
import Quickshell
import Quickshell.Services.Mpris
import "../common" as Common
import qs.Ui
Item {
id: root
@@ -113,7 +113,7 @@ Item {
onExited: if (root.bar) root.bar.hideTooltip(root)
}
Common.PopupCard {
PopupCard {
id: popup
anchorItem: root
bar: root.bar
@@ -198,7 +198,7 @@ Item {
anchors.horizontalCenter: parent.horizontalCenter
spacing: 6
Common.PillButton {
PillButton {
iconText: "󰒮"
foreground: root.bar.foreground
horizontalPadding: 10
@@ -208,7 +208,7 @@ Item {
onClicked: if (root.activePlayer) root.activePlayer.previous()
}
Common.PillButton {
PillButton {
iconText: root.activePlayer && root.activePlayer.isPlaying ? "󰏤" : "󰐊"
foreground: root.bar.foreground
horizontalPadding: 14
@@ -219,7 +219,7 @@ Item {
onClicked: if (root.activePlayer) root.activePlayer.togglePlaying()
}
Common.PillButton {
PillButton {
iconText: "󰒭"
foreground: root.bar.foreground
horizontalPadding: 10
@@ -1,7 +1,7 @@
import QtQuick
import Quickshell
import Quickshell.Services.Pipewire
import "../common" as Common
import qs.Ui
Item {
id: root
@@ -36,7 +36,7 @@ Item {
PwObjectTracker { objects: root.source ? [root.source] : [] }
Common.WidgetButton {
WidgetButton {
id: button
anchors.fill: parent
bar: root.bar
@@ -2,7 +2,7 @@ import QtQuick
import QtQuick.Controls
import Quickshell
import Quickshell.Io
import "../common" as Common
import qs.Ui
Item {
id: root
@@ -174,7 +174,7 @@ Item {
onRunningChanged: if (!running) root.refresh()
}
Common.WidgetButton {
WidgetButton {
id: button
anchors.fill: parent
bar: root.bar
@@ -186,7 +186,7 @@ Item {
}
}
Common.PopupCard {
PopupCard {
anchorItem: button
owner: root
bar: root.bar
@@ -222,7 +222,7 @@ Item {
anchors.verticalCenter: parent.verticalCenter
}
Common.Slider {
PanelSlider {
id: brightnessSlider
bar: root.bar
width: parent.width - 22 - brightnessPercent.width - 16
@@ -2,7 +2,7 @@ import QtQuick
import QtQuick.Controls
import Quickshell
import Quickshell.Io
import "../common" as Common
import qs.Ui
Item {
id: root
@@ -66,7 +66,7 @@ Item {
// Single cursor model: exactly one highlighted spot across the whole
// panel, located via `focusSection` + (`selectedIndex` | `dnsIndex`).
// Mouse hover and keyboard nav both mutate this state at the root; items
// never read containsMouse for visuals. See Common.CursorSurface for the
// never read containsMouse for visuals. See CursorSurface for the
// shared chrome (fill / border) shared by NetworkRow and DnsProviderPill.
readonly property color activeFill: bar ? Qt.rgba(bar.foreground.r, bar.foreground.g, bar.foreground.b, 0.18) : "transparent"
@@ -518,7 +518,7 @@ iwctl station "$station" get-networks rssi-dbms 2>/dev/null \\
}
}
Common.WidgetButton {
WidgetButton {
id: button
anchors.fill: parent
bar: root.bar
@@ -535,12 +535,12 @@ iwctl station "$station" get-networks rssi-dbms 2>/dev/null \\
}
// Keyboard-driven popup anchored to the bar widget icon. The shared
// Common.KeyboardPanel handles the layer-shell PanelWindow scaffolding
// KeyboardPanel handles the layer-shell PanelWindow scaffolding
// (Exclusive focus on map, screen binding, anchored-to-icon positioning,
// outside-click via an overlay MouseArea + Region mask that lets the bar
// remain clickable, fade animation, popout coordination). What stays
// here is the wifi-specific UI inside.
Common.KeyboardPanel {
KeyboardPanel {
id: panel
anchorItem: button
owner: root
@@ -664,7 +664,7 @@ iwctl station "$station" get-networks rssi-dbms 2>/dev/null \\
}
}
Common.PillButton {
PillButton {
id: refreshBtn
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
@@ -681,7 +681,7 @@ iwctl station "$station" get-networks rssi-dbms 2>/dev/null \\
}
}
Common.PanelSeparator {
PanelSeparator {
visible: !!root.info.iface
foreground: root.bar.foreground
}
@@ -776,7 +776,7 @@ iwctl station "$station" get-networks rssi-dbms 2>/dev/null \\
}
// DNS provider selection.
Common.PanelSeparator {
PanelSeparator {
foreground: root.bar.foreground
}
@@ -784,7 +784,7 @@ iwctl station "$station" get-networks rssi-dbms 2>/dev/null \\
width: parent.width
spacing: 8
Common.PanelSectionHeader {
PanelSectionHeader {
text: "DNS provider"
foreground: root.bar.foreground
fontFamily: root.bar.fontFamily
@@ -825,12 +825,12 @@ iwctl station "$station" get-networks rssi-dbms 2>/dev/null \\
}
// Wi-Fi networks (only if a Wi-Fi station is available).
Common.PanelSeparator {
PanelSeparator {
visible: root.wifiStationAvailable
foreground: root.bar.foreground
}
Common.PanelSectionHeader {
PanelSectionHeader {
visible: root.wifiStationAvailable
text: root.scanning ? "Scanning Wi-Fi…" : "Wi-Fi networks"
foreground: root.bar.foreground
@@ -882,7 +882,7 @@ iwctl station "$station" get-networks rssi-dbms 2>/dev/null \\
// One DNS provider pill. The cursor + current visuals come entirely from
// CursorSurface; this component just binds them to the panel's cursor
// state and renders the label/tooltip/click target.
component DnsProviderPill: Common.CursorSurface {
component DnsProviderPill: CursorSurface {
id: pill
required property string provider
required property int index
@@ -921,7 +921,7 @@ iwctl station "$station" get-networks rssi-dbms 2>/dev/null \\
onClicked: pill.clicked()
}
Common.PanelToolTip {
PanelToolTip {
visible: pill.tooltipText !== "" && pillMouse.containsMouse
text: pill.tooltipText
panelForeground: root.bar.foreground
@@ -934,7 +934,7 @@ iwctl station "$station" get-networks rssi-dbms 2>/dev/null \\
// expands inline to a passphrase prompt when the user picks a protected
// network we don't have credentials for. Clicking a connected row
// disconnects; the X button on a connected row forgets the network.
component NetworkRow: Common.CursorSurface {
component NetworkRow: CursorSurface {
id: row
required property var net
required property int index
@@ -1042,7 +1042,7 @@ iwctl known-networks list 2>/dev/null \\
anchors.verticalCenter: parent.verticalCenter
}
Common.PanelActionButton {
PanelActionButton {
id: forgetBtn
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
@@ -1167,7 +1167,7 @@ iwctl known-networks list 2>/dev/null \\
// 22×22 right-anchored to line up with forgetBtn and lockIndicator
// above. Esc closes the prompt (handled by pwField.Keys.onEscapePressed)
// so there's no separate cancel button.
Common.PanelActionButton {
PanelActionButton {
id: connectPwBtn
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
@@ -2,7 +2,7 @@ import QtQuick
import QtQuick.Layouts
import Quickshell
import qs.Commons
import "../common" as Common
import qs.Ui
Item {
id: root
@@ -72,7 +72,7 @@ Item {
implicitWidth: button.implicitWidth
implicitHeight: button.implicitHeight
Common.WidgetButton {
WidgetButton {
id: button
anchors.fill: parent
bar: root.bar
@@ -103,7 +103,7 @@ Item {
}
}
Common.PopupCard {
PopupCard {
id: popup
anchorItem: button
bar: root.bar
@@ -1,7 +1,7 @@
import QtQuick
import Quickshell
import Quickshell.Io
import "../common" as Common
import qs.Ui
Item {
id: root
@@ -147,7 +147,7 @@ Item {
onButtonHoveredChanged: buttonHovered ? showPopup() : scheduleHide()
onPopupHoveredChanged: popupHovered ? hideTimer.stop() : scheduleHide()
Common.WidgetButton {
WidgetButton {
id: button
anchors.fill: parent
bar: root.bar
@@ -169,7 +169,7 @@ Item {
onHoveredChanged: root.buttonHovered = hovered
}
Common.PopupCard {
PopupCard {
id: popup
anchorItem: button
owner: root
@@ -1,7 +1,7 @@
import QtQuick
import Quickshell
import Quickshell.Io
import "../common" as Common
import qs.Ui
Item {
id: root
@@ -279,7 +279,7 @@ Item {
onTriggered: root.refresh()
}
Common.WidgetButton {
WidgetButton {
id: button
anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter
@@ -305,7 +305,7 @@ Item {
}
}
Common.PopupCard {
PopupCard {
id: popup
anchorItem: button
owner: root