diff --git a/Modules/Audio/AudioDeviceSelector.qml b/Modules/Audio/AudioDeviceSelector.qml index 7cd5de6..109d88d 100644 --- a/Modules/Audio/AudioDeviceSelector.qml +++ b/Modules/Audio/AudioDeviceSelector.qml @@ -1,369 +1,485 @@ import QtQuick import QtQuick.Controls import QtQuick.Layouts +import Quickshell import Quickshell.Services.Pipewire import qs.Services import qs.Widgets -NPanel { - id: ioSelector - - // property int tabIndex: 0 - // property Item anchorItem: null - - // signal panelClosed() - - // function sinkNodes() { - // let nodes = Pipewire.nodes && Pipewire.nodes.values ? Pipewire.nodes.values.filter(function(n) { - // return n.isSink && n.audio && n.isStream === false; - // }) : []; - // if (Pipewire.defaultAudioSink) - // nodes = nodes.slice().sort(function(a, b) { - // if (a.id === Pipewire.defaultAudioSink.id) - // return -1; - - // if (b.id === Pipewire.defaultAudioSink.id) - // return 1; - - // return 0; - // }); - - // return nodes; - // } - - // function sourceNodes() { - // let nodes = Pipewire.nodes && Pipewire.nodes.values ? Pipewire.nodes.values.filter(function(n) { - // return !n.isSink && n.audio && n.isStream === false; - // }) : []; - // if (Pipewire.defaultAudioSource) - // nodes = nodes.slice().sort(function(a, b) { - // if (a.id === Pipewire.defaultAudioSource.id) - // return -1; - - // if (b.id === Pipewire.defaultAudioSource.id) - // return 1; - - // return 0; - // }); - - // return nodes; - // } - - // Component.onCompleted: { - // if (Pipewire.nodes && Pipewire.nodes.values) { - // for (var i = 0; i < Pipewire.nodes.values.length; ++i) { - // var n = Pipewire.nodes.values[i]; - // } - // } - // } - // Component.onDestruction: { - // } - // onVisibleChanged: { - // if (!visible) - // panelClosed(); - - // } - - // // Bind all Pipewire nodes so their properties are valid - // PwObjectTracker { - // id: nodeTracker - - // objects: Pipewire.nodes - // } - - // Rectangle { - // color: Theme.backgroundPrimary - // radius: 20 - // width: 340 - // height: 340 - // anchors.top: parent.top - // anchors.right: parent.right - // anchors.topMargin: 4 - // anchors.rightMargin: 4 - - // // Prevent closing when clicking in the panel bg - // MouseArea { - // anchors.fill: parent - // } - - // ColumnLayout { - // anchors.fill: parent - // anchors.margins: 16 - // spacing: 10 - - // // Tabs centered inside the window - // RowLayout { - // Layout.fillWidth: true - // Layout.alignment: Qt.AlignHCenter - // spacing: 0 - - // Tabs { - // id: ioTabs - - // tabsModel: [{ - // "label": "Output", - // "icon": "volume_up" - // }, { - // "label": "Input", - // "icon": "mic" - // }] - // currentIndex: tabIndex - // onTabChanged: { - // tabIndex = currentIndex; - // } - // } - - // } - - // // Add vertical space between tabs and entries - // Item { - // height: 36 - // Layout.fillWidth: true - // } - - // // Output Devices - // Flickable { - // id: sinkList - - // visible: tabIndex === 0 - // contentHeight: sinkColumn.height - // clip: true - // interactive: contentHeight > height - // width: parent.width - // height: 220 - - // ColumnLayout { - // id: sinkColumn - - // width: sinkList.width - // spacing: 6 - - // Repeater { - // model: ioSelector.sinkNodes() - - // Rectangle { - // width: parent.width - // height: 36 - // color: "transparent" - // radius: 6 - - // RowLayout { - // anchors.fill: parent - // anchors.margins: 6 - // spacing: 8 - - // Text { - // text: "volume_up" - // font.family: "Material Symbols Outlined" - // font.pixelSize: 16 * Theme.scale(screen) - // color: (Pipewire.defaultAudioSink && Pipewire.defaultAudioSink.id === modelData.id) ? Theme.accentPrimary : Theme.textPrimary - // Layout.alignment: Qt.AlignVCenter - // } - - // ColumnLayout { - // Layout.fillWidth: true - // spacing: 1 - // Layout.maximumWidth: sinkList.width - 120 // Reserve space for the Set button - - // Text { - // text: modelData.nickname || modelData.description || modelData.name - // font.bold: true - // font.pixelSize: 12 * Theme.scale(screen) - // color: (Pipewire.defaultAudioSink && Pipewire.defaultAudioSink.id === modelData.id) ? Theme.accentPrimary : Theme.textPrimary - // elide: Text.ElideRight - // maximumLineCount: 1 - // Layout.fillWidth: true - // } - - // Text { - // text: modelData.description !== modelData.nickname ? modelData.description : "" - // font.pixelSize: 10 * Theme.scale(screen) - // color: Theme.textSecondary - // elide: Text.ElideRight - // maximumLineCount: 1 - // Layout.fillWidth: true - // } - - // } - - // Rectangle { - // visible: Pipewire.preferredDefaultAudioSink !== modelData - // width: 60 - // height: 20 - // radius: 4 - // color: Theme.accentPrimary - // border.color: Theme.accentPrimary - // border.width: 1 - // Layout.alignment: Qt.AlignVCenter - - // Text { - // anchors.centerIn: parent - // text: "Set" - // color: Theme.onAccent - // font.pixelSize: 10 * Theme.scale(screen) - // font.bold: true - // } - - // MouseArea { - // anchors.fill: parent - // cursorShape: Qt.PointingHandCursor - // onClicked: Pipewire.preferredDefaultAudioSink = modelData - // } - - // } - - // Text { - // text: "(Current)" - // visible: Pipewire.defaultAudioSink && Pipewire.defaultAudioSink.id === modelData.id - // color: Theme.accentPrimary - // font.pixelSize: 10 * Theme.scale(screen) - // Layout.alignment: Qt.AlignVCenter - // } - - // } - - // } - - // } - - // } - - // ScrollBar.vertical: ScrollBar { - // } - - // } - - // // Input Devices - // Flickable { - // id: sourceList - - // visible: tabIndex === 1 - // contentHeight: sourceColumn.height - // clip: true - // interactive: contentHeight > height - // width: parent.width - // height: 220 - - // ColumnLayout { - // id: sourceColumn - - // width: sourceList.width - // spacing: 6 - - // Repeater { - // model: ioSelector.sourceNodes() - - // Rectangle { - // width: parent.width - // height: 36 - // color: "transparent" - // radius: 6 - - // RowLayout { - // anchors.fill: parent - // anchors.margins: 6 - // spacing: 8 - - // Text { - // text: "mic" - // font.family: "Material Symbols Outlined" - // font.pixelSize: 16 * Theme.scale(screen) - // color: (Pipewire.defaultAudioSource && Pipewire.defaultAudioSource.id === modelData.id) ? Theme.accentPrimary : Theme.textPrimary - // Layout.alignment: Qt.AlignVCenter - // } - - // ColumnLayout { - // Layout.fillWidth: true - // spacing: 1 - // Layout.maximumWidth: sourceList.width - 120 // Reserve space for the Set button - - // Text { - // text: modelData.nickname || modelData.description || modelData.name - // font.bold: true - // font.pixelSize: 12 * Theme.scale(screen) - // color: (Pipewire.defaultAudioSource && Pipewire.defaultAudioSource.id === modelData.id) ? Theme.accentPrimary : Theme.textPrimary - // elide: Text.ElideRight - // maximumLineCount: 1 - // Layout.fillWidth: true - // } - - // Text { - // text: modelData.description !== modelData.nickname ? modelData.description : "" - // font.pixelSize: 10 * Theme.scale(screen) - // color: Theme.textSecondary - // elide: Text.ElideRight - // maximumLineCount: 1 - // Layout.fillWidth: true - // } - - // } - - // Rectangle { - // visible: Pipewire.preferredDefaultAudioSource !== modelData - // width: 60 - // height: 20 - // radius: 4 - // color: Theme.accentPrimary - // border.color: Theme.accentPrimary - // border.width: 1 - // Layout.alignment: Qt.AlignVCenter - - // Text { - // anchors.centerIn: parent - // text: "Set" - // color: Theme.onAccent - // font.pixelSize: 10 * Theme.scale(screen) - // font.bold: true - // } - - // MouseArea { - // anchors.fill: parent - // cursorShape: Qt.PointingHandCursor - // onClicked: Pipewire.preferredDefaultAudioSource = modelData - // } - - // } - - // Text { - // text: "(Current)" - // visible: Pipewire.defaultAudioSource && Pipewire.defaultAudioSource.id === modelData.id - // color: Theme.accentPrimary - // font.pixelSize: 10 * Theme.scale(screen) - // Layout.alignment: Qt.AlignVCenter - // } - - // } - - // } - - // } - - // } - - // ScrollBar.vertical: ScrollBar { - // } - - // } - - // } - - // } - - // Connections { - // function onReadyChanged() { - // if (Pipewire.ready && Pipewire.nodes && Pipewire.nodes.values) { - // for (var i = 0; i < Pipewire.nodes.values.length; ++i) { - // var n = Pipewire.nodes.values[i]; - // } - // } - // } - - // function onDefaultAudioSinkChanged() { - // } - - // function onDefaultAudioSourceChanged() { - // } - - // target: Pipewire - // } +NLoader { + id: root + + content: Component { + NPanel { + id: demoPanel + + readonly property real scaling: Scaling.scale(screen) + + // Ensure panel shows itself once created + Component.onCompleted: show() + + Rectangle { + color: Colors.backgroundPrimary + radius: Style.radiusMedium * scaling + border.color: Colors.backgroundTertiary + border.width: Math.min(1, Style.borderMedium * scaling) + width: 500 * scaling + height: 400 + anchors.centerIn: parent + + // Prevent closing when clicking in the panel bg + MouseArea { + anchors.fill: parent + } + + ColumnLayout { + anchors.fill: parent + anchors.margins: Style.marginXL * scaling + spacing: Style.marginSmall * scaling + + // NIconButton + ColumnLayout { + spacing: 16 * scaling + NText { + text: "NIconButton" + color: Colors.accentSecondary + } + + NIconButton { + id: myIconButton + icon: "refresh" + } + + NDivider { + Layout.fillWidth: true + } + } + + // NToggle + ColumnLayout { + spacing: Style.marginLarge * scaling + NText { + text: "NToggle" + color: Colors.accentSecondary + } + + NToggle { + label: "Label" + description: "Description" + onToggled: function (value) { + console.log("NToggle: " + value) + } + } + + NDivider { + Layout.fillWidth: true + } + } + + // NSlider + ColumnLayout { + spacing: 16 * scaling + NText { + text: "Scaling" + color: Colors.accentSecondary + } + RowLayout { + spacing: Style.marginSmall * scaling + NText { + text: `${Math.round(Scaling.overrideScale * 100)}%` + Layout.alignment: Qt.AlignVCenter + } + NSlider { + id: scaleSlider + from: 0.6 + to: 1.8 + stepSize: 0.01 + value: Scaling.overrideScale + onMoved: function () { + Scaling.overrideScale = value + } + onPressedChanged: function () { + Scaling.overrideEnabled = true + } + } + NIconButton { + icon: "restart_alt" + sizeMultiplier: 0.7 + onClicked: function () { + Scaling.overrideEnabled = false + Scaling.overrideScale = 1.0 + } + } + } + NDivider { + Layout.fillWidth: true + } + } + } + } + } + } } +// NPanel { +// id: ioSelector + +// property int tabIndex: 0 +// property Item anchorItem: null + +// signal panelClosed() + +// function sinkNodes() { +// let nodes = Pipewire.nodes && Pipewire.nodes.values ? Pipewire.nodes.values.filter(function(n) { +// return n.isSink && n.audio && n.isStream === false; +// }) : []; +// if (Pipewire.defaultAudioSink) +// nodes = nodes.slice().sort(function(a, b) { +// if (a.id === Pipewire.defaultAudioSink.id) +// return -1; + +// if (b.id === Pipewire.defaultAudioSink.id) +// return 1; + +// return 0; +// }); + +// return nodes; +// } + +// function sourceNodes() { +// let nodes = Pipewire.nodes && Pipewire.nodes.values ? Pipewire.nodes.values.filter(function(n) { +// return !n.isSink && n.audio && n.isStream === false; +// }) : []; +// if (Pipewire.defaultAudioSource) +// nodes = nodes.slice().sort(function(a, b) { +// if (a.id === Pipewire.defaultAudioSource.id) +// return -1; + +// if (b.id === Pipewire.defaultAudioSource.id) +// return 1; + +// return 0; +// }); + +// return nodes; +// } + +// Component.onCompleted: { +// if (Pipewire.nodes && Pipewire.nodes.values) { +// for (var i = 0; i < Pipewire.nodes.values.length; ++i) { +// var n = Pipewire.nodes.values[i]; +// } +// } +// } +// Component.onDestruction: { +// } +// onVisibleChanged: { +// if (!visible) +// panelClosed(); + +// } + +// // Bind all Pipewire nodes so their properties are valid +// PwObjectTracker { +// id: nodeTracker + +// objects: Pipewire.nodes +// } + +// Rectangle { +// color: Theme.backgroundPrimary +// radius: 20 +// width: 340 +// height: 340 +// anchors.top: parent.top +// anchors.right: parent.right +// anchors.topMargin: 4 +// anchors.rightMargin: 4 + +// // Prevent closing when clicking in the panel bg +// MouseArea { +// anchors.fill: parent +// } + +// ColumnLayout { +// anchors.fill: parent +// anchors.margins: 16 +// spacing: 10 + +// // Tabs centered inside the window +// RowLayout { +// Layout.fillWidth: true +// Layout.alignment: Qt.AlignHCenter +// spacing: 0 + +// Tabs { +// id: ioTabs + +// tabsModel: [{ +// "label": "Output", +// "icon": "volume_up" +// }, { +// "label": "Input", +// "icon": "mic" +// }] +// currentIndex: tabIndex +// onTabChanged: { +// tabIndex = currentIndex; +// } +// } + +// } + +// // Add vertical space between tabs and entries +// Item { +// height: 36 +// Layout.fillWidth: true +// } + +// // Output Devices +// Flickable { +// id: sinkList + +// visible: tabIndex === 0 +// contentHeight: sinkColumn.height +// clip: true +// interactive: contentHeight > height +// width: parent.width +// height: 220 + +// ColumnLayout { +// id: sinkColumn + +// width: sinkList.width +// spacing: 6 + +// Repeater { +// model: ioSelector.sinkNodes() + +// Rectangle { +// width: parent.width +// height: 36 +// color: "transparent" +// radius: 6 + +// RowLayout { +// anchors.fill: parent +// anchors.margins: 6 +// spacing: 8 + +// Text { +// text: "volume_up" +// font.family: "Material Symbols Outlined" +// font.pixelSize: 16 * Theme.scale(screen) +// color: (Pipewire.defaultAudioSink && Pipewire.defaultAudioSink.id === modelData.id) ? Theme.accentPrimary : Theme.textPrimary +// Layout.alignment: Qt.AlignVCenter +// } + +// ColumnLayout { +// Layout.fillWidth: true +// spacing: 1 +// Layout.maximumWidth: sinkList.width - 120 // Reserve space for the Set button + +// Text { +// text: modelData.nickname || modelData.description || modelData.name +// font.bold: true +// font.pixelSize: 12 * Theme.scale(screen) +// color: (Pipewire.defaultAudioSink && Pipewire.defaultAudioSink.id === modelData.id) ? Theme.accentPrimary : Theme.textPrimary +// elide: Text.ElideRight +// maximumLineCount: 1 +// Layout.fillWidth: true +// } + +// Text { +// text: modelData.description !== modelData.nickname ? modelData.description : "" +// font.pixelSize: 10 * Theme.scale(screen) +// color: Theme.textSecondary +// elide: Text.ElideRight +// maximumLineCount: 1 +// Layout.fillWidth: true +// } + +// } + +// Rectangle { +// visible: Pipewire.preferredDefaultAudioSink !== modelData +// width: 60 +// height: 20 +// radius: 4 +// color: Theme.accentPrimary +// border.color: Theme.accentPrimary +// border.width: 1 +// Layout.alignment: Qt.AlignVCenter + +// Text { +// anchors.centerIn: parent +// text: "Set" +// color: Theme.onAccent +// font.pixelSize: 10 * Theme.scale(screen) +// font.bold: true +// } + +// MouseArea { +// anchors.fill: parent +// cursorShape: Qt.PointingHandCursor +// onClicked: Pipewire.preferredDefaultAudioSink = modelData +// } + +// } + +// Text { +// text: "(Current)" +// visible: Pipewire.defaultAudioSink && Pipewire.defaultAudioSink.id === modelData.id +// color: Theme.accentPrimary +// font.pixelSize: 10 * Theme.scale(screen) +// Layout.alignment: Qt.AlignVCenter +// } + +// } + +// } + +// } + +// } + +// ScrollBar.vertical: ScrollBar { +// } + +// } + +// // Input Devices +// Flickable { +// id: sourceList + +// visible: tabIndex === 1 +// contentHeight: sourceColumn.height +// clip: true +// interactive: contentHeight > height +// width: parent.width +// height: 220 + +// ColumnLayout { +// id: sourceColumn + +// width: sourceList.width +// spacing: 6 + +// Repeater { +// model: ioSelector.sourceNodes() + +// Rectangle { +// width: parent.width +// height: 36 +// color: "transparent" +// radius: 6 + +// RowLayout { +// anchors.fill: parent +// anchors.margins: 6 +// spacing: 8 + +// Text { +// text: "mic" +// font.family: "Material Symbols Outlined" +// font.pixelSize: 16 * Theme.scale(screen) +// color: (Pipewire.defaultAudioSource && Pipewire.defaultAudioSource.id === modelData.id) ? Theme.accentPrimary : Theme.textPrimary +// Layout.alignment: Qt.AlignVCenter +// } + +// ColumnLayout { +// Layout.fillWidth: true +// spacing: 1 +// Layout.maximumWidth: sourceList.width - 120 // Reserve space for the Set button + +// Text { +// text: modelData.nickname || modelData.description || modelData.name +// font.bold: true +// font.pixelSize: 12 * Theme.scale(screen) +// color: (Pipewire.defaultAudioSource && Pipewire.defaultAudioSource.id === modelData.id) ? Theme.accentPrimary : Theme.textPrimary +// elide: Text.ElideRight +// maximumLineCount: 1 +// Layout.fillWidth: true +// } + +// Text { +// text: modelData.description !== modelData.nickname ? modelData.description : "" +// font.pixelSize: 10 * Theme.scale(screen) +// color: Theme.textSecondary +// elide: Text.ElideRight +// maximumLineCount: 1 +// Layout.fillWidth: true +// } + +// } + +// Rectangle { +// visible: Pipewire.preferredDefaultAudioSource !== modelData +// width: 60 +// height: 20 +// radius: 4 +// color: Theme.accentPrimary +// border.color: Theme.accentPrimary +// border.width: 1 +// Layout.alignment: Qt.AlignVCenter + +// Text { +// anchors.centerIn: parent +// text: "Set" +// color: Theme.onAccent +// font.pixelSize: 10 * Theme.scale(screen) +// font.bold: true +// } + +// MouseArea { +// anchors.fill: parent +// cursorShape: Qt.PointingHandCursor +// onClicked: Pipewire.preferredDefaultAudioSource = modelData +// } + +// } + +// Text { +// text: "(Current)" +// visible: Pipewire.defaultAudioSource && Pipewire.defaultAudioSource.id === modelData.id +// color: Theme.accentPrimary +// font.pixelSize: 10 * Theme.scale(screen) +// Layout.alignment: Qt.AlignVCenter +// } + +// } + +// } + +// } + +// } + +// ScrollBar.vertical: ScrollBar { +// } + +// } + +// } + +// } + +// Connections { +// function onReadyChanged() { +// if (Pipewire.ready && Pipewire.nodes && Pipewire.nodes.values) { +// for (var i = 0; i < Pipewire.nodes.values.length; ++i) { +// var n = Pipewire.nodes.values[i]; +// } +// } +// } + +// function onDefaultAudioSinkChanged() { +// } + +// function onDefaultAudioSourceChanged() { +// } + +// target: Pipewire +// } +// } + diff --git a/Modules/Bar/Volume.qml b/Modules/Bar/Volume.qml index 996ec03..d1f0992 100644 --- a/Modules/Bar/Volume.qml +++ b/Modules/Bar/Volume.qml @@ -40,32 +40,6 @@ Item { Colors.accentPrimary.b + (Colors.error.b - Colors.accentPrimary.b) * factor, 1) } - NPill { - id: pill - icon: getIcon() - iconCircleColor: getVolumeColor() - collapsedIconColor: getIconColor() - autoHide: true - text: Math.round(Audio.volume * 100) + "%" - tooltipText: "Volume: " + Math.round( - Audio.volume * 100) + "%\nLeft click for advanced settings.\nScroll up/down to change volume." - onClicked: function () { - console.log("onClicked") - // if (ioSelector.visible) { - // ioSelector.dismiss() - // } else { - // ioSelector.show() - // } - } - onWheel: function (angle) { - if (angle > 0) { - Audio.volumeIncrement() - } else if (angle < 0) { - Audio.volumeDecrement() - } - } - } - // Connection used to open the pill when volume changes Connections { target: Audio.sink?.audio ? Audio.sink?.audio : null @@ -80,8 +54,29 @@ Item { } } + NPill { + id: pill + icon: getIcon() + iconCircleColor: getVolumeColor() + collapsedIconColor: getIconColor() + autoHide: true + text: Math.round(Audio.volume * 100) + "%" + tooltipText: "Volume: " + Math.round( + Audio.volume * 100) + "%\nLeft click for advanced settings.\nScroll up/down to change volume." + + onWheel: function (angle) { + if (angle > 0) { + Audio.volumeIncrement() + } else if (angle < 0) { + Audio.volumeDecrement() + } + } + onClicked: function () { + ioSelector.isLoaded = !ioSelector.isLoaded + } + } + AudioDeviceSelector { id: ioSelector - // onPanelClosed: ioSelector.dismiss() } } diff --git a/Services/Audio.qml b/Services/Audio.qml index 3c8bf02..6ce01a0 100644 --- a/Services/Audio.qml +++ b/Services/Audio.qml @@ -37,7 +37,7 @@ Singleton { } PwObjectTracker { - objects: [Pipewire.defaultAudioSink] + objects: [Pipewire.defaultAudioSink, Pipewire.nodes] } Connections { diff --git a/Widgets/NLoader.qml b/Widgets/NLoader.qml index 2dfd104..133083b 100644 --- a/Widgets/NLoader.qml +++ b/Widgets/NLoader.qml @@ -4,7 +4,6 @@ import QtQuick // NLoader { // content: Component { // NPanel { - Loader { id: loader