Fix bg tracking, use slow spatial for detach, default spatial for everything else, adjust deform, move instead of width scale
205 lines
5.3 KiB
QML
205 lines
5.3 KiB
QML
pragma ComponentBehavior: Bound
|
|
|
|
import QtQuick
|
|
import Quickshell
|
|
import Quickshell.Hyprland
|
|
import Quickshell.Wayland
|
|
import qs.components
|
|
import qs.services
|
|
import qs.config
|
|
import qs.modules.controlcenter
|
|
import qs.modules.windowinfo
|
|
|
|
Item {
|
|
id: root
|
|
|
|
required property ShellScreen screen
|
|
required property real offsetScale
|
|
|
|
readonly property alias content: content
|
|
readonly property alias winfo: winfo
|
|
readonly property alias controlCenter: controlCenter
|
|
|
|
readonly property real nonAnimWidth: children.find(c => c.shouldBeActive)?.implicitWidth ?? content.implicitWidth
|
|
readonly property real nonAnimHeight: children.find(c => c.shouldBeActive)?.implicitHeight ?? content.implicitHeight
|
|
readonly property Item current: (content.item as Content)?.current ?? null
|
|
readonly property bool isDetached: detachedMode.length > 0
|
|
|
|
property alias currentName: popoutState.currentName
|
|
property alias hasCurrent: popoutState.hasCurrent
|
|
property real currentCenter
|
|
|
|
property string detachedMode
|
|
property string queuedMode
|
|
|
|
property int animLength: Appearance.anim.durations.expressiveDefaultSpatial
|
|
property list<real> animCurve: Appearance.anim.curves.expressiveDefaultSpatial
|
|
|
|
function setAnims(detach: bool): void {
|
|
const type = `expressive${detach ? "Slow" : "Default"}Spatial`;
|
|
animLength = Appearance.anim.durations[type];
|
|
animCurve = Appearance.anim.curves[type];
|
|
}
|
|
|
|
function detach(mode: string): void {
|
|
setAnims(true);
|
|
if (mode === "winfo") {
|
|
detachedMode = mode;
|
|
} else {
|
|
queuedMode = mode;
|
|
detachedMode = "any";
|
|
}
|
|
setAnims(false);
|
|
focus = true;
|
|
}
|
|
|
|
function close(): void {
|
|
hasCurrent = false;
|
|
detachedMode = "";
|
|
}
|
|
|
|
implicitWidth: nonAnimWidth
|
|
implicitHeight: nonAnimHeight
|
|
|
|
focus: hasCurrent
|
|
Keys.onEscapePressed: {
|
|
// Forward escape to password popout if active, otherwise close
|
|
if (currentName === "wirelesspassword" && content.item) {
|
|
const passwordPopout = (content.item as Content)?.children.find(c => c.name === "wirelesspassword");
|
|
if (passwordPopout && passwordPopout.item) {
|
|
passwordPopout.item.closeDialog();
|
|
return;
|
|
}
|
|
}
|
|
close();
|
|
}
|
|
|
|
Keys.onPressed: event => {
|
|
// Don't intercept keys when password popout is active - let it handle them
|
|
if (currentName === "wirelesspassword") {
|
|
event.accepted = false;
|
|
}
|
|
}
|
|
|
|
PopoutState {
|
|
id: popoutState
|
|
|
|
onDetachRequested: mode => root.detach(mode)
|
|
}
|
|
|
|
HyprlandFocusGrab {
|
|
active: root.isDetached
|
|
windows: [QsWindow.window]
|
|
onCleared: root.close()
|
|
}
|
|
|
|
Binding {
|
|
when: root.isDetached || (root.hasCurrent && root.currentName === "wirelesspassword")
|
|
|
|
target: QsWindow.window
|
|
property: "WlrLayershell.keyboardFocus"
|
|
value: WlrKeyboardFocus.OnDemand
|
|
}
|
|
|
|
Comp {
|
|
id: content
|
|
|
|
shouldBeActive: root.hasCurrent && !root.detachedMode
|
|
anchors.right: parent.right
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
|
|
sourceComponent: Content {
|
|
popouts: popoutState
|
|
}
|
|
}
|
|
|
|
Comp {
|
|
id: winfo
|
|
|
|
shouldBeActive: root.detachedMode === "winfo"
|
|
anchors.centerIn: parent
|
|
|
|
sourceComponent: WindowInfo {
|
|
screen: root.screen
|
|
client: Hypr.activeToplevel
|
|
}
|
|
}
|
|
|
|
Comp {
|
|
id: controlCenter
|
|
|
|
shouldBeActive: root.detachedMode === "any"
|
|
anchors.centerIn: parent
|
|
|
|
sourceComponent: ControlCenter {
|
|
screen: root.screen
|
|
active: root.queuedMode
|
|
onClose: root.close()
|
|
}
|
|
}
|
|
|
|
Behavior on implicitWidth {
|
|
Anim {
|
|
duration: root.animLength
|
|
easing.bezierCurve: root.animCurve
|
|
}
|
|
}
|
|
|
|
Behavior on implicitHeight {
|
|
enabled: root.offsetScale < 1
|
|
|
|
Anim {
|
|
duration: root.animLength
|
|
easing.bezierCurve: root.animCurve
|
|
}
|
|
}
|
|
|
|
component Comp: Loader {
|
|
id: comp
|
|
|
|
property bool shouldBeActive
|
|
|
|
active: false
|
|
opacity: 0
|
|
|
|
// Makes the loader load on the same frame shouldBeActive becomes true, which ensures size is set
|
|
states: State {
|
|
name: "active"
|
|
when: comp.shouldBeActive
|
|
|
|
PropertyChanges {
|
|
comp.opacity: 1
|
|
comp.active: true
|
|
}
|
|
}
|
|
|
|
transitions: [
|
|
Transition {
|
|
from: ""
|
|
to: "active"
|
|
|
|
SequentialAnimation {
|
|
PropertyAction {
|
|
property: "active"
|
|
}
|
|
Anim {
|
|
property: "opacity"
|
|
}
|
|
}
|
|
},
|
|
Transition {
|
|
from: "active"
|
|
to: ""
|
|
|
|
SequentialAnimation {
|
|
Anim {
|
|
property: "opacity"
|
|
}
|
|
PropertyAction {
|
|
property: "active"
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}
|
|
}
|