aerothemeplasma/plasma/plasmoids/io.gitgud.wackyideas.volume/contents/ui/MixerWindow.qml
wackyideas ac5ee71af8 Improve Mixer window popup positioning on Wayland
- Requires building a C++ component for the volume mixer plasmoid
2025-06-13 17:13:36 +02:00

197 lines
6.3 KiB
QML

import QtQuick
import QtQuick.Controls as QQC2
import QtQuick.Layouts
import QtQuick.Window
import org.kde.ksvg as KSvg
import org.kde.kirigami as Kirigami
import org.kde.plasma.extras as PlasmaExtras
import org.kde.plasma.plasmoid
import org.kde.kitemmodels as KItemModels
import org.kde.plasma.core as PlasmaCore
import org.kde.plasma.private.volume
import org.kde.kwindowsystem
import org.kde.kwin.private.kdecoration as KDecoration
Window {
id: mixer
property bool mixer: true
width: 473
height: 311
KDecoration.Bridge {
id: bridgeItem
plugin: KWindowSystem.isPlatformWayland ? Plasmoid.getDecorationPluginName() : "";
theme: KWindowSystem.isPlatformWayland ? Plasmoid.getDecorationThemeName() : "";
}
KDecoration.Settings {
id: settingsItem
bridge: bridgeItem.bridge
}
KDecoration.Decoration {
id: decorationMetrics
bridge: bridgeItem.bridge
settings: settingsItem
anchors.fill: parent
visible: false
}
onVisibleChanged: {
if(visible) {
var pos = main.mapToGlobal(main.x, main.y);
var availScreen = Plasmoid.containment.availableScreenRect;
if(Plasmoid.location === PlasmaCore.Types.BottomEdge) {
x = pos.x - mixer.width / 2;
y = pos.y - mixer.height;
} else if(Plasmoid.location === PlasmaCore.Types.TopEdge) {
x = pos.x - mixer.width / 2;
y = availScreen.y;
} else if(Plasmoid.location === PlasmaCore.Types.LeftEdge) {
x = pos.x;
y = pos.y - mixer.height / 2;
} else if(Plasmoid.location === PlasmaCore.Types.RightEdge) {
x = pos.x - mixer.width;
y = pos.y - mixer.height / 2;
}
if(KWindowSystem.isPlatformWayland) {
var wl_width = mixer.width + decorationMetrics.decoration.borderLeft + decorationMetrics.decoration.borderRight
var wl_height = mixer.height + decorationMetrics.decoration.borderTop + decorationMetrics.decoration.borderBottom
var wl_x = Math.max(availScreen.x, Math.min(x, availScreen.width-wl_width));
var wl_y = Math.max(availScreen.y, Math.min(y, availScreen.height-wl_height));
Plasmoid.setPopupPosition(mixer, wl_x, wl_y);
}
}
}
onClosing: {
mixer.destroy();
}
title: "Volume Mixer" + (paSinkFilterModelDefault.defaultSinkName !== "" ? " - " + paSinkFilterModelDefault.defaultSinkName: "")
component CustomGroupBox: QQC2.GroupBox {
id: gbox
label: QQC2.Label {
id: lbl
x: gbox.leftPadding + 2
y: lbl.implicitHeight/2-gbox.bottomPadding-1
color: "black"
width: lbl.implicitWidth
text: gbox.title
elide: Text.ElideRight
Rectangle {
anchors.fill: parent
anchors.leftMargin: -2
anchors.rightMargin: -2
color: "white"
z: -1
}
}
background: Rectangle {
y: gbox.topPadding - gbox.bottomPadding*2
width: parent.width
height: parent.height - gbox.topPadding + gbox.bottomPadding*2
color: "transparent"
border.color: "#d5dfe5"
radius: 3
}
}
RowLayout {
anchors.fill: parent
anchors.margins: Kirigami.Units.smallSpacing * 3
spacing: 1
CustomGroupBox {
id: speaker
title: "Device"
Layout.fillHeight: true
Layout.preferredWidth: sinkList.width +
(sourceList.visible ? (sourceList.width + (Kirigami.Units.smallSpacing * 4)) : Kirigami.Units.smallSpacing) +
(Kirigami.Units.smallSpacing * 2)
RowLayout {
anchors.fill: parent
anchors.rightMargin: Kirigami.Units.smallSpacing * 4
spacing: Kirigami.Units.smallSpacing * 2
ListView {
id: sinkList
Layout.bottomMargin: Kirigami.Units.smallSpacing * 3
Layout.preferredWidth: 96
Layout.fillHeight: true
interactive: false
model: paSinkFilterModelDefault
delegate: DeviceListItem { type: "sink-output"; width: 96; height: parent.height }
orientation: ListView.Horizontal
spacing: 0
Rectangle {
anchors.right: parent.right
anchors.rightMargin: -1
anchors.top: parent.top
anchors.bottom: parent.bottom
width: 1
color: "#d6e1dd"
visible: sourceList.visible
}
}
ListView {
id: sourceList
Layout.bottomMargin: Kirigami.Units.smallSpacing * 3
Layout.preferredWidth: 96
Layout.fillHeight: true
interactive: false
model: paSourceFilterModelDefault
delegate: DeviceListItem { type: "sink-input"; width: 96; height: parent.height; isInWindow: true }
orientation: ListView.Horizontal
focus: visible
visible: count != 0
spacing: 0
}
}
}
CustomGroupBox {
id: apps
Layout.fillHeight: true
Layout.fillWidth: true
title: "Applications"
QQC2.ScrollView {
anchors.fill: parent
ListView {
id: sinkInputList
anchors.fill: parent
anchors.bottomMargin: Kirigami.Units.smallSpacing * 3
interactive: false
model: paSinkInputFilterModel
delegate: StreamListItem { type: "source-output"; width: 96; height: parent.height; isInWindow: true }
orientation: ListView.Horizontal
focus: visible
spacing: Kirigami.Units.smallSpacing
clip: true
}
}
}
}
}