fix(quickshell): rail popouts no longer land short of the rail
Popouts anchored to their trigger item, and Quickshell maps an anchor rect given in item coordinates through the item's transform. Rail icons scale to 1.08 on hover, so a panel placed ~360px left of the icon landed up to ~29px further left still, leaving a strip of desktop between it and the rail — by however far the hover scale had got when the dwell timer fired, which is why it only happened sometimes. Anchor to the trigger window's content item instead, which never transforms, and place in window coordinates from the trigger's centre, which a scale about the centre leaves where it is. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
196abc2311
commit
a27dd6f93b
1 file changed
+22
-12
@@ -92,15 +92,25 @@ PopupWindow {
|
|||||||
// 0 = tucked behind the frame, 1 = fully out.
|
// 0 = tucked behind the frame, 1 = fully out.
|
||||||
property real reveal: 0
|
property real reveal: 0
|
||||||
|
|
||||||
// Placement, in the trigger's own coordinates. Worked out once per open
|
// Placement, in the trigger window's coordinates. Worked out once per open
|
||||||
// in place(): item positions are not bindable, and a popout should not
|
// in place(): item positions are not bindable, and a popout should not
|
||||||
// drift while it is up anyway.
|
// drift while it is up anyway.
|
||||||
property real placeX: 0
|
property real placeX: 0
|
||||||
property real placeY: 0
|
property real placeY: 0
|
||||||
|
|
||||||
|
// The popout anchors to the trigger's window, not to the trigger. Rail
|
||||||
|
// icons scale up on hover, and an anchor rect given in an item's own
|
||||||
|
// coordinates is mapped through that item's transform: a panel placed
|
||||||
|
// 360px left of a 1.08-scaled icon landed 29px further left still, off
|
||||||
|
// the rail — by however far the hover scale had got when the popout
|
||||||
|
// opened. The window's content item never transforms.
|
||||||
|
readonly property Item anchorFrame: anchorItem?.Window.contentItem ?? null
|
||||||
|
|
||||||
function place() {
|
function place() {
|
||||||
if (!anchorItem) return;
|
if (!anchorItem) return;
|
||||||
const p = anchorItem.mapToItem(null, 0, 0);
|
// The trigger's centre. A transform about the centre leaves it where
|
||||||
|
// it is, so this is the same whatever the hover scale is doing.
|
||||||
|
const c = anchorItem.mapToItem(null, anchorItem.width / 2, anchorItem.height / 2);
|
||||||
const winW = anchorItem.Window.width;
|
const winW = anchorItem.Window.width;
|
||||||
const winH = anchorItem.Window.height;
|
const winH = anchorItem.Window.height;
|
||||||
const f = root.fillet, R = Theme.frameRadius;
|
const f = root.fillet, R = Theme.frameRadius;
|
||||||
@@ -110,40 +120,40 @@ PopupWindow {
|
|||||||
// edge, so its x = 0 is that edge and its y = 0 is the bar's
|
// edge, so its x = 0 is that edge and its y = 0 is the bar's
|
||||||
// underside.
|
// underside.
|
||||||
const h = root.contentHeight + f * 2;
|
const h = root.contentHeight + f * 2;
|
||||||
const y = p.y + anchorItem.height / 2 - h / 2;
|
const y = c.y - h / 2;
|
||||||
const lo = R, hi = winH - Theme.frame - R - h;
|
const lo = R, hi = winH - Theme.frame - R - h;
|
||||||
|
|
||||||
if (y < lo + root.dockReach) {
|
if (y < lo + root.dockReach) {
|
||||||
root.dock = "topRight";
|
root.dock = "topRight";
|
||||||
root.placeY = -root.seam - p.y;
|
root.placeY = -root.seam;
|
||||||
} else if (y > hi - root.dockReach) {
|
} else if (y > hi - root.dockReach) {
|
||||||
root.dock = "bottomRight";
|
root.dock = "bottomRight";
|
||||||
root.placeY = winH - Theme.frame + root.seam - root.windowHeight - p.y;
|
root.placeY = winH - Theme.frame + root.seam - root.windowHeight;
|
||||||
} else {
|
} else {
|
||||||
root.dock = "right";
|
root.dock = "right";
|
||||||
root.placeY = y - p.y;
|
root.placeY = y;
|
||||||
}
|
}
|
||||||
root.placeX = root.seam - root.windowWidth - p.x;
|
root.placeX = root.seam - root.windowWidth;
|
||||||
} else {
|
} else {
|
||||||
// The bar's window is the full screen width, so the opening runs
|
// The bar's window is the full screen width, so the opening runs
|
||||||
// from `frame` to `width - railWidth`.
|
// from `frame` to `width - railWidth`.
|
||||||
const w = root.contentWidth + f * 2;
|
const w = root.contentWidth + f * 2;
|
||||||
const x = p.x + anchorItem.width / 2 - w / 2;
|
const x = c.x - w / 2;
|
||||||
const lo = Theme.frame + R - f;
|
const lo = Theme.frame + R - f;
|
||||||
const hi = winW - Theme.railWidth - R + f - w;
|
const hi = winW - Theme.railWidth - R + f - w;
|
||||||
|
|
||||||
if (x > hi - root.dockReach) {
|
if (x > hi - root.dockReach) {
|
||||||
root.dock = "topRight";
|
root.dock = "topRight";
|
||||||
root.placeX = winW - Theme.railWidth + root.seam - root.windowWidth - p.x;
|
root.placeX = winW - Theme.railWidth + root.seam - root.windowWidth;
|
||||||
} else {
|
} else {
|
||||||
root.dock = "top";
|
root.dock = "top";
|
||||||
root.placeX = Math.max(lo, x) - p.x;
|
root.placeX = Math.max(lo, x);
|
||||||
}
|
}
|
||||||
root.placeY = winH - root.seam - p.y;
|
root.placeY = winH - root.seam;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
anchor.item: anchorItem
|
anchor.item: anchorFrame
|
||||||
anchor.rect.x: root.placeX
|
anchor.rect.x: root.placeX
|
||||||
anchor.rect.y: root.placeY
|
anchor.rect.y: root.placeY
|
||||||
anchor.rect.w: 1
|
anchor.rect.w: 1
|
||||||
|
|||||||
Reference in new issue
Block a user