dots/shell/bar/Popup.qml
2025-08-10 23:54:48 -04:00

160 lines
4.4 KiB
QML

pragma ComponentBehavior: Bound
import QtQuick
import Quickshell
import Quickshell.Hyprland
import qs.widgets
Scope {
id: root
required property var bar
property real gaps: 5
property Item parentItem
property PopupItem activeItem
property PopupItem lastActiveItem
property PopupItem shownItem: activeItem ?? lastActiveItem
onActiveItemChanged: {
if (activeItem != null) {
activeItem.targetVisible = true;
if (parentItem) {
activeItem.parent = parentItem;
}
}
if (lastActiveItem != null && lastActiveItem != activeItem) {
lastActiveItem.targetVisible = false;
}
}
function setItem(item: PopupItem) {
if (activeItem != null) {
lastActiveItem = activeItem;
}
activeItem = item;
}
function removeItem(item: PopupItem) {
if (activeItem == item) {
activeItem = null;
}
}
function onHidden(item: PopupItem) {
if (item == lastActiveItem) {
lastActiveItem = null;
}
}
LazyLoader {
id: popupLoader
activeAsync: root.shownItem != null
PopupWindow {
id: popup
visible: true
color: "transparent"
implicitWidth: root.bar.width
implicitHeight: Math.max(800, parentItem.targetHeight)
anchor {
window: root.bar
rect: Qt.rect(0, 0, root.bar.width, root.bar.height)
edges: Edges.Bottom | Edges.Left
gravity: Edges.Bottom | Edges.Right
adjustment: PopupAdjustment.None
}
mask: Region {
item: parentItem
}
HyprlandFocusGrab {
id: grab
active: true
windows: [popup, root.bar]
onCleared: {
root.shownItem.closed();
}
}
HyprlandWindow.visibleMask: Region {
id: mask
item: parentItem
}
StyledRectangle {
id: parentItem
width: targetWidth
height: targetHeight
x: targetX
y: root.gaps
clip: true
readonly property var targetWidth: root.shownItem?.implicitWidth ?? 0
readonly property var targetHeight: root.shownItem?.implicitHeight ?? 0
readonly property var targetX: {
if (root.shownItem == null) {
return 0;
}
let owner = root.shownItem.owner;
let bar = root.bar;
let xPos = owner.mapToItem(bar.contentItem, 0, bar.height, owner.width, 0).x;
let rightEdge = xPos + targetWidth;
let maxRightEdge = popup.width;
if (rightEdge > maxRightEdge) {
// touching right edge, reposition
// console.log("touching right edge");
return maxRightEdge - targetWidth - root.gaps;
}
return xPos;
}
Component.onCompleted: {
root.parentItem = this;
if (root.activeItem) {
root.activeItem.parent = this;
}
}
// TODO: Make a close animation, a little complicated, will need to track if an animation is running
// and stop unload from occuring until its done, in the LazyLoader.
Behavior on width {
enabled: root.lastActiveItem != null
SmoothedAnimation {
duration: 300
easing.type: Easing.InOutQuad
}
}
Behavior on height {
SmoothedAnimation {
duration: 300
easing.type: Easing.InOutQuad
}
}
Behavior on x {
enabled: root.lastActiveItem != null
SmoothedAnimation {
duration: 300
easing.type: Easing.InOutQuad
}
}
}
}
}
}