/* * SPDX-FileCopyrightText: 2023 Marco Martin * * SPDX-License-Identifier: LGPL-2.0-or-later */ import QtQuick import QtQuick.Controls as QQC2 import QtQuick.Templates as T import org.kde.kirigami as Kirigami import org.kde.kirigami.templates as KT Item { id: root /* * This property is used to set when the tooltip is visible. * It exists because the text is changed while the tooltip is still visible. */ property bool displayToolTip: true /* * The drawer this handle will control */ // Should be KT.OverlayDrawer, but can't due to "Cyclic dependency" property T.Drawer drawer readonly property T.Overlay overlay: drawer.T.Overlay.overlay // Above the Overlay when modal but below when non-modal and when the drawer is closed // so that other overlays can be above it. parent: overlay?.parent ?? null z: overlay ? overlay.z + (drawer?.modal && (drawer as KT.OverlayDrawer)?.drawerOpen ? 1 : - 1) : 0 QQC2.ToolButton { id: button anchors.centerIn: parent flat: false icon.name: root.drawer.position > 0 ? root.drawer.handleOpenIcon.name : root.drawer.handleClosedIcon.name icon.source: root.drawer.position > 0 ? root.drawer.handleOpenIcon.source ?? "" : root.drawer.handleClosedIcon.source ?? "" icon.width: root.drawer.handleOpenIcon.width icon.height: root.drawer.handleOpenIcon.height Accessible.name: QQC2.ToolTip.text onClicked: { root.displayToolTip = false; Qt.callLater(() => { const oDrawer = root.drawer as KT.OverlayDrawer oDrawer.drawerOpen = !oDrawer.drawerOpen; }) } Keys.onEscapePressed: { if (root.drawer.closePolicy & T.Popup.CloseOnEscape) { root.drawer.drawerOpen = false; } } QQC2.ToolTip.visible: root.displayToolTip && hovered QQC2.ToolTip.text: { const oDrawer = root.drawer as KT.OverlayDrawer return oDrawer.drawerOpen ? oDrawer.handleOpenToolTip : oDrawer.handleClosedToolTip } QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay DragHandler { target: null acceptedDevices: PointerDevice.TouchScreen | PointerDevice.Stylus xAxis { enabled: root.drawer.edge === Qt.LeftEdge || root.drawer.edge === Qt.RightEdge minimum: 0 maximum: root.drawer.contentItem.width onActiveValueChanged: (delta) => { let positionDelta = delta / root.drawer.contentItem.width; if (root.drawer.edge === Qt.RightEdge) { positionDelta *= -1; } root.drawer.position += positionDelta; } } yAxis.enabled: false onGrabChanged: (transition, point) => { switch (transition) { case PointerDevice.GrabExclusive: case PointerDevice.GrabPassive: root.drawer.peeking = true; break; case PointerDevice.UngrabExclusive: case PointerDevice.UngrabPassive: case PointerDevice.CancelGrabExclusive: case PointerDevice.CancelGrabPassive: root.drawer.peeking = false; break; default: break; } } } } property Item handleAnchor: { if (typeof applicationWindow === "undefined") { return null; } const window = applicationWindow(); const globalToolBar = window.pageStack?.globalToolBar; if (!globalToolBar) { return null; } return (drawer.edge === Qt.LeftEdge && !LayoutMirroring.enabled) || (drawer.edge === Qt.RightEdge && LayoutMirroring.enabled) ? globalToolBar.leftHandleAnchor : globalToolBar.rightHandleAnchor; } enabled: (drawer as KT.OverlayDrawer).handleVisible x: { switch (drawer.edge) { case Qt.LeftEdge: return drawer.background.width * drawer.position + Kirigami.Units.smallSpacing; case Qt.RightEdge: return parent.width - (drawer.background.width * drawer.position) - width - Kirigami.Units.smallSpacing; default: return 0; } } Binding { when: root.handleAnchor && root.anchors.bottom target: root property: "y" value: root.handleAnchor ? root.handleAnchor.Kirigami.ScenePosition.y : 0 restoreMode: Binding.RestoreBinding } anchors { bottom: handleAnchor ? undefined : parent.bottom bottomMargin: { if (typeof applicationWindow === "undefined") { return undefined; } const window = applicationWindow(); let margin = Kirigami.Units.smallSpacing; if (window.footer) { margin = window.footer.height + Kirigami.Units.smallSpacing; } if (drawer.parent && drawer.height < drawer.parent.height) { margin = drawer.parent.height - drawer.height - drawer.y + Kirigami.Units.smallSpacing; } if (!window || !window.pageStack || !window.pageStack.contentItem || !window.pageStack.contentItem.itemAt) { return margin; } let item; if (window.pageStack.layers.depth > 1) { item = window.pageStack.layers.currentItem; } else { item = window.pageStack.contentItem.itemAt(window.pageStack.contentItem.contentX + x, 0); } // try to take the last item if (!item) { item = window.pageStack.lastItem; } let pageFooter = item && item.page ? item.page.footer : (item ? item.footer : undefined); if (pageFooter && drawer.parent) { margin = drawer.height < drawer.parent.height ? margin : margin + pageFooter.height } return margin; } Behavior on bottomMargin { NumberAnimation { duration: Kirigami.Units.shortDuration easing.type: Easing.InOutQuad } } } visible: drawer.enabled && drawer.modal && (drawer.edge === Qt.LeftEdge || drawer.edge === Qt.RightEdge) && opacity > 0 width: handleAnchor?.visible ? handleAnchor.width : Kirigami.Units.iconSizes.smallMedium + Kirigami.Units.smallSpacing * 2 height: handleAnchor?.visible ? handleAnchor.height : width // NOTE: check on pageStack.depth is to keep and hack elisa is doing working opacity: handleAnchor && applicationWindow()?.pageStack.depth > 0 ? drawer.position * (root.drawer as KT.OverlayDrawer).handleVisible : 1 transform: Translate { x: (root.drawer as KT.OverlayDrawer).handleVisible ? 0 : (root.drawer.edge === Qt.LeftEdge ? -Math.max(root.width, button.width) : Math.max(root.width, button.width)) Behavior on x { NumberAnimation { duration: Kirigami.Units.longDuration easing.type: !(root.drawer as KT.OverlayDrawer).handleVisible ? Easing.OutQuad : Easing.InQuad } } } }