From 4067896434e16e3a0da215be4484d045edb6016d Mon Sep 17 00:00:00 2001 From: LemmyCook Date: Thu, 11 Sep 2025 17:56:47 -0400 Subject: [PATCH] New components: NScrollView + NListView Allow controlling the handle color and stuf... --- Widgets/NListView.qml | 203 ++++++++++++++++++++++++++++++++++++++++ Widgets/NScrollView.qml | 107 +++++++++++++++++++++ 2 files changed, 310 insertions(+) create mode 100644 Widgets/NListView.qml create mode 100644 Widgets/NScrollView.qml diff --git a/Widgets/NListView.qml b/Widgets/NListView.qml new file mode 100644 index 0000000..6731d7c --- /dev/null +++ b/Widgets/NListView.qml @@ -0,0 +1,203 @@ +import QtQuick +import QtQuick.Controls +import QtQuick.Templates as T +import qs.Commons + +Item { + id: root + + property color handleColor: Qt.alpha(Color.mTertiary, 0.8) + property color handleHoverColor: handleColor + property color handlePressedColor: handleColor + property color trackColor: Color.transparent + property real handleWidth: 6 * scaling + property real handleRadius: Style.radiusM * scaling + property int verticalPolicy: ScrollBar.AsNeeded + property int horizontalPolicy: ScrollBar.AsNeeded + + // Forward ListView properties + property alias model: listView.model + property alias delegate: listView.delegate + property alias spacing: listView.spacing + property alias orientation: listView.orientation + property alias currentIndex: listView.currentIndex + property alias count: listView.count + property alias contentHeight: listView.contentHeight + property alias contentWidth: listView.contentWidth + property alias contentY: listView.contentY + property alias contentX: listView.contentX + property alias currentItem: listView.currentItem + property alias highlightItem: listView.highlightItem + property alias headerItem: listView.headerItem + property alias footerItem: listView.footerItem + property alias section: listView.section + property alias highlightFollowsCurrentItem: listView.highlightFollowsCurrentItem + property alias highlightMoveDuration: listView.highlightMoveDuration + property alias highlightMoveVelocity: listView.highlightMoveVelocity + property alias preferredHighlightBegin: listView.preferredHighlightBegin + property alias preferredHighlightEnd: listView.preferredHighlightEnd + property alias highlightRangeMode: listView.highlightRangeMode + property alias snapMode: listView.snapMode + property alias keyNavigationWraps: listView.keyNavigationWraps + property alias cacheBuffer: listView.cacheBuffer + property alias displayMarginBeginning: listView.displayMarginBeginning + property alias displayMarginEnd: listView.displayMarginEnd + property alias layoutDirection: listView.layoutDirection + property alias effectiveLayoutDirection: listView.effectiveLayoutDirection + property alias verticalLayoutDirection: listView.verticalLayoutDirection + property alias boundsBehavior: listView.boundsBehavior + property alias flickableDirection: listView.flickableDirection + property alias interactive: listView.interactive + property alias moving: listView.moving + property alias flicking: listView.flicking + property alias dragging: listView.dragging + property alias horizontalVelocity: listView.horizontalVelocity + property alias verticalVelocity: listView.verticalVelocity + + // Forward ListView methods + function positionViewAtIndex(index, mode) { + listView.positionViewAtIndex(index, mode) + } + + function positionViewAtBeginning() { + listView.positionViewAtBeginning() + } + + function positionViewAtEnd() { + listView.positionViewAtEnd() + } + + function forceLayout() { + listView.forceLayout() + } + + function cancelFlick() { + listView.cancelFlick() + } + + function flick(xVelocity, yVelocity) { + listView.flick(xVelocity, yVelocity) + } + + function incrementCurrentIndex() { + listView.incrementCurrentIndex() + } + + function decrementCurrentIndex() { + listView.decrementCurrentIndex() + } + + function indexAt(x, y) { + return listView.indexAt(x, y) + } + + function itemAt(x, y) { + return listView.itemAt(x, y) + } + + function itemAtIndex(index) { + return listView.itemAtIndex(index) + } + + // Set reasonable implicit sizes for Layout usage + implicitWidth: 200 + implicitHeight: 200 + + ListView { + id: listView + anchors.fill: parent + + // Enable clipping to keep content within bounds + clip: true + + // Enable flickable for smooth scrolling + boundsBehavior: Flickable.StopAtBounds + + ScrollBar.vertical: ScrollBar { + parent: listView + x: listView.mirrored ? 0 : listView.width - width + y: 0 + height: listView.height + active: listView.ScrollBar.horizontal.active + policy: root.verticalPolicy + + contentItem: Rectangle { + implicitWidth: root.handleWidth + implicitHeight: 100 + radius: root.handleRadius + color: parent.pressed ? root.handlePressedColor : parent.hovered ? root.handleHoverColor : root.handleColor + opacity: parent.policy === ScrollBar.AlwaysOn || parent.active ? 1.0 : 0.0 + + Behavior on opacity { + NumberAnimation { + duration: Style.animationFast + } + } + + Behavior on color { + ColorAnimation { + duration: Style.animationFast + } + } + } + + background: Rectangle { + implicitWidth: root.handleWidth + implicitHeight: 100 + color: root.trackColor + opacity: parent.policy === ScrollBar.AlwaysOn || parent.active ? 0.3 : 0.0 + radius: root.handleRadius / 2 + + Behavior on opacity { + NumberAnimation { + duration: Style.animationFast + } + } + } + } + + ScrollBar.horizontal: ScrollBar { + id: horizontalScrollBar + parent: listView + x: 0 + y: listView.height - height + width: listView.width + active: listView.ScrollBar.vertical.active + policy: root.horizontalPolicy + + contentItem: Rectangle { + implicitWidth: 100 + implicitHeight: root.handleWidth + radius: root.handleRadius + color: parent.pressed ? root.handlePressedColor : parent.hovered ? root.handleHoverColor : root.handleColor + opacity: parent.policy === ScrollBar.AlwaysOn || parent.active ? 1.0 : 0.0 + + Behavior on opacity { + NumberAnimation { + duration: Style.animationFast + } + } + + Behavior on color { + ColorAnimation { + duration: Style.animationFast + } + } + } + + background: Rectangle { + implicitWidth: 100 + implicitHeight: root.handleWidth + color: root.trackColor + opacity: parent.policy === ScrollBar.AlwaysOn || parent.active ? 0.3 : 0.0 + radius: root.handleRadius / 2 + + Behavior on opacity { + NumberAnimation { + duration: Style.animationFast + } + } + } + } + } +} diff --git a/Widgets/NScrollView.qml b/Widgets/NScrollView.qml new file mode 100644 index 0000000..feec375 --- /dev/null +++ b/Widgets/NScrollView.qml @@ -0,0 +1,107 @@ +import QtQuick +import QtQuick.Controls +import QtQuick.Templates as T +import qs.Commons + +T.ScrollView { + id: root + + property color handleColor: Qt.alpha(Color.mTertiary, 0.8) + property color handleHoverColor: handleColor + property color handlePressedColor: handleColor + property color trackColor: Color.transparent + property real handleWidth: 6 * scaling + property real handleRadius: Style.radiusM * scaling + property int verticalPolicy: ScrollBar.AsNeeded + property int horizontalPolicy: ScrollBar.AsNeeded + + implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset, contentWidth + leftPadding + rightPadding) + implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset, + contentHeight + topPadding + bottomPadding) + + ScrollBar.vertical: ScrollBar { + parent: root + x: root.mirrored ? 0 : root.width - width + y: root.topPadding + height: root.availableHeight + active: root.ScrollBar.horizontal.active + policy: root.verticalPolicy + + contentItem: Rectangle { + implicitWidth: root.handleWidth + implicitHeight: 100 + radius: root.handleRadius + color: parent.pressed ? root.handlePressedColor : parent.hovered ? root.handleHoverColor : root.handleColor + opacity: parent.policy === ScrollBar.AlwaysOn || parent.active ? 1.0 : 0.0 + + Behavior on opacity { + NumberAnimation { + duration: Style.animationFast + } + } + + Behavior on color { + ColorAnimation { + duration: Style.animationFast + } + } + } + + background: Rectangle { + implicitWidth: root.handleWidth + implicitHeight: 100 + color: root.trackColor + opacity: parent.policy === ScrollBar.AlwaysOn || parent.active ? 0.3 : 0.0 + radius: root.handleRadius / 2 + + Behavior on opacity { + NumberAnimation { + duration: Style.animationFast + } + } + } + } + + ScrollBar.horizontal: ScrollBar { + parent: root + x: root.leftPadding + y: root.height - height + width: root.availableWidth + active: root.ScrollBar.vertical.active + policy: root.horizontalPolicy + + contentItem: Rectangle { + implicitWidth: 100 + implicitHeight: root.handleWidth + radius: root.handleRadius + color: parent.pressed ? root.handlePressedColor : parent.hovered ? root.handleHoverColor : root.handleColor + opacity: parent.policy === ScrollBar.AlwaysOn || parent.active ? 1.0 : 0.0 + + Behavior on opacity { + NumberAnimation { + duration: Style.animationFast + } + } + + Behavior on color { + ColorAnimation { + duration: Style.animationFast + } + } + } + + background: Rectangle { + implicitWidth: 100 + implicitHeight: root.handleWidth + color: root.trackColor + opacity: parent.policy === ScrollBar.AlwaysOn || parent.active ? 0.3 : 0.0 + radius: root.handleRadius / 2 + + Behavior on opacity { + NumberAnimation { + duration: Style.animationFast + } + } + } + } +}