quickshell and hyprland additions

This commit is contained in:
2026-03-15 13:56:00 +02:00
parent c9c27d1554
commit 1ad06b82a6
509 changed files with 68371 additions and 19 deletions

View File

@@ -0,0 +1,185 @@
import ".."
import qs.components.effects
import qs.services
import qs.config
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
Popup {
id: root
required property Item target
required property string text
property int delay: 500
property int timeout: 0
property bool tooltipVisible: false
property Timer showTimer: Timer {
interval: root.delay
onTriggered: root.tooltipVisible = true
}
property Timer hideTimer: Timer {
interval: root.timeout
onTriggered: root.tooltipVisible = false
}
// Popup properties - doesn't affect layout
parent: {
let p = target;
// Walk up to find the root Item (usually has anchors.fill: parent)
while (p && p.parent) {
const parentItem = p.parent;
// Check if this looks like a root pane Item
if (parentItem && parentItem.anchors && parentItem.anchors.fill !== undefined) {
return parentItem;
}
p = parentItem;
}
// Fallback
return target.parent?.parent?.parent ?? target.parent?.parent ?? target.parent ?? target;
}
visible: tooltipVisible
modal: false
closePolicy: Popup.NoAutoClose
padding: 0
margins: 0
background: Item {}
// Update position when target moves or tooltip becomes visible
onTooltipVisibleChanged: {
if (tooltipVisible) {
Qt.callLater(updatePosition);
}
}
Connections {
target: root.target
function onXChanged() {
if (root.tooltipVisible)
root.updatePosition();
}
function onYChanged() {
if (root.tooltipVisible)
root.updatePosition();
}
function onWidthChanged() {
if (root.tooltipVisible)
root.updatePosition();
}
function onHeightChanged() {
if (root.tooltipVisible)
root.updatePosition();
}
}
function updatePosition() {
if (!target || !parent)
return;
// Wait for tooltipRect to have its size calculated
Qt.callLater(() => {
if (!target || !parent || !tooltipRect)
return;
// Get target position in parent's coordinate system
const targetPos = target.mapToItem(parent, 0, 0);
const targetCenterX = targetPos.x + target.width / 2;
// Get tooltip size (use width/height if available, otherwise implicit)
const tooltipWidth = tooltipRect.width > 0 ? tooltipRect.width : tooltipRect.implicitWidth;
const tooltipHeight = tooltipRect.height > 0 ? tooltipRect.height : tooltipRect.implicitHeight;
// Center tooltip horizontally on target
let newX = targetCenterX - tooltipWidth / 2;
// Position tooltip above target
let newY = targetPos.y - tooltipHeight - Appearance.spacing.small;
// Keep within bounds
const padding = Appearance.padding.normal;
if (newX < padding) {
newX = padding;
} else if (newX + tooltipWidth > (parent.width - padding)) {
newX = parent.width - tooltipWidth - padding;
}
// Update popup position
x = newX;
y = newY;
});
}
enter: Transition {
Anim {
property: "opacity"
from: 0
to: 1
duration: Appearance.anim.durations.expressiveFastSpatial
easing.bezierCurve: Appearance.anim.curves.expressiveFastSpatial
}
}
exit: Transition {
Anim {
property: "opacity"
from: 1
to: 0
duration: Appearance.anim.durations.expressiveFastSpatial
easing.bezierCurve: Appearance.anim.curves.expressiveFastSpatial
}
}
// Monitor hover state
Connections {
target: root.target
function onHoveredChanged() {
if (target.hovered) {
showTimer.start();
if (timeout > 0) {
hideTimer.stop();
hideTimer.start();
}
} else {
showTimer.stop();
hideTimer.stop();
tooltipVisible = false;
}
}
}
contentItem: StyledRect {
id: tooltipRect
implicitWidth: tooltipText.implicitWidth + Appearance.padding.normal * 2
implicitHeight: tooltipText.implicitHeight + Appearance.padding.smaller * 2
color: Colours.palette.m3surfaceContainerHighest
radius: Appearance.rounding.small
antialiasing: true
// Add elevation for depth
Elevation {
anchors.fill: parent
radius: parent.radius
z: -1
level: 3
}
StyledText {
id: tooltipText
anchors.centerIn: parent
text: root.text
color: Colours.palette.m3onSurface
font.pointSize: Appearance.font.size.small
}
}
Component.onCompleted: {
if (tooltipVisible) {
updatePosition();
}
}
}