190 lines
4.8 KiB
QML
190 lines
4.8 KiB
QML
import QtQuick
|
|
import Quickshell
|
|
import Quickshell.Services.Pipewire
|
|
import qs.Common
|
|
import qs.Services
|
|
import qs.Widgets
|
|
import "../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
|
|
// Changes when the overlay lands on a different monitor (or that monitor
|
|
// changes resolution); widgets re-read their saved spot when it does.
|
|
readonly property string screenKey: daemon ? daemon.screenKey(root.targetScreen) : ""
|
|
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, root.width, root.height);
|
|
|
|
return {
|
|
"x": root.width * 0.1,
|
|
"y": root.height * 0.15
|
|
};
|
|
}
|
|
|
|
function saveWidgetPosition(widgetId, x, y) {
|
|
if (daemon)
|
|
daemon.saveWidgetPosition(root.targetScreen, widgetId, x, y);
|
|
}
|
|
|
|
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()
|
|
}
|
|
|
|
TopBar {
|
|
id: topBar
|
|
|
|
panel: root
|
|
anchors.top: parent.top
|
|
anchors.topMargin: Theme.spacingL
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
}
|
|
|
|
Repeater {
|
|
model: root.daemon ? root.daemon.widgetDefs : []
|
|
|
|
delegate: WidgetWindow {
|
|
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 "capture":
|
|
return captureWidgetComponent;
|
|
case "media":
|
|
return mediaWidgetComponent;
|
|
case "visualizer":
|
|
return visualizerWidgetComponent;
|
|
case "bluetooth":
|
|
return bluetoothWidgetComponent;
|
|
case "notepad":
|
|
return notepadWidgetComponent;
|
|
case "home":
|
|
return homeWidgetComponent;
|
|
case "system":
|
|
return systemWidgetComponent;
|
|
}
|
|
return null;
|
|
}
|
|
}
|
|
}
|
|
|
|
Component {
|
|
id: audioWidgetComponent
|
|
|
|
AudioWidget {}
|
|
}
|
|
|
|
Component {
|
|
id: appsWidgetComponent
|
|
|
|
AppMixer {}
|
|
}
|
|
|
|
Component {
|
|
id: captureWidgetComponent
|
|
|
|
CaptureWidget {
|
|
service: root.daemon ? root.daemon.captureService : null
|
|
panel: root
|
|
}
|
|
}
|
|
|
|
Component {
|
|
id: visualizerWidgetComponent
|
|
|
|
VisualizerWidget {}
|
|
}
|
|
|
|
Component {
|
|
id: bluetoothWidgetComponent
|
|
|
|
BluetoothWidget {}
|
|
}
|
|
|
|
Component {
|
|
id: notepadWidgetComponent
|
|
|
|
NotepadWidget {}
|
|
}
|
|
|
|
Component {
|
|
id: mediaWidgetComponent
|
|
|
|
MediaWidget {}
|
|
}
|
|
|
|
Component {
|
|
id: homeWidgetComponent
|
|
|
|
HomeWidget {
|
|
service: root.daemon ? root.daemon.homeService : null
|
|
}
|
|
}
|
|
|
|
Component {
|
|
id: systemWidgetComponent
|
|
|
|
SystemWidget {}
|
|
}
|
|
}
|