mirror of
https://github.com/belsabbagh/dotfiles.git
synced 2026-04-11 01:26:46 +00:00
quickshell and hyprland additions
This commit is contained in:
185
.config/quickshell/caelestia/components/controls/Tooltip.qml
Normal file
185
.config/quickshell/caelestia/components/controls/Tooltip.qml
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user