From 5c93d4a41a2cf12bcd6f2a17dcf71d0644678068 Mon Sep 17 00:00:00 2001 From: Ly-sec Date: Fri, 7 Nov 2025 22:42:50 +0100 Subject: [PATCH] SettingsPanel: add NListView to enable scrolling in sidepanel if needed --- Modules/Panels/Settings/SettingsPanel.qml | 149 +++++++++++----------- Widgets/NListView.qml | 53 +------- 2 files changed, 82 insertions(+), 120 deletions(-) diff --git a/Modules/Panels/Settings/SettingsPanel.qml b/Modules/Panels/Settings/SettingsPanel.qml index 40f8531e..540a75d2 100644 --- a/Modules/Panels/Settings/SettingsPanel.qml +++ b/Modules/Panels/Settings/SettingsPanel.qml @@ -360,92 +360,93 @@ SmartPanel { border.width: Style.borderS radius: Style.radiusM - MouseArea { - anchors.fill: parent - acceptedButtons: Qt.NoButton // Don't interfere with clicks - property int wheelAccumulator: 0 - onWheel: wheel => { - wheelAccumulator += wheel.angleDelta.y - if (wheelAccumulator >= 120) { - root.selectPreviousTab() - wheelAccumulator = 0 - } else if (wheelAccumulator <= -120) { - root.selectNextTab() - wheelAccumulator = 0 - } - wheel.accepted = true - } - } - - ColumnLayout { + NListView { + id: sidebarList anchors.fill: parent anchors.margins: Style.marginS + model: root.tabsModel spacing: Style.marginXS + currentIndex: root.currentTabIndex + verticalPolicy: ScrollBar.AsNeeded - Repeater { - id: sections - model: root.tabsModel - delegate: Rectangle { - id: tabItem - Layout.fillWidth: true - Layout.preferredHeight: tabEntryRow.implicitHeight + Style.marginM * 2 - radius: Style.radiusS - color: selected ? Color.mPrimary : (tabItem.hovering ? Color.mHover : Color.transparent) - readonly property bool selected: index === currentTabIndex - property bool hovering: false - property color tabTextColor: selected ? Color.mOnPrimary : (tabItem.hovering ? Color.mOnHover : Color.mOnSurface) + delegate: Rectangle { + id: tabItem + width: sidebarList.verticalScrollBarActive ? sidebarList.width - sidebarList.scrollBarWidth - Style.marginXS : sidebarList.width + height: tabEntryRow.implicitHeight + Style.marginM * 2 + radius: Style.radiusS + color: selected ? Color.mPrimary : (tabItem.hovering ? Color.mHover : Color.transparent) + readonly property bool selected: index === root.currentTabIndex + property bool hovering: false + property color tabTextColor: selected ? Color.mOnPrimary : (tabItem.hovering ? Color.mOnHover : Color.mOnSurface) - Behavior on color { - ColorAnimation { - duration: Style.animationFast - } + Behavior on width { + NumberAnimation { + duration: Style.animationFast + } + } + + Behavior on color { + ColorAnimation { + duration: Style.animationFast + } + } + + Behavior on tabTextColor { + ColorAnimation { + duration: Style.animationFast + } + } + + RowLayout { + id: tabEntryRow + anchors.fill: parent + anchors.leftMargin: Style.marginS + anchors.rightMargin: Style.marginS + spacing: Style.marginM + + // Tab icon + NIcon { + icon: modelData.icon + color: tabTextColor + pointSize: Style.fontSizeXL } - Behavior on tabTextColor { - ColorAnimation { - duration: Style.animationFast - } + // Tab label + NText { + text: I18n.tr(modelData.label) + color: tabTextColor + pointSize: Style.fontSizeM + font.weight: Style.fontWeightBold + Layout.fillWidth: true + Layout.alignment: Qt.AlignVCenter } + } - RowLayout { - id: tabEntryRow - anchors.fill: parent - anchors.leftMargin: Style.marginS - anchors.rightMargin: Style.marginS - spacing: Style.marginM - - // Tab icon - NIcon { - icon: modelData.icon - color: tabTextColor - pointSize: Style.fontSizeXL - } - - // Tab label - NText { - text: I18n.tr(modelData.label) - color: tabTextColor - pointSize: Style.fontSizeM - font.weight: Style.fontWeightBold - Layout.fillWidth: true - Layout.alignment: Qt.AlignVCenter - } - } - - MouseArea { - anchors.fill: parent - hoverEnabled: true - acceptedButtons: Qt.LeftButton - onEntered: tabItem.hovering = true - onExited: tabItem.hovering = false - onCanceled: tabItem.hovering = false - onClicked: currentTabIndex = index - } + MouseArea { + anchors.fill: parent + hoverEnabled: true + acceptedButtons: Qt.LeftButton + onEntered: tabItem.hovering = true + onExited: tabItem.hovering = false + onCanceled: tabItem.hovering = false + onClicked: root.currentTabIndex = index } } - Item { - Layout.fillHeight: true + onCurrentIndexChanged: { + if (currentIndex !== root.currentTabIndex) { + root.currentTabIndex = currentIndex + } + } + + Connections { + target: root + function onCurrentTabIndexChanged() { + if (sidebarList.currentIndex !== root.currentTabIndex) { + sidebarList.currentIndex = root.currentTabIndex + sidebarList.positionViewAtIndex(root.currentTabIndex, ListView.Contain) + } + } } } } diff --git a/Widgets/NListView.qml b/Widgets/NListView.qml index 9545bd2e..5fc13b90 100644 --- a/Widgets/NListView.qml +++ b/Widgets/NListView.qml @@ -13,7 +13,13 @@ Item { property real handleWidth: 6 property real handleRadius: Style.radiusM property int verticalPolicy: ScrollBar.AsNeeded - property int horizontalPolicy: ScrollBar.AsNeeded + property int horizontalPolicy: ScrollBar.AlwaysOff + readonly property bool verticalScrollBarActive: { + if (listView.ScrollBar.vertical.policy === ScrollBar.AlwaysOff) + return false + return listView.contentHeight > listView.height + } + readonly property real scrollBarWidth: verticalScrollBarActive ? handleWidth : 0 // Forward ListView properties property alias model: listView.model @@ -118,7 +124,6 @@ Item { x: listView.mirrored ? 0 : listView.width - width y: 0 height: listView.height - active: listView.ScrollBar.horizontal.active policy: root.verticalPolicy contentItem: Rectangle { @@ -155,49 +160,5 @@ Item { } } } - - 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 - } - } - } - } } }