import QtQuick import QtQuick.Controls import "root:/Data" as Data // Calendar popup with animations Popup { id: calendarPopup property bool hovered: false property bool clickMode: false // Persistent mode - stays open until clicked again property var shell property int targetX: 0 readonly property int targetY: Screen.height - height width: 280 height: 280 modal: false focus: true closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside padding: 15 // Animation state properties property bool _visible: false property real animX: targetX - 20 property real animOpacity: 0 x: animX y: targetY opacity: animOpacity visible: _visible // Smooth slide-in animation Behavior on animX { NumberAnimation { duration: 200; easing.type: Easing.InOutQuad } } Behavior on animOpacity { NumberAnimation { duration: 200; easing.type: Easing.InOutQuad } } // Hover mode: show/hide based on mouse state onHoveredChanged: { if (!clickMode) { if (hovered) { _visible = true animX = targetX animOpacity = 1 } else { animX = targetX - 20 animOpacity = 0 } } } // Click mode: persistent visibility toggle onClickModeChanged: { if (clickMode) { _visible = true animX = targetX animOpacity = 1 } else { animX = targetX - 20 animOpacity = 0 } } // Hide when animation completes onAnimOpacityChanged: { if (animOpacity === 0 && !hovered && !clickMode) { _visible = false } } function setHovered(state) { hovered = state } function setClickMode(state) { clickMode = state } // Hover detection MouseArea { id: hoverArea anchors.fill: parent hoverEnabled: true propagateComposedEvents: true anchors.margins: 10 // Larger area to reduce flicker onEntered: { if (!clickMode) { setHovered(true) } } onExited: { if (!clickMode) { // Delayed exit check to prevent hover flicker Qt.callLater(() => { if (!hoverArea.containsMouse) { setHovered(false) } }) } } } // Lazy-loaded calendar content Loader { anchors.fill: parent active: calendarPopup._visible source: active ? "Calendar.qml" : "" onLoaded: { if (item) { item.shell = calendarPopup.shell } } } background: Rectangle { color: Data.ThemeManager.bgColor topRightRadius: 20 } }