Files
dms-gamebar/GameBarPanel.qml
T
2026-09-21 16:50:56 +02:00

133 lines
3.4 KiB
QML

import QtQuick
import Quickshell
import Quickshell.Services.Pipewire
import qs.Common
import qs.Services
import qs.Widgets
FocusScope {
id: root
property var overlayRef: null
readonly property var daemon: overlayRef ? overlayRef.daemon : null
readonly property var pluginData: (daemon && daemon.pluginData) ? daemon.pluginData : ({})
readonly property var targetScreen: overlayRef ? overlayRef.effectiveScreen : null
readonly property real edgeMargin: Theme.spacingM
readonly property real topLimit: topBar.y + topBar.height + Theme.spacingM
property int windowZCounter: 1
function nextWindowZ() {
root.windowZCounter = root.windowZCounter + 1;
return root.windowZCounter;
}
function requestClose() {
if (overlayRef)
overlayRef.requestClose();
}
function isWidgetVisible(widgetId) {
return daemon ? daemon.isWidgetVisible(widgetId) : false;
}
function toggleWidget(widgetId) {
if (daemon)
daemon.toggleWidget(widgetId);
}
function widgetPosition(widgetId) {
if (daemon)
return daemon.widgetPosition(root.targetScreen, widgetId);
return {
"x": 0.1,
"y": 0.15
};
}
function saveWidgetPosition(widgetId, fractionX, fractionY) {
if (daemon)
daemon.saveWidgetPosition(root.targetScreen, widgetId, fractionX, fractionY);
}
anchors.fill: parent
focus: true
// The modal's own Escape handler sits on a sibling focus scope, so the key
// never reaches it once this content holds focus - handle it here instead.
Keys.onEscapePressed: event => {
root.requestClose();
event.accepted = true;
}
Component.onCompleted: root.forceActiveFocus()
// Keeps the default sink/source properties live while the overlay is open.
PwObjectTracker {
objects: [AudioService.sink, AudioService.source].filter(node => !!node)
}
// Clicking empty space closes, like clicking outside a dialog.
MouseArea {
anchors.fill: parent
onClicked: root.requestClose()
}
GameBarTopBar {
id: topBar
panel: root
anchors.top: parent.top
anchors.topMargin: Theme.spacingL
anchors.horizontalCenter: parent.horizontalCenter
}
Repeater {
model: root.daemon ? root.daemon.widgetDefs : []
delegate: GameBarWindow {
required property var modelData
panel: root
widgetId: modelData.id
title: modelData.title
icon: modelData.icon
widgetWidth: modelData.width
widgetHeight: modelData.height
minimumY: root.topLimit
shown: root.isWidgetVisible(modelData.id)
contentComponent: {
switch (modelData.id) {
case "audio":
return audioWidgetComponent;
case "apps":
return appsWidgetComponent;
case "system":
return systemWidgetComponent;
}
return null;
}
}
}
Component {
id: audioWidgetComponent
GameBarAudioWidget {}
}
Component {
id: appsWidgetComponent
GameBarAppMixer {}
}
Component {
id: systemWidgetComponent
GameBarSystemWidget {}
}
}