aboutsummaryrefslogtreecommitdiffstats
path: root/desktop/companion/Companion.qml
diff options
context:
space:
mode:
Diffstat (limited to 'desktop/companion/Companion.qml')
-rw-r--r--desktop/companion/Companion.qml50
1 files changed, 37 insertions, 13 deletions
diff --git a/desktop/companion/Companion.qml b/desktop/companion/Companion.qml
index e2d91a9..21b1a38 100644
--- a/desktop/companion/Companion.qml
+++ b/desktop/companion/Companion.qml
@@ -63,24 +63,42 @@ PanelWindow {
}
}
- // The monitor she is on trails the focused one: a change plays her exit
- // here first, and only then moves the window (settled, below).
+ // Where she goes: the focused monitor's corner, or seated on the
+ // assistant's tall card. here and sitting are where the window is now
+ // and trail the goal: a change plays her exit first, and only then
+ // moves the window (settled, below).
readonly property string focused: Hyprland.focusedMonitor?.name ?? ""
+ readonly property bool seated: root.asst.open && root.asst.tall
+ readonly property string goal: root.seated ? root.asst.monitor : root.focused
property string here: ""
+ property bool sitting: false
property bool hopping: false
// No focused monitor (outputs gone over a suspend) is not a destination.
// Already out of view, there is no exit to wait for: settled would never
// fire, hopping would stick and hide her for good, so move at once.
- onFocusedChanged: {
- if (root.focused === "" || root.focused === root.here) return;
- if (root.here === "" || root.away) root.here = root.focused;
- else root.hopping = true;
+ function move() {
+ if (root.goal === "" || (root.goal === root.here && root.seated === root.sitting)) return;
+ if (root.here === "" || root.away) {
+ root.here = root.goal;
+ root.sitting = root.seated;
+ } else {
+ root.hopping = true;
+ }
}
- Component.onCompleted: root.here = root.focused
+ onGoalChanged: root.move()
+ onSeatedChanged: root.move()
+ Component.onCompleted: root.move()
screen: Quickshell.screens.find(s => s.name === root.here) ?? Quickshell.screens[0]
anchors { right: true; bottom: true }
- margins { right: 24; bottom: 16 }
+ // Seated, her right edge is 90 px right of the screen's centre, which
+ // puts her in the gap in the card's header, and her feet 35 px below the
+ // card's top. The right edge rather than her centre, because frames
+ // differ in width and the window would shift with every frame.
+ margins {
+ right: root.sitting ? Math.round(root.asst.screenObj.width / 2 - 90) : 24
+ bottom: root.sitting ? root.asst.screenObj.height - root.asst.cardTop - 35 : 16
+ }
implicitWidth: 760
implicitHeight: 260
color: "transparent"
@@ -268,7 +286,7 @@ PanelWindow {
interval: 100
onTriggered: {
const t = Date.now();
- if (root.away || root.here !== root.focused || !Mood.admireAllowed(root.admireAt, t)) return;
+ if (root.away || root.sitting || root.here !== root.focused || !Mood.admireAllowed(root.admireAt, t)) return;
if ((Hyprland.focusedWorkspace?.toplevels.values.length ?? 1) !== 0) return;
if (!Admired.listed(Admired.on(root.here))) return;
root.admireAt = t;
@@ -291,8 +309,10 @@ PanelWindow {
Timer { id: remap; interval: 400; onTriggered: root.remapping = false }
// Balloons stack bottom-right of their screen. When that is her corner,
- // any balloon on screen shoves her left past the stack.
+ // any balloon on screen shoves her left past the stack. Seated on the
+ // assistant's card she is nowhere near them.
readonly property bool shoved: {
+ if (root.sitting) return false;
const place = Notify.config.balloons;
if (place.screen !== root.here || place.corner !== "bottom-right") return false;
return (Notify.queue || []).some(n => NC.shown(Notify.config, n, Notify.dnd,
@@ -452,8 +472,10 @@ PanelWindow {
running: root.cycle !== null && !root.away
onTriggered: root.cycleIndex = (root.cycleIndex + 1) % root.cycle.frames.length
}
- readonly property string frame: root.leaving ? root.waveCycle[root.waveIndex]
+ readonly property string standing: root.leaving ? root.waveCycle[root.waveIndex]
: root.cycle ? root.cycle.frames[root.cycleIndex % root.cycle.frames.length] : root.mood.frame
+ // Seated, the sitting version of it (Mood.seatFrame).
+ readonly property string frame: root.sitting ? Mood.seatFrame(root.standing) : root.standing
// qs -p <desktop> ipc call companion toggle -> SUPER+\
IpcHandler {
@@ -463,10 +485,12 @@ PanelWindow {
function hide() { Prefs.setCompanion(false); }
}
- // The exit has played on the old monitor: move, and the entrance plays.
+ // The exit has played: move, and the entrance plays. The goal may have
+ // changed during the exit; the latest one wins.
function settled(out) {
if (out && root.hopping) {
- root.here = root.focused;
+ root.here = root.goal;
+ root.sitting = root.seated;
root.hopping = false;
}
}