update quickshell conf
This commit is contained in:
@ -17,68 +17,121 @@ PanelWindow {
|
|||||||
color: Theme.bg
|
color: Theme.bg
|
||||||
|
|
||||||
readonly property string screenName: modelData.name
|
readonly property string screenName: modelData.name
|
||||||
|
property string activePopup: ""
|
||||||
|
|
||||||
// Layout — three sections anchored independently for true centering
|
readonly property int bw: Theme.borderWidth // 2
|
||||||
|
readonly property int pad: Theme.enclosureMargin // 3
|
||||||
|
|
||||||
|
// ── Bar bottom border ─────────────────────────────────────────────
|
||||||
|
Rectangle {
|
||||||
|
anchors { bottom: parent.bottom; left: parent.left; right: parent.right }
|
||||||
|
height: root.bw
|
||||||
|
color: Theme.border
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Bar content ───────────────────────────────────────────────────
|
||||||
Item {
|
Item {
|
||||||
anchors.fill: parent
|
anchors {
|
||||||
anchors.leftMargin: 8
|
fill: parent
|
||||||
anchors.rightMargin: 8
|
leftMargin: 8
|
||||||
anchors.topMargin: 2
|
rightMargin: 8
|
||||||
anchors.bottomMargin: 2
|
topMargin: root.bw
|
||||||
|
bottomMargin: root.bw
|
||||||
|
}
|
||||||
|
|
||||||
// Left
|
Workspaces {
|
||||||
Enclosure {
|
anchors { left: parent.left; verticalCenter: parent.verticalCenter }
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
child: Workspaces {
|
|
||||||
screenName: root.screenName
|
screenName: root.screenName
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Center — truly centered regardless of left/right content width
|
MusicPlayer {
|
||||||
Enclosure {
|
|
||||||
anchors.centerIn: parent
|
|
||||||
child: MusicPlayer {
|
|
||||||
id: musicChip
|
id: musicChip
|
||||||
onClicked: musicControls.visible = !musicControls.visible
|
anchors { horizontalCenter: parent.horizontalCenter; verticalCenter: parent.verticalCenter }
|
||||||
}
|
onClicked: root.activePopup = root.activePopup === "controls" ? "" : "controls"
|
||||||
}
|
}
|
||||||
|
|
||||||
// Right — status chips
|
Row {
|
||||||
Enclosure {
|
id: rightRow
|
||||||
anchors.right: parent.right
|
anchors { right: parent.right; verticalCenter: parent.verticalCenter }
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
child: Row {
|
|
||||||
spacing: 8
|
spacing: 8
|
||||||
|
|
||||||
SysTray {
|
SysTray {
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
barWindow: root
|
barWindow: root
|
||||||
}
|
}
|
||||||
|
|
||||||
NetworkStatus {
|
NetworkStatus {
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
}
|
}
|
||||||
|
|
||||||
VolumeControl {
|
VolumeControl {
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
onClickedLeft: root.activePopup = root.activePopup === "mixer" ? "" : "mixer"
|
||||||
}
|
}
|
||||||
|
|
||||||
Clock {
|
Clock {
|
||||||
|
id: clockDisp
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
}
|
onClicked: root.activePopup = root.activePopup === "calendar" ? "" : "calendar"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Popup declared after the layout so musicChip is already initialised.
|
// ── Music controls popup ──────────────────────────────────────────
|
||||||
// Centered horizontally within the bar window, placed just below it.
|
PopoutWindow {
|
||||||
MusicPlayerControls {
|
popupName: "controls"
|
||||||
id: musicControls
|
activePopup: root.activePopup
|
||||||
visible: false
|
|
||||||
anchor.window: root
|
anchor.window: root
|
||||||
anchor.rect.x: Math.round((root.width - musicControls.width) / 2)
|
anchor.rect.y: root.implicitHeight - root.bw - Theme.radius
|
||||||
anchor.rect.y: root.height
|
anchor.rect.x: Math.round((root.width - implicitWidth) / 2)
|
||||||
|
|
||||||
|
implicitWidth: Math.max(musicChip.implicitWidth + 2 * root.pad,
|
||||||
|
ctrlContent.implicitWidth + 2 * root.bw)
|
||||||
|
implicitHeight: ctrlContent.implicitHeight + root.bw + Theme.radius
|
||||||
|
|
||||||
|
MusicPlayerControls {
|
||||||
|
id: ctrlContent
|
||||||
|
anchors { left: parent.left; right: parent.right }
|
||||||
player: musicChip.player
|
player: musicChip.player
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ── Calendar popup ────────────────────────────────────────────────
|
||||||
|
PopoutWindow {
|
||||||
|
popupName: "calendar"
|
||||||
|
activePopup: root.activePopup
|
||||||
|
|
||||||
|
anchor.window: root
|
||||||
|
anchor.rect.y: root.implicitHeight - root.bw - Theme.radius
|
||||||
|
readonly property real pw: Math.max(rightRow.width + 2 * root.pad,
|
||||||
|
calContent.implicitWidth + 2 * root.bw)
|
||||||
|
anchor.rect.x: root.width - pw
|
||||||
|
|
||||||
|
implicitWidth: pw
|
||||||
|
implicitHeight: calContent.implicitHeight + root.bw + Theme.radius
|
||||||
|
|
||||||
|
CalendarContent {
|
||||||
|
id: calContent
|
||||||
|
anchors { left: parent.left; right: parent.right }
|
||||||
|
now: clockDisp.now
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Volume mixer popup ────────────────────────────────────────────
|
||||||
|
PopoutWindow {
|
||||||
|
popupName: "mixer"
|
||||||
|
activePopup: root.activePopup
|
||||||
|
|
||||||
|
anchor.window: root
|
||||||
|
anchor.rect.y: root.implicitHeight - root.bw - Theme.radius
|
||||||
|
readonly property real pw: Math.max(rightRow.width + 2 * root.pad,
|
||||||
|
mixContent.implicitWidth + 2 * root.bw)
|
||||||
|
anchor.rect.x: root.width - pw
|
||||||
|
|
||||||
|
implicitWidth: pw
|
||||||
|
implicitHeight: mixContent.implicitHeight + root.bw + Theme.radius
|
||||||
|
|
||||||
|
VolumeMixerContent {
|
||||||
|
id: mixContent
|
||||||
|
anchors { left: parent.left; right: parent.right }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
139
roles/quickshell/files/bar/CalendarContent.qml
Normal file
139
roles/quickshell/files/bar/CalendarContent.qml
Normal file
@ -0,0 +1,139 @@
|
|||||||
|
import QtQuick
|
||||||
|
import "../components"
|
||||||
|
|
||||||
|
// Calendar grid – a plain Item so it can live inside an expanding section border.
|
||||||
|
Item {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property var now: new Date()
|
||||||
|
|
||||||
|
property int viewYear: now.getFullYear()
|
||||||
|
property int viewMonth: now.getMonth() // 0-based
|
||||||
|
|
||||||
|
readonly property var monthNames: [
|
||||||
|
"January","February","March","April","May","June",
|
||||||
|
"July","August","September","October","November","December"
|
||||||
|
]
|
||||||
|
readonly property int daysInMonth: new Date(viewYear, viewMonth + 1, 0).getDate()
|
||||||
|
// First weekday of month: Mon=0 … Sun=6
|
||||||
|
readonly property int startOffset: (new Date(viewYear, viewMonth, 1).getDay() + 6) % 7
|
||||||
|
readonly property int totalCells: Math.ceil((startOffset + daysInMonth) / 7) * 7
|
||||||
|
|
||||||
|
readonly property int todayYear: now.getFullYear()
|
||||||
|
readonly property int todayMonth: now.getMonth()
|
||||||
|
readonly property int todayDay: now.getDate()
|
||||||
|
|
||||||
|
// All widths derived from this constant — never from parent.width —
|
||||||
|
// to avoid Column polish loops when the popup is wider than the grid.
|
||||||
|
readonly property int cellW: 28
|
||||||
|
readonly property int cellGap: 2
|
||||||
|
readonly property int gridW: 7 * cellW + 6 * cellGap // 208
|
||||||
|
|
||||||
|
implicitWidth: gridW + 24
|
||||||
|
implicitHeight: calLayout.implicitHeight + 16
|
||||||
|
|
||||||
|
Column {
|
||||||
|
id: calLayout
|
||||||
|
// Centre the fixed-width grid inside the (potentially wider) popup.
|
||||||
|
// No left+right anchors → implicitWidth stays at gridW, no resize loop.
|
||||||
|
anchors { top: parent.top; topMargin: 8; horizontalCenter: parent.horizontalCenter }
|
||||||
|
spacing: 6
|
||||||
|
|
||||||
|
// Month navigation — all child widths are explicit constants
|
||||||
|
Row {
|
||||||
|
spacing: 0
|
||||||
|
|
||||||
|
Text {
|
||||||
|
text: "‹"
|
||||||
|
color: Theme.text
|
||||||
|
font.pixelSize: 16
|
||||||
|
width: 20
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
onClicked: {
|
||||||
|
if (root.viewMonth === 0) { root.viewMonth = 11; root.viewYear-- }
|
||||||
|
else root.viewMonth--
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
text: root.monthNames[root.viewMonth] + " " + root.viewYear
|
||||||
|
color: Theme.text
|
||||||
|
font.pixelSize: 13
|
||||||
|
font.bold: true
|
||||||
|
width: root.gridW - 40 // fixed constant, not parent.width
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
text: "›"
|
||||||
|
color: Theme.text
|
||||||
|
font.pixelSize: 16
|
||||||
|
width: 20
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
onClicked: {
|
||||||
|
if (root.viewMonth === 11) { root.viewMonth = 0; root.viewYear++ }
|
||||||
|
else root.viewMonth++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Weekday headers
|
||||||
|
Row {
|
||||||
|
spacing: root.cellGap
|
||||||
|
Repeater {
|
||||||
|
model: ["Mo","Tu","We","Th","Fr","Sa","Su"]
|
||||||
|
Text {
|
||||||
|
text: modelData
|
||||||
|
color: Theme.textDim
|
||||||
|
font.pixelSize: 10
|
||||||
|
width: root.cellW
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Day grid
|
||||||
|
Grid {
|
||||||
|
columns: 7
|
||||||
|
spacing: root.cellGap
|
||||||
|
Repeater {
|
||||||
|
model: root.totalCells
|
||||||
|
delegate: Item {
|
||||||
|
width: root.cellW
|
||||||
|
height: 22
|
||||||
|
readonly property int dayNum: index - root.startOffset + 1
|
||||||
|
readonly property bool valid:
|
||||||
|
index >= root.startOffset &&
|
||||||
|
index < root.startOffset + root.daysInMonth
|
||||||
|
readonly property bool isToday:
|
||||||
|
valid &&
|
||||||
|
root.viewYear === root.todayYear &&
|
||||||
|
root.viewMonth === root.todayMonth &&
|
||||||
|
dayNum === root.todayDay
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
|
radius: 3
|
||||||
|
color: isToday ? Theme.accent : "transparent"
|
||||||
|
visible: isToday
|
||||||
|
}
|
||||||
|
Text {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
text: parent.valid ? String(parent.dayNum) : ""
|
||||||
|
color: parent.isToday ? Theme.text : Theme.textDim
|
||||||
|
font.pixelSize: 11
|
||||||
|
font.bold: parent.isToday
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,10 +1,12 @@
|
|||||||
import Quickshell
|
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import "../components"
|
import "../components"
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: root
|
id: root
|
||||||
implicitWidth: timeLabel.implicitWidth + 10
|
|
||||||
|
signal clicked
|
||||||
|
|
||||||
|
implicitWidth: timeLabel.implicitWidth + 16
|
||||||
implicitHeight: 24
|
implicitHeight: 24
|
||||||
|
|
||||||
property var now: new Date()
|
property var now: new Date()
|
||||||
@ -19,10 +21,13 @@ Item {
|
|||||||
readonly property string display: {
|
readonly property string display: {
|
||||||
const d = now
|
const d = now
|
||||||
const days = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]
|
const days = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]
|
||||||
|
const dd = String(d.getDate()).padStart(2, "0")
|
||||||
|
const mm = String(d.getMonth() + 1).padStart(2, "0")
|
||||||
|
const yyyy = d.getFullYear()
|
||||||
const h = String(d.getHours()).padStart(2, "0")
|
const h = String(d.getHours()).padStart(2, "0")
|
||||||
const m = String(d.getMinutes()).padStart(2, "0")
|
const m = String(d.getMinutes()).padStart(2, "0")
|
||||||
const s = String(d.getSeconds()).padStart(2, "0")
|
const s = String(d.getSeconds()).padStart(2, "0")
|
||||||
return days[d.getDay()] + " " + h + ":" + m + ":" + s
|
return days[d.getDay()] + " " + dd + "." + mm + "." + yyyy + " " + h + ":" + m + ":" + s
|
||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
@ -37,160 +42,6 @@ Item {
|
|||||||
MouseArea {
|
MouseArea {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
cursorShape: Qt.PointingHandCursor
|
cursorShape: Qt.PointingHandCursor
|
||||||
onClicked: calPopup.visible = !calPopup.visible
|
onClicked: root.clicked()
|
||||||
}
|
|
||||||
|
|
||||||
// --------------- Calendar popup ---------------
|
|
||||||
PopupWindow {
|
|
||||||
id: calPopup
|
|
||||||
visible: false
|
|
||||||
anchor.item: root
|
|
||||||
anchor.edges: Edges.Bottom
|
|
||||||
anchor.gravity: Edges.Bottom
|
|
||||||
|
|
||||||
// calendar state
|
|
||||||
property int viewYear: root.now.getFullYear()
|
|
||||||
property int viewMonth: root.now.getMonth() // 0-based
|
|
||||||
|
|
||||||
readonly property var monthNames: [
|
|
||||||
"January","February","March","April","May","June",
|
|
||||||
"July","August","September","October","November","December"
|
|
||||||
]
|
|
||||||
readonly property int daysInMonth: new Date(viewYear, viewMonth + 1, 0).getDate()
|
|
||||||
// first weekday of month: Mon=0 … Sun=6
|
|
||||||
readonly property int startOffset: (new Date(viewYear, viewMonth, 1).getDay() + 6) % 7
|
|
||||||
readonly property int totalCells: Math.ceil((startOffset + daysInMonth) / 7) * 7
|
|
||||||
|
|
||||||
readonly property int todayYear: root.now.getFullYear()
|
|
||||||
readonly property int todayMonth: root.now.getMonth()
|
|
||||||
readonly property int todayDay: root.now.getDate()
|
|
||||||
|
|
||||||
implicitWidth: calBg.implicitWidth
|
|
||||||
implicitHeight: calBg.implicitHeight
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
id: calBg
|
|
||||||
anchors.fill: parent
|
|
||||||
color: Theme.bg
|
|
||||||
border.color: Theme.border
|
|
||||||
border.width: Theme.borderWidth
|
|
||||||
radius: Theme.radius
|
|
||||||
implicitWidth: calLayout.implicitWidth + 24
|
|
||||||
implicitHeight: calLayout.implicitHeight + 24
|
|
||||||
|
|
||||||
Column {
|
|
||||||
id: calLayout
|
|
||||||
anchors { fill: parent; margins: 12 }
|
|
||||||
spacing: 6
|
|
||||||
|
|
||||||
// Month navigation
|
|
||||||
Row {
|
|
||||||
width: parent.width
|
|
||||||
spacing: 0
|
|
||||||
|
|
||||||
Text {
|
|
||||||
text: "‹"
|
|
||||||
color: Theme.text
|
|
||||||
font.pixelSize: 16
|
|
||||||
width: 20
|
|
||||||
horizontalAlignment: Text.AlignHCenter
|
|
||||||
MouseArea {
|
|
||||||
anchors.fill: parent
|
|
||||||
cursorShape: Qt.PointingHandCursor
|
|
||||||
onClicked: {
|
|
||||||
if (calPopup.viewMonth === 0) {
|
|
||||||
calPopup.viewMonth = 11
|
|
||||||
calPopup.viewYear--
|
|
||||||
} else {
|
|
||||||
calPopup.viewMonth--
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Text {
|
|
||||||
text: calPopup.monthNames[calPopup.viewMonth] + " " + calPopup.viewYear
|
|
||||||
color: Theme.text
|
|
||||||
font.pixelSize: 13
|
|
||||||
font.bold: true
|
|
||||||
// fill remaining space between arrows
|
|
||||||
width: parent.width - 40
|
|
||||||
horizontalAlignment: Text.AlignHCenter
|
|
||||||
}
|
|
||||||
|
|
||||||
Text {
|
|
||||||
text: "›"
|
|
||||||
color: Theme.text
|
|
||||||
font.pixelSize: 16
|
|
||||||
width: 20
|
|
||||||
horizontalAlignment: Text.AlignHCenter
|
|
||||||
MouseArea {
|
|
||||||
anchors.fill: parent
|
|
||||||
cursorShape: Qt.PointingHandCursor
|
|
||||||
onClicked: {
|
|
||||||
if (calPopup.viewMonth === 11) {
|
|
||||||
calPopup.viewMonth = 0
|
|
||||||
calPopup.viewYear++
|
|
||||||
} else {
|
|
||||||
calPopup.viewMonth++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Weekday headers
|
|
||||||
Row {
|
|
||||||
spacing: 2
|
|
||||||
Repeater {
|
|
||||||
model: ["Mo","Tu","We","Th","Fr","Sa","Su"]
|
|
||||||
Text {
|
|
||||||
text: modelData
|
|
||||||
color: Theme.textDim
|
|
||||||
font.pixelSize: 10
|
|
||||||
width: 28
|
|
||||||
horizontalAlignment: Text.AlignHCenter
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Day grid
|
|
||||||
Grid {
|
|
||||||
columns: 7
|
|
||||||
spacing: 2
|
|
||||||
Repeater {
|
|
||||||
model: calPopup.totalCells
|
|
||||||
delegate: Item {
|
|
||||||
width: 28
|
|
||||||
height: 22
|
|
||||||
readonly property int dayNum: index - calPopup.startOffset + 1
|
|
||||||
readonly property bool valid:
|
|
||||||
index >= calPopup.startOffset &&
|
|
||||||
index < calPopup.startOffset + calPopup.daysInMonth
|
|
||||||
readonly property bool isToday:
|
|
||||||
valid &&
|
|
||||||
calPopup.viewYear === calPopup.todayYear &&
|
|
||||||
calPopup.viewMonth === calPopup.todayMonth &&
|
|
||||||
dayNum === calPopup.todayDay
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
anchors.fill: parent
|
|
||||||
radius: 3
|
|
||||||
color: isToday ? Theme.accent : "transparent"
|
|
||||||
visible: isToday
|
|
||||||
}
|
|
||||||
|
|
||||||
Text {
|
|
||||||
anchors.centerIn: parent
|
|
||||||
text: parent.valid ? String(parent.dayNum) : ""
|
|
||||||
color: parent.isToday ? Theme.text : Theme.textDim
|
|
||||||
font.pixelSize: 11
|
|
||||||
font.bold: parent.isToday
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,3 @@
|
|||||||
import Quickshell
|
|
||||||
import Quickshell.Services.Mpris
|
import Quickshell.Services.Mpris
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import "../components"
|
import "../components"
|
||||||
|
|||||||
@ -1,32 +1,22 @@
|
|||||||
import Quickshell
|
|
||||||
import Quickshell.Services.Mpris
|
import Quickshell.Services.Mpris
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
import "../components"
|
import "../components"
|
||||||
|
|
||||||
PopupWindow {
|
// Plain Item – lives inside the expanding center section border in Bar.qml.
|
||||||
|
Item {
|
||||||
id: root
|
id: root
|
||||||
required property var player
|
required property var player
|
||||||
|
|
||||||
implicitWidth: 280
|
implicitWidth: 280
|
||||||
implicitHeight: bg.implicitHeight
|
implicitHeight: layout.implicitHeight + 28
|
||||||
|
|
||||||
// Tickle positionChanged every frame while playing so the player.position
|
// Keep the progress binding live while playing, pause while seeking.
|
||||||
// binding re-evaluates. Paused while the user is dragging the seek bar.
|
|
||||||
FrameAnimation {
|
FrameAnimation {
|
||||||
running: (root.player?.isPlaying ?? false) && !progressArea.pressed
|
running: (root.player?.isPlaying ?? false) && !progressArea.pressed
|
||||||
onTriggered: root.player.positionChanged()
|
onTriggered: root.player.positionChanged()
|
||||||
}
|
}
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
id: bg
|
|
||||||
anchors.fill: parent
|
|
||||||
color: Theme.bg
|
|
||||||
border.color: Theme.border
|
|
||||||
border.width: Theme.borderWidth
|
|
||||||
radius: Theme.radius
|
|
||||||
implicitHeight: layout.implicitHeight + 28
|
|
||||||
|
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
id: layout
|
id: layout
|
||||||
anchors { fill: parent; margins: 14 }
|
anchors { fill: parent; margins: 14 }
|
||||||
@ -57,9 +47,8 @@ PopupWindow {
|
|||||||
visible: root.player?.positionSupported && root.player?.lengthSupported
|
visible: root.player?.positionSupported && root.player?.lengthSupported
|
||||||
&& (root.player?.length ?? 0) > 0
|
&& (root.player?.length ?? 0) > 0
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
height: 12 // visual track is centred inside; extra height = easier to hit
|
height: 12
|
||||||
|
|
||||||
// Track
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
width: parent.width
|
width: parent.width
|
||||||
@ -67,7 +56,6 @@ PopupWindow {
|
|||||||
radius: 2
|
radius: 2
|
||||||
color: Theme.progressTrack
|
color: Theme.progressTrack
|
||||||
|
|
||||||
// Filled portion
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
width: root.player?.length > 0
|
width: root.player?.length > 0
|
||||||
? parent.width * (root.player.position / root.player.length)
|
? parent.width * (root.player.position / root.player.length)
|
||||||
@ -130,9 +118,7 @@ PopupWindow {
|
|||||||
Item { Layout.fillWidth: true }
|
Item { Layout.fillWidth: true }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Inline helper — a button that highlights on hover
|
|
||||||
component ControlButton: Rectangle {
|
component ControlButton: Rectangle {
|
||||||
id: btn
|
id: btn
|
||||||
required property string icon
|
required property string icon
|
||||||
@ -144,7 +130,6 @@ PopupWindow {
|
|||||||
implicitHeight: label.implicitHeight + 10
|
implicitHeight: label.implicitHeight + 10
|
||||||
radius: Theme.radius
|
radius: Theme.radius
|
||||||
color: btnArea.containsMouse ? Qt.rgba(1, 1, 1, 0.08) : 'transparent'
|
color: btnArea.containsMouse ? Qt.rgba(1, 1, 1, 0.08) : 'transparent'
|
||||||
|
|
||||||
Behavior on color { ColorAnimation { duration: 80 } }
|
Behavior on color { ColorAnimation { duration: 80 } }
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
|||||||
162
roles/quickshell/files/bar/PopoutWindow.qml
Normal file
162
roles/quickshell/files/bar/PopoutWindow.qml
Normal file
@ -0,0 +1,162 @@
|
|||||||
|
import Quickshell
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Shapes
|
||||||
|
import "../components"
|
||||||
|
|
||||||
|
PopupWindow {
|
||||||
|
id: self
|
||||||
|
|
||||||
|
property string popupName: ""
|
||||||
|
property string activePopup: ""
|
||||||
|
|
||||||
|
visible: false
|
||||||
|
color: "transparent"
|
||||||
|
|
||||||
|
default property alias content: contentSlot.data
|
||||||
|
|
||||||
|
readonly property int bw: Theme.borderWidth
|
||||||
|
readonly property real r: Theme.radius
|
||||||
|
|
||||||
|
readonly property bool _open: activePopup === popupName
|
||||||
|
on_OpenChanged: {
|
||||||
|
if (_open) {
|
||||||
|
hideTimer.stop();
|
||||||
|
self.visible = true;
|
||||||
|
fade.opacity = 1.0;
|
||||||
|
} else {
|
||||||
|
fade.opacity = 0.0;
|
||||||
|
hideTimer.start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Timer {
|
||||||
|
id: hideTimer
|
||||||
|
interval: 200
|
||||||
|
onTriggered: self.visible = false
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: fade
|
||||||
|
anchors.fill: parent
|
||||||
|
opacity: 0.0
|
||||||
|
Behavior on opacity {
|
||||||
|
NumberAnimation {
|
||||||
|
duration: 180
|
||||||
|
easing.type: Easing.InOutCubic
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Background + border in one Shape so fill matches stroke exactly
|
||||||
|
Shape {
|
||||||
|
id: pbs
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
ShapePath {
|
||||||
|
strokeWidth: self.bw
|
||||||
|
strokeColor: Theme.border
|
||||||
|
fillColor: Theme.bg
|
||||||
|
|
||||||
|
// Start flush at top-left, hidden under bar
|
||||||
|
startX: 0
|
||||||
|
startY: self.r
|
||||||
|
|
||||||
|
// Left side down to bottom-left corner
|
||||||
|
PathLine {
|
||||||
|
x: 0
|
||||||
|
y: pbs.height - self.r
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bottom-left corner — Counterclockwise for outward curve
|
||||||
|
PathArc {
|
||||||
|
x: self.r
|
||||||
|
y: pbs.height
|
||||||
|
radiusX: self.r
|
||||||
|
radiusY: self.r
|
||||||
|
direction: PathArc.Counterclockwise
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bottom edge
|
||||||
|
PathLine {
|
||||||
|
x: pbs.width - self.r
|
||||||
|
y: pbs.height
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bottom-right corner — Counterclockwise for outward curve
|
||||||
|
PathArc {
|
||||||
|
x: pbs.width
|
||||||
|
y: pbs.height - self.r
|
||||||
|
radiusX: self.r
|
||||||
|
radiusY: self.r
|
||||||
|
direction: PathArc.Counterclockwise
|
||||||
|
}
|
||||||
|
|
||||||
|
// Right side up, flush to top, hidden under bar
|
||||||
|
PathLine {
|
||||||
|
x: pbs.width
|
||||||
|
y: self.r
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// // Top-left concave corner
|
||||||
|
// Shape {
|
||||||
|
// x: 0
|
||||||
|
// y: 0
|
||||||
|
// width: self.r
|
||||||
|
// height: self.r
|
||||||
|
// ShapePath {
|
||||||
|
// fillColor: Theme.bg
|
||||||
|
// strokeColor: "transparent"
|
||||||
|
// startX: 0
|
||||||
|
// startY: 0
|
||||||
|
// PathLine {
|
||||||
|
// x: self.r
|
||||||
|
// y: 0
|
||||||
|
// }
|
||||||
|
// PathArc {
|
||||||
|
// x: 0
|
||||||
|
// y: self.r
|
||||||
|
// radiusX: self.r
|
||||||
|
// radiusY: self.r
|
||||||
|
// direction: PathArc.Clockwise
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // Top-right concave corner
|
||||||
|
// Shape {
|
||||||
|
// x: parent.width - self.r
|
||||||
|
// y: 0
|
||||||
|
// width: self.r
|
||||||
|
// height: self.r
|
||||||
|
// ShapePath {
|
||||||
|
// fillColor: Theme.bg
|
||||||
|
// strokeColor: "transparent"
|
||||||
|
// startX: self.r
|
||||||
|
// startY: 0
|
||||||
|
// PathLine {
|
||||||
|
// x: 0
|
||||||
|
// y: 0
|
||||||
|
// }
|
||||||
|
// PathArc {
|
||||||
|
// x: self.r
|
||||||
|
// y: self.r
|
||||||
|
// radiusX: self.r
|
||||||
|
// radiusY: self.r
|
||||||
|
// direction: PathArc.Counterclockwise
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: contentSlot
|
||||||
|
anchors {
|
||||||
|
top: parent.top
|
||||||
|
topMargin: self.r + self.bw
|
||||||
|
left: parent.left
|
||||||
|
leftMargin: self.bw
|
||||||
|
right: parent.right
|
||||||
|
rightMargin: self.bw
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,4 +1,3 @@
|
|||||||
import Quickshell
|
|
||||||
import Quickshell.Services.Pipewire
|
import Quickshell.Services.Pipewire
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
@ -9,13 +8,12 @@ Item {
|
|||||||
implicitWidth: chip.implicitWidth + 10
|
implicitWidth: chip.implicitWidth + 10
|
||||||
implicitHeight: 24
|
implicitHeight: 24
|
||||||
|
|
||||||
// Track all PipeWire nodes so their properties are populated.
|
signal clickedLeft
|
||||||
// Without this, nodes in Pipewire.nodes are "unbound" and have null audio/type.
|
|
||||||
PwObjectTracker {
|
PwObjectTracker {
|
||||||
objects: Pipewire.nodes.values
|
objects: Pipewire.nodes.values
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── helpers ────────────────────────────────────────────────────────
|
|
||||||
function safeVolume(node) {
|
function safeVolume(node) {
|
||||||
if (!node || !node.ready || !node.audio) return 0
|
if (!node || !node.ready || !node.audio) return 0
|
||||||
const v = node.audio.volume
|
const v = node.audio.volume
|
||||||
@ -26,13 +24,12 @@ Item {
|
|||||||
node.audio.volume = Math.max(0, Math.min(1, v))
|
node.audio.volume = Math.max(0, Math.min(1, v))
|
||||||
}
|
}
|
||||||
function volIcon(vol, muted) {
|
function volIcon(vol, muted) {
|
||||||
if (muted) return "\uf6a9" // fa-volume-mute
|
if (muted) return "\uf6a9"
|
||||||
if (vol > 0.6) return "\uf028" // fa-volume-up
|
if (vol > 0.6) return "\uf028"
|
||||||
if (vol > 0.2) return "\uf027" // fa-volume-down
|
if (vol > 0.2) return "\uf027"
|
||||||
return "\uf026" // fa-volume-off
|
return "\uf026"
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── bar chip (default sink) ─────────────────────────────────────────
|
|
||||||
readonly property var defaultSink: Pipewire.defaultAudioSink
|
readonly property var defaultSink: Pipewire.defaultAudioSink
|
||||||
readonly property real defaultVolume: safeVolume(defaultSink)
|
readonly property real defaultVolume: safeVolume(defaultSink)
|
||||||
readonly property bool defaultMuted: defaultSink?.audio?.muted ?? false
|
readonly property bool defaultMuted: defaultSink?.audio?.muted ?? false
|
||||||
@ -66,7 +63,7 @@ Item {
|
|||||||
if (root.defaultSink?.ready && root.defaultSink?.audio)
|
if (root.defaultSink?.ready && root.defaultSink?.audio)
|
||||||
root.defaultSink.audio.muted = !root.defaultSink.audio.muted
|
root.defaultSink.audio.muted = !root.defaultSink.audio.muted
|
||||||
} else {
|
} else {
|
||||||
mixerPopup.visible = !mixerPopup.visible
|
root.clickedLeft()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
onWheel: wheel => {
|
onWheel: wheel => {
|
||||||
@ -74,149 +71,4 @@ Item {
|
|||||||
root.setVolume(root.defaultSink, root.defaultVolume + wheel.angleDelta.y / 120 * 0.05)
|
root.setVolume(root.defaultSink, root.defaultVolume + wheel.angleDelta.y / 120 * 0.05)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── mixer popup ─────────────────────────────────────────────────────
|
|
||||||
PopupWindow {
|
|
||||||
id: mixerPopup
|
|
||||||
visible: false
|
|
||||||
anchor.item: root
|
|
||||||
anchor.edges: Edges.Bottom
|
|
||||||
anchor.gravity: Edges.Bottom
|
|
||||||
|
|
||||||
implicitWidth: mixerBg.implicitWidth
|
|
||||||
implicitHeight: mixerBg.implicitHeight
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
id: mixerBg
|
|
||||||
anchors.fill: parent
|
|
||||||
color: Theme.bg
|
|
||||||
border.color: Theme.border
|
|
||||||
border.width: Theme.borderWidth
|
|
||||||
radius: Theme.radius
|
|
||||||
implicitWidth: 300
|
|
||||||
implicitHeight: mixerCol.implicitHeight + 24
|
|
||||||
|
|
||||||
ColumnLayout {
|
|
||||||
id: mixerCol
|
|
||||||
anchors { fill: parent; margins: 12 }
|
|
||||||
spacing: 4
|
|
||||||
|
|
||||||
// ── Output devices ──────────────────────────────────────
|
|
||||||
Text {
|
|
||||||
text: "Output Devices"
|
|
||||||
color: Theme.textDim
|
|
||||||
font.pixelSize: 10
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.bottomMargin: 2
|
|
||||||
}
|
|
||||||
|
|
||||||
Repeater {
|
|
||||||
model: Pipewire.nodes
|
|
||||||
delegate: NodeRow {
|
|
||||||
required property var modelData
|
|
||||||
Layout.fillWidth: true
|
|
||||||
node: modelData
|
|
||||||
visible: modelData.isSink && !modelData.isStream && modelData.ready
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ── Application streams ────────────────────────────────
|
|
||||||
Text {
|
|
||||||
text: "Applications"
|
|
||||||
color: Theme.textDim
|
|
||||||
font.pixelSize: 10
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.topMargin: 6
|
|
||||||
Layout.bottomMargin: 2
|
|
||||||
}
|
|
||||||
|
|
||||||
Repeater {
|
|
||||||
model: Pipewire.nodes
|
|
||||||
delegate: NodeRow {
|
|
||||||
required property var modelData
|
|
||||||
Layout.fillWidth: true
|
|
||||||
node: modelData
|
|
||||||
// exclude monitor sources; include only audio output streams
|
|
||||||
visible: modelData.isStream && !modelData.isSink && modelData.ready
|
|
||||||
&& !(modelData.description ?? "").toLowerCase().includes("monitor")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ── per-node row component ──────────────────────────────────────────
|
|
||||||
component NodeRow: RowLayout {
|
|
||||||
id: row
|
|
||||||
required property var node
|
|
||||||
spacing: 8
|
|
||||||
implicitHeight: 28
|
|
||||||
|
|
||||||
// mute toggle
|
|
||||||
Text {
|
|
||||||
id: nodeIcon
|
|
||||||
text: root.volIcon(root.safeVolume(row.node), row.node.audio?.muted ?? false)
|
|
||||||
font.family: "JetBrainsMono Nerd Font Mono"
|
|
||||||
font.pixelSize: 13
|
|
||||||
color: (row.node.audio?.muted ?? false) ? Theme.textDim : Theme.text
|
|
||||||
MouseArea {
|
|
||||||
anchors.fill: parent
|
|
||||||
cursorShape: Qt.PointingHandCursor
|
|
||||||
onClicked: {
|
|
||||||
if (row.node.ready && row.node.audio)
|
|
||||||
row.node.audio.muted = !row.node.audio.muted
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// name
|
|
||||||
Text {
|
|
||||||
text: row.node.description || row.node.nickname || row.node.name || "?"
|
|
||||||
font.pixelSize: 11
|
|
||||||
color: Theme.textDim
|
|
||||||
Layout.preferredWidth: 90
|
|
||||||
elide: Text.ElideRight
|
|
||||||
}
|
|
||||||
|
|
||||||
// horizontal slider
|
|
||||||
Item {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
implicitHeight: 16
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
width: parent.width
|
|
||||||
height: 3
|
|
||||||
radius: 2
|
|
||||||
color: Theme.progressTrack
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
width: parent.width * Math.min(1, root.safeVolume(row.node))
|
|
||||||
height: parent.height
|
|
||||||
radius: parent.radius
|
|
||||||
color: Theme.accent
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
MouseArea {
|
|
||||||
anchors { fill: parent; topMargin: -4; bottomMargin: -4 }
|
|
||||||
hoverEnabled: true
|
|
||||||
cursorShape: Qt.PointingHandCursor
|
|
||||||
function seek(mx) {
|
|
||||||
root.setVolume(row.node, mx / width)
|
|
||||||
}
|
|
||||||
onClicked: seek(mouseX)
|
|
||||||
onPositionChanged: if (pressed) seek(mouseX)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// percentage
|
|
||||||
Text {
|
|
||||||
text: Math.round(root.safeVolume(row.node) * 100) + "%"
|
|
||||||
font.pixelSize: 10
|
|
||||||
color: Theme.textDim
|
|
||||||
Layout.preferredWidth: 30
|
|
||||||
horizontalAlignment: Text.AlignRight
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
143
roles/quickshell/files/bar/VolumeMixerContent.qml
Normal file
143
roles/quickshell/files/bar/VolumeMixerContent.qml
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
import Quickshell.Services.Pipewire
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import "../components"
|
||||||
|
|
||||||
|
// Volume mixer – a plain Item so it can live inside an expanding section border.
|
||||||
|
Item {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
implicitWidth: 300
|
||||||
|
implicitHeight: mixerCol.implicitHeight + 24
|
||||||
|
|
||||||
|
PwObjectTracker {
|
||||||
|
objects: Pipewire.nodes.values
|
||||||
|
}
|
||||||
|
|
||||||
|
function safeVolume(node) {
|
||||||
|
if (!node || !node.ready || !node.audio) return 0
|
||||||
|
const v = node.audio.volume
|
||||||
|
return (v !== undefined && !isNaN(v)) ? v : 0
|
||||||
|
}
|
||||||
|
function setVolume(node, v) {
|
||||||
|
if (!node || !node.ready || !node.audio) return
|
||||||
|
node.audio.volume = Math.max(0, Math.min(1, v))
|
||||||
|
}
|
||||||
|
function volIcon(vol, muted) {
|
||||||
|
if (muted) return "\uf6a9"
|
||||||
|
if (vol > 0.6) return "\uf028"
|
||||||
|
if (vol > 0.2) return "\uf027"
|
||||||
|
return "\uf026"
|
||||||
|
}
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
id: mixerCol
|
||||||
|
anchors { fill: parent; margins: 12 }
|
||||||
|
spacing: 4
|
||||||
|
|
||||||
|
Text {
|
||||||
|
text: "Output Devices"
|
||||||
|
color: Theme.textDim
|
||||||
|
font.pixelSize: 10
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.bottomMargin: 2
|
||||||
|
}
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
model: Pipewire.nodes
|
||||||
|
delegate: NodeRow {
|
||||||
|
required property var modelData
|
||||||
|
Layout.fillWidth: true
|
||||||
|
node: modelData
|
||||||
|
visible: modelData.isSink && !modelData.isStream && modelData.ready
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
text: "Applications"
|
||||||
|
color: Theme.textDim
|
||||||
|
font.pixelSize: 10
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.topMargin: 6
|
||||||
|
Layout.bottomMargin: 2
|
||||||
|
}
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
model: Pipewire.nodes
|
||||||
|
delegate: NodeRow {
|
||||||
|
required property var modelData
|
||||||
|
Layout.fillWidth: true
|
||||||
|
node: modelData
|
||||||
|
visible: modelData.isStream && !modelData.isSink && modelData.ready
|
||||||
|
&& !(modelData.description ?? "").toLowerCase().includes("monitor")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
component NodeRow: RowLayout {
|
||||||
|
id: row
|
||||||
|
required property var node
|
||||||
|
spacing: 8
|
||||||
|
implicitHeight: 28
|
||||||
|
|
||||||
|
Text {
|
||||||
|
text: root.volIcon(root.safeVolume(row.node), row.node.audio?.muted ?? false)
|
||||||
|
font.family: "JetBrainsMono Nerd Font Mono"
|
||||||
|
font.pixelSize: 13
|
||||||
|
color: (row.node.audio?.muted ?? false) ? Theme.textDim : Theme.text
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
onClicked: {
|
||||||
|
if (row.node.ready && row.node.audio)
|
||||||
|
row.node.audio.muted = !row.node.audio.muted
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
text: row.node.description || row.node.nickname || row.node.name || "?"
|
||||||
|
font.pixelSize: 11
|
||||||
|
color: Theme.textDim
|
||||||
|
Layout.preferredWidth: 90
|
||||||
|
elide: Text.ElideRight
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
implicitHeight: 16
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
width: parent.width
|
||||||
|
height: 3
|
||||||
|
radius: 2
|
||||||
|
color: Theme.progressTrack
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
width: parent.width * Math.min(1, root.safeVolume(row.node))
|
||||||
|
height: parent.height
|
||||||
|
radius: parent.radius
|
||||||
|
color: Theme.accent
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors { fill: parent; topMargin: -4; bottomMargin: -4 }
|
||||||
|
hoverEnabled: true
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
function seek(mx) { root.setVolume(row.node, mx / width) }
|
||||||
|
onClicked: seek(mouseX)
|
||||||
|
onPositionChanged: if (pressed) seek(mouseX)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
text: Math.round(root.safeVolume(row.node) * 100) + "%"
|
||||||
|
font.pixelSize: 10
|
||||||
|
color: Theme.textDim
|
||||||
|
Layout.preferredWidth: 30
|
||||||
|
horizontalAlignment: Text.AlignRight
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,9 +1,12 @@
|
|||||||
Bar 1.0 Bar.qml
|
Bar 1.0 Bar.qml
|
||||||
|
PopoutWindow 1.0 PopoutWindow.qml
|
||||||
|
CalendarContent 1.0 CalendarContent.qml
|
||||||
Clock 1.0 Clock.qml
|
Clock 1.0 Clock.qml
|
||||||
MusicPlayer 1.0 MusicPlayer.qml
|
MusicPlayer 1.0 MusicPlayer.qml
|
||||||
MusicPlayerControls 1.0 MusicPlayerControls.qml
|
MusicPlayerControls 1.0 MusicPlayerControls.qml
|
||||||
NetworkStatus 1.0 NetworkStatus.qml
|
NetworkStatus 1.0 NetworkStatus.qml
|
||||||
SysTray 1.0 SysTray.qml
|
SysTray 1.0 SysTray.qml
|
||||||
VolumeControl 1.0 VolumeControl.qml
|
VolumeControl 1.0 VolumeControl.qml
|
||||||
|
VolumeMixerContent 1.0 VolumeMixerContent.qml
|
||||||
Workspaces 1.0 Workspaces.qml
|
Workspaces 1.0 Workspaces.qml
|
||||||
WorkspaceButton 1.0 WorkspaceButton.qml
|
WorkspaceButton 1.0 WorkspaceButton.qml
|
||||||
|
|||||||
@ -3,7 +3,8 @@ import QtQuick
|
|||||||
|
|
||||||
QtObject {
|
QtObject {
|
||||||
// Core palette
|
// Core palette
|
||||||
readonly property color bg: '#000000'
|
readonly property color bg: '#D9000000' // bar background (semi-transparent)
|
||||||
|
readonly property color bgPopup: '#000000' // popup background (fully opaque)
|
||||||
readonly property color accent: '#9B1A1A'
|
readonly property color accent: '#9B1A1A'
|
||||||
readonly property color border: '#FFFFFF'
|
readonly property color border: '#FFFFFF'
|
||||||
readonly property color text: '#FFFFFF'
|
readonly property color text: '#FFFFFF'
|
||||||
@ -12,7 +13,7 @@ QtObject {
|
|||||||
readonly property color progressTrack: '#333333'
|
readonly property color progressTrack: '#333333'
|
||||||
|
|
||||||
// Shape / sizing
|
// Shape / sizing
|
||||||
readonly property int radius: 4
|
readonly property int radius: 16
|
||||||
readonly property int borderWidth: 2
|
readonly property int borderWidth: 2
|
||||||
readonly property int enclosureMargin: 3
|
readonly property int enclosureMargin: 3
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user