diff --git a/quickshell/Modals/DankLauncherV2/Controller.qml b/quickshell/Modals/DankLauncherV2/Controller.qml index 57d16114..1517612a 100644 --- a/quickshell/Modals/DankLauncherV2/Controller.qml +++ b/quickshell/Modals/DankLauncherV2/Controller.qml @@ -42,6 +42,14 @@ Item { signal viewModeChanged(string sectionId, string mode) signal searchQueryRequested(string query) + onActiveChanged: { + if (!active) { + sections = []; + flatModel = []; + selectedItem = null; + } + } + Connections { target: SettingsData function onSortAppsAlphabeticallyChanged() { diff --git a/quickshell/Widgets/DankFlickable.qml b/quickshell/Widgets/DankFlickable.qml index e85d7878..6c93f3c2 100644 --- a/quickshell/Widgets/DankFlickable.qml +++ b/quickshell/Widgets/DankFlickable.qml @@ -1,21 +1,20 @@ import QtQuick import QtQuick.Controls import qs.Widgets +import "ScrollConstants.js" as Scroll Flickable { id: flickable property alias verticalScrollBar: vbar - property real mouseWheelSpeed: 60 + property real mouseWheelSpeed: Scroll.mouseWheelSpeed property real momentumVelocity: 0 property bool isMomentumActive: false - property real friction: 0.95 - property real minMomentumVelocity: 50 - property real maxMomentumVelocity: 2500 + property real friction: Scroll.friction property bool _scrollBarActive: false - flickDeceleration: 1500 - maximumFlickVelocity: 2000 + flickDeceleration: Scroll.flickDeceleration + maximumFlickVelocity: Scroll.maximumFlickVelocity boundsBehavior: Flickable.StopAtBounds boundsMovement: Flickable.FollowBoundsBehavior pressDelay: 0 @@ -24,8 +23,8 @@ Flickable { WheelHandler { id: wheelHandler - property real touchpadSpeed: 2.8 - property real momentumRetention: 0.92 + property real touchpadSpeed: Scroll.touchpadSpeed + property real momentumRetention: Scroll.momentumRetention property real lastWheelTime: 0 property real momentum: 0 property var velocitySamples: [] @@ -33,7 +32,7 @@ Flickable { function startMomentum() { flickable.isMomentumActive = true; - momentumTimer.start(); + momentumAnim.running = true; } acceptedDevices: PointerDevice.Mouse | PointerDevice.TouchPad @@ -54,7 +53,7 @@ Flickable { if (isTraditionalMouse) { sessionUsedMouseWheel = true; - momentumTimer.stop(); + momentumAnim.running = false; flickable.isMomentumActive = false; velocitySamples = []; momentum = 0; @@ -72,7 +71,7 @@ Flickable { flickable.contentY = newY; } else if (isHighDpiMouse) { sessionUsedMouseWheel = true; - momentumTimer.stop(); + momentumAnim.running = false; flickable.isMomentumActive = false; velocitySamples = []; momentum = 0; @@ -89,7 +88,7 @@ Flickable { flickable.contentY = newY; } else if (isTouchpad) { sessionUsedMouseWheel = false; - momentumTimer.stop(); + momentumAnim.running = false; flickable.isMomentumActive = false; let delta = event.pixelDelta.y * touchpadSpeed; @@ -98,18 +97,18 @@ Flickable { "delta": delta, "time": currentTime }); - velocitySamples = velocitySamples.filter(s => currentTime - s.time < 100); + velocitySamples = velocitySamples.filter(s => currentTime - s.time < Scroll.velocitySampleWindowMs); if (velocitySamples.length > 1) { const totalDelta = velocitySamples.reduce((sum, s) => sum + s.delta, 0); const timeSpan = currentTime - velocitySamples[0].time; if (timeSpan > 0) { - flickable.momentumVelocity = Math.max(-flickable.maxMomentumVelocity, Math.min(flickable.maxMomentumVelocity, totalDelta / timeSpan * 1000)); + flickable.momentumVelocity = Math.max(-Scroll.maxMomentumVelocity, Math.min(Scroll.maxMomentumVelocity, totalDelta / timeSpan * 1000)); } } - if (timeDelta < 50) { - momentum = momentum * momentumRetention + delta * 0.15; + if (timeDelta < Scroll.momentumTimeThreshold) { + momentum = momentum * momentumRetention + delta * Scroll.momentumDeltaFactor; delta += momentum; } else { momentum = 0; @@ -130,7 +129,7 @@ Flickable { onActiveChanged: { if (!active) { - if (!sessionUsedMouseWheel && Math.abs(flickable.momentumVelocity) >= flickable.minMomentumVelocity) { + if (!sessionUsedMouseWheel && Math.abs(flickable.momentumVelocity) >= Scroll.minMomentumVelocity) { startMomentum(); } else { velocitySamples = []; @@ -146,42 +145,34 @@ Flickable { } onMovementEnded: vbar.hideTimer.restart() - Timer { - id: momentumTimer - interval: 16 - repeat: true + FrameAnimation { + id: momentumAnim + running: false onTriggered: { - const newY = flickable.contentY - flickable.momentumVelocity * 0.016; + const dt = frameTime; + const newY = flickable.contentY - flickable.momentumVelocity * dt; const maxY = Math.max(0, flickable.contentHeight - flickable.height); if (newY < 0 || newY > maxY) { flickable.contentY = newY < 0 ? 0 : maxY; - stop(); + running = false; flickable.isMomentumActive = false; flickable.momentumVelocity = 0; return; } flickable.contentY = newY; - flickable.momentumVelocity *= flickable.friction; + flickable.momentumVelocity *= Math.pow(flickable.friction, dt / 0.016); - if (Math.abs(flickable.momentumVelocity) < 5) { - stop(); + if (Math.abs(flickable.momentumVelocity) < Scroll.momentumStopThreshold) { + running = false; flickable.isMomentumActive = false; flickable.momentumVelocity = 0; } } } - NumberAnimation { - id: returnToBoundsAnimation - target: flickable - property: "contentY" - duration: 300 - easing.type: Easing.OutQuad - } - ScrollBar.vertical: DankScrollbar { id: vbar } diff --git a/quickshell/Widgets/DankGridView.qml b/quickshell/Widgets/DankGridView.qml index 8fee01b4..c670d0fe 100644 --- a/quickshell/Widgets/DankGridView.qml +++ b/quickshell/Widgets/DankGridView.qml @@ -1,18 +1,17 @@ import QtQuick import QtQuick.Controls import qs.Widgets +import "ScrollConstants.js" as Scroll GridView { id: gridView property real momentumVelocity: 0 property bool isMomentumActive: false - property real friction: 0.95 - property real minMomentumVelocity: 50 - property real maxMomentumVelocity: 2500 + property real friction: Scroll.friction - flickDeceleration: 1500 - maximumFlickVelocity: 2000 + flickDeceleration: Scroll.flickDeceleration + maximumFlickVelocity: Scroll.maximumFlickVelocity boundsBehavior: Flickable.StopAtBounds boundsMovement: Flickable.FollowBoundsBehavior pressDelay: 0 @@ -27,9 +26,9 @@ GridView { WheelHandler { id: wheelHandler - property real mouseWheelSpeed: 60 - property real touchpadSpeed: 2.8 - property real momentumRetention: 0.92 + property real mouseWheelSpeed: Scroll.mouseWheelSpeed + property real touchpadSpeed: Scroll.touchpadSpeed + property real momentumRetention: Scroll.momentumRetention property real lastWheelTime: 0 property real momentum: 0 property var velocitySamples: [] @@ -37,7 +36,7 @@ GridView { function startMomentum() { isMomentumActive = true; - momentumTimer.start(); + momentumAnim.running = true; } acceptedDevices: PointerDevice.Mouse | PointerDevice.TouchPad @@ -57,7 +56,7 @@ GridView { if (isTraditionalMouse) { sessionUsedMouseWheel = true; - momentumTimer.stop(); + momentumAnim.running = false; isMomentumActive = false; velocitySamples = []; momentum = 0; @@ -75,7 +74,7 @@ GridView { contentY = newY; } else if (isHighDpiMouse) { sessionUsedMouseWheel = true; - momentumTimer.stop(); + momentumAnim.running = false; isMomentumActive = false; velocitySamples = []; momentum = 0; @@ -92,7 +91,7 @@ GridView { contentY = newY; } else if (isTouchpad) { sessionUsedMouseWheel = false; - momentumTimer.stop(); + momentumAnim.running = false; isMomentumActive = false; let delta = event.pixelDelta.y * touchpadSpeed; @@ -101,18 +100,18 @@ GridView { "delta": delta, "time": currentTime }); - velocitySamples = velocitySamples.filter(s => currentTime - s.time < 100); + velocitySamples = velocitySamples.filter(s => currentTime - s.time < Scroll.velocitySampleWindowMs); if (velocitySamples.length > 1) { const totalDelta = velocitySamples.reduce((sum, s) => sum + s.delta, 0); const timeSpan = currentTime - velocitySamples[0].time; if (timeSpan > 0) { - momentumVelocity = Math.max(-maxMomentumVelocity, Math.min(maxMomentumVelocity, totalDelta / timeSpan * 1000)); + momentumVelocity = Math.max(-Scroll.maxMomentumVelocity, Math.min(Scroll.maxMomentumVelocity, totalDelta / timeSpan * 1000)); } } - if (timeDelta < 50) { - momentum = momentum * momentumRetention + delta * 0.15; + if (timeDelta < Scroll.momentumTimeThreshold) { + momentum = momentum * momentumRetention + delta * Scroll.momentumDeltaFactor; delta += momentum; } else { momentum = 0; @@ -132,7 +131,7 @@ GridView { } onActiveChanged: { if (!active) { - if (!sessionUsedMouseWheel && Math.abs(momentumVelocity) >= minMomentumVelocity) { + if (!sessionUsedMouseWheel && Math.abs(momentumVelocity) >= Scroll.minMomentumVelocity) { startMomentum(); } else { velocitySamples = []; @@ -142,41 +141,34 @@ GridView { } } - Timer { - id: momentumTimer - interval: 16 - repeat: true + FrameAnimation { + id: momentumAnim + running: false + onTriggered: { - const newY = contentY - momentumVelocity * 0.016; + const dt = frameTime; + const newY = contentY - momentumVelocity * dt; const maxY = Math.max(0, contentHeight - height); if (newY < 0 || newY > maxY) { contentY = newY < 0 ? 0 : maxY; - stop(); + running = false; isMomentumActive = false; momentumVelocity = 0; return; } contentY = newY; - momentumVelocity *= friction; + momentumVelocity *= Math.pow(friction, dt / 0.016); - if (Math.abs(momentumVelocity) < 5) { - stop(); + if (Math.abs(momentumVelocity) < Scroll.momentumStopThreshold) { + running = false; isMomentumActive = false; momentumVelocity = 0; } } } - NumberAnimation { - id: returnToBoundsAnimation - target: gridView - property: "contentY" - duration: 300 - easing.type: Easing.OutQuad - } - ScrollBar.vertical: DankScrollbar { id: vbar } diff --git a/quickshell/Widgets/DankListView.qml b/quickshell/Widgets/DankListView.qml index 888de7c7..41bdc9b6 100644 --- a/quickshell/Widgets/DankListView.qml +++ b/quickshell/Widgets/DankListView.qml @@ -2,23 +2,22 @@ import QtQuick import QtQuick.Controls import qs.Common import qs.Widgets +import "ScrollConstants.js" as Scroll ListView { id: listView property real scrollBarTopMargin: 0 - property real mouseWheelSpeed: 60 + property real mouseWheelSpeed: Scroll.mouseWheelSpeed property real savedY: 0 property bool justChanged: false property bool isUserScrolling: false property real momentumVelocity: 0 property bool isMomentumActive: false - property real friction: 0.95 - property real minMomentumVelocity: 50 - property real maxMomentumVelocity: 2500 + property real friction: Scroll.friction - flickDeceleration: 1500 - maximumFlickVelocity: 2000 + flickDeceleration: Scroll.flickDeceleration + maximumFlickVelocity: Scroll.maximumFlickVelocity boundsBehavior: Flickable.StopAtBounds boundsMovement: Flickable.FollowBoundsBehavior pressDelay: 0 @@ -53,7 +52,7 @@ ListView { WheelHandler { id: wheelHandler - property real touchpadSpeed: 2.8 + property real touchpadSpeed: Scroll.touchpadSpeed property real lastWheelTime: 0 property real momentum: 0 property var velocitySamples: [] @@ -61,7 +60,7 @@ ListView { function startMomentum() { isMomentumActive = true; - momentumTimer.start(); + momentumAnim.running = true; } acceptedDevices: PointerDevice.Mouse | PointerDevice.TouchPad @@ -83,7 +82,7 @@ ListView { if (isTraditionalMouse) { sessionUsedMouseWheel = true; - momentumTimer.stop(); + momentumAnim.running = false; isMomentumActive = false; velocitySamples = []; momentum = 0; @@ -103,7 +102,7 @@ ListView { savedY = newY; } else if (isHighDpiMouse) { sessionUsedMouseWheel = true; - momentumTimer.stop(); + momentumAnim.running = false; isMomentumActive = false; velocitySamples = []; momentum = 0; @@ -122,7 +121,7 @@ ListView { savedY = newY; } else if (isTouchpad) { sessionUsedMouseWheel = false; - momentumTimer.stop(); + momentumAnim.running = false; isMomentumActive = false; let delta = event.pixelDelta.y * touchpadSpeed; @@ -131,18 +130,18 @@ ListView { "delta": delta, "time": currentTime }); - velocitySamples = velocitySamples.filter(s => currentTime - s.time < 100); + velocitySamples = velocitySamples.filter(s => currentTime - s.time < Scroll.velocitySampleWindowMs); if (velocitySamples.length > 1) { const totalDelta = velocitySamples.reduce((sum, s) => sum + s.delta, 0); const timeSpan = currentTime - velocitySamples[0].time; if (timeSpan > 0) { - momentumVelocity = Math.max(-maxMomentumVelocity, Math.min(maxMomentumVelocity, totalDelta / timeSpan * 1000)); + momentumVelocity = Math.max(-Scroll.maxMomentumVelocity, Math.min(Scroll.maxMomentumVelocity, totalDelta / timeSpan * 1000)); } } - if (timeDelta < 50) { - momentum = momentum * 0.92 + delta * 0.15; + if (timeDelta < Scroll.momentumTimeThreshold) { + momentum = momentum * Scroll.momentumRetention + delta * Scroll.momentumDeltaFactor; delta += momentum; } else { momentum = 0; @@ -166,7 +165,7 @@ ListView { onActiveChanged: { if (!active) { isUserScrolling = false; - if (!sessionUsedMouseWheel && Math.abs(momentumVelocity) >= minMomentumVelocity) { + if (!sessionUsedMouseWheel && Math.abs(momentumVelocity) >= Scroll.minMomentumVelocity) { startMomentum(); } else { velocitySamples = []; @@ -176,20 +175,20 @@ ListView { } } - Timer { - id: momentumTimer - interval: 16 - repeat: true + FrameAnimation { + id: momentumAnim + running: false onTriggered: { - const newY = contentY - momentumVelocity * 0.016; + const dt = frameTime; + const newY = contentY - momentumVelocity * dt; const maxY = Math.max(0, contentHeight - height + originY); const minY = originY; if (newY < minY || newY > maxY) { contentY = newY < minY ? minY : maxY; savedY = contentY; - stop(); + running = false; isMomentumActive = false; momentumVelocity = 0; return; @@ -197,10 +196,10 @@ ListView { contentY = newY; savedY = newY; - momentumVelocity *= friction; + momentumVelocity *= Math.pow(friction, dt / 0.016); - if (Math.abs(momentumVelocity) < 5) { - stop(); + if (Math.abs(momentumVelocity) < Scroll.momentumStopThreshold) { + running = false; isMomentumActive = false; momentumVelocity = 0; } diff --git a/quickshell/Widgets/ScrollConstants.js b/quickshell/Widgets/ScrollConstants.js new file mode 100644 index 00000000..22d314fa --- /dev/null +++ b/quickshell/Widgets/ScrollConstants.js @@ -0,0 +1,14 @@ +.pragma library + +const friction = 0.96; +const touchpadSpeed = 3.5; +const mouseWheelSpeed = 60; +const momentumRetention = 0.92; +const momentumDeltaFactor = 0.15; +const maxMomentumVelocity = 2500; +const minMomentumVelocity = 50; +const momentumStopThreshold = 5; +const velocitySampleWindowMs = 100; +const momentumTimeThreshold = 50; +const flickDeceleration = 1500; +const maximumFlickVelocity = 2000;