Files
z-bar-qt/Components/CustomScrollBar.qml
T
2026-08-26 02:06:10 +02:00

146 lines
4.2 KiB
QML

pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Templates
import qs.Helpers
import ZShell.Config
ScrollBar {
id: root
required property Flickable flickable
readonly property bool isHorizontal: flickable && flickable.ScrollBar.horizontal === root
readonly property real axisSize: isHorizontal ? flickable.width : flickable.height
readonly property real axisContentSize: isHorizontal ? flickable.contentWidth : flickable.contentHeight
readonly property real axisContentPos: isHorizontal ? flickable.contentX : flickable.contentY
readonly property real axisLength: isHorizontal ? root.width : root.height
readonly property real effectiveSize: Math.max(nonAnimHeight, root.minimumSize)
readonly property real effectiveTravel: Math.max(0, 1 - root.effectiveSize)
readonly property real nonAnimHeight: root.axisSize / root.axisContentSize
readonly property real nonAnimY: root.axisContentPos / root.axisContentSize
readonly property real rawTravel: Math.max(0, 1 - root.nonAnimHeight)
readonly property bool reversed: isHorizontal ? (flickable instanceof ListView && flickable.layoutDirection === Qt.RightToLeft) : (flickable instanceof ListView && flickable.verticalLayoutDirection === ListView.BottomToTop)
property bool shouldBeActive
readonly property real travelScale: root.rawTravel > 0 ? root.effectiveTravel / root.rawTravel : 0
enabled: !Visibilities.getForActive().isDrawing
parent: flickable.parent
anchors.left: isHorizontal ? flickable.left : undefined
anchors.right: flickable.right
anchors.top: isHorizontal ? undefined : flickable.top
anchors.bottom: flickable.bottom
implicitWidth: isHorizontal ? 0 : Tokens.padding.extraSmall * 2
implicitHeight: isHorizontal ? Tokens.padding.extraSmall * 2 : 0
contentItem: Item {}
Behavior on position {
enabled: !fullMouse.pressed
Anim {}
}
onHoveredChanged: {
if (hovered)
shouldBeActive = hovered;
else
hideDelay.restart();
}
Connections {
function onMovingChanged() {
if (root.flickable.moving)
root.shouldBeActive = true;
else
hideDelay.restart();
}
target: root.flickable
}
Loader {
anchors.fill: parent
sourceComponent: root.isHorizontal ? horizontalTrack : verticalTrack
}
Component {
id: verticalTrack
VerticalScrollBarTrack {
scrollBar: root
mouseArea: fullMouse
}
}
Component {
id: horizontalTrack
HorizontalScrollBarTrack {
scrollBar: root
mouseArea: fullMouse
}
}
Timer {
id: hideDelay
interval: 600
onTriggered: root.shouldBeActive = root.flickable.moving || root.hovered
}
CustomMouseArea {
id: fullMouse
property real pressOffset: 0
function contentPosFromThumbStart(thumbStart) {
var visualPos = root.effectiveTravel > 0 ? thumbStart / root.travelScale : 0;
return root.reversed ? (visualPos - 1) * root.axisContentSize : visualPos * root.axisContentSize;
}
function updateFromEvent(event) {
var eventPos = root.isHorizontal ? event.x : event.y;
var posInTrack = eventPos / root.axisLength;
var thumbStart = posInTrack - pressOffset;
thumbStart = Math.max(0, Math.min(root.effectiveTravel, thumbStart));
var newPos = contentPosFromThumbStart(thumbStart);
if (root.isHorizontal)
root.flickable.contentX = newPos;
else
root.flickable.contentY = newPos;
}
function visualThumbStart() {
const visualPos = root.reversed ? (1 + root.nonAnimY) : root.nonAnimY;
return visualPos * root.travelScale;
}
anchors.fill: parent
cursorShape: undefined
hoverEnabled: true
preventStealing: true
onPositionChanged: event => {
if (pressed)
updateFromEvent(event);
}
onPressed: event => {
var currentStart = visualThumbStart();
var currentEnd = currentStart + root.effectiveSize;
var eventPos = root.isHorizontal ? event.x : event.y;
var clickPos = eventPos / root.axisLength;
var clickedInsideThumb = clickPos >= currentStart && clickPos <= currentEnd;
pressOffset = clickedInsideThumb ? (clickPos - currentStart) : root.effectiveSize / 2;
updateFromEvent(event);
}
onWheel: event => {
var delta = (root.isHorizontal ? event.angleDelta.x : event.angleDelta.y) > 0 ? -0.1 : 0.1;
var newPos = Math.max(0, Math.min(1 - root.size, root.position + delta));
root.position = newPos;
}
}
}