mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-01-25 14:02:53 -05:00
de-dupe scrollview
This commit is contained in:
@@ -501,29 +501,46 @@ DankModal {
|
||||
border.width: 1
|
||||
clip: true
|
||||
|
||||
ScrollView {
|
||||
ListView {
|
||||
id: clipboardListView
|
||||
|
||||
anchors.fill: parent
|
||||
anchors.margins: Theme.spacingS
|
||||
clip: true
|
||||
ScrollBar.vertical.policy: ScrollBar.AsNeeded
|
||||
ScrollBar.horizontal.policy: ScrollBar.AlwaysOff
|
||||
model: filteredClipboardModel
|
||||
spacing: Theme.spacingXS
|
||||
|
||||
ListView {
|
||||
id: clipboardListView
|
||||
ScrollBar.vertical: ScrollBar { policy: ScrollBar.AsNeeded }
|
||||
ScrollBar.horizontal: ScrollBar { policy: ScrollBar.AlwaysOff }
|
||||
|
||||
width: parent.availableWidth
|
||||
model: filteredClipboardModel
|
||||
spacing: Theme.spacingXS
|
||||
property real wheelMultiplier: 1.8
|
||||
property int wheelBaseStep: 160
|
||||
|
||||
StyledText {
|
||||
text: "No clipboard entries found"
|
||||
anchors.centerIn: parent
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Theme.surfaceVariantText
|
||||
visible: filteredClipboardModel.count === 0
|
||||
WheelHandler {
|
||||
target: null
|
||||
onWheel: (ev) => {
|
||||
let dy = ev.pixelDelta.y !== 0
|
||||
? ev.pixelDelta.y
|
||||
: (ev.angleDelta.y / 120) * clipboardListView.wheelBaseStep;
|
||||
if (ev.inverted) dy = -dy;
|
||||
|
||||
const maxY = Math.max(0, clipboardListView.contentHeight - clipboardListView.height);
|
||||
clipboardListView.contentY = Math.max(0, Math.min(maxY,
|
||||
clipboardListView.contentY - dy * clipboardListView.wheelMultiplier));
|
||||
|
||||
ev.accepted = true;
|
||||
}
|
||||
}
|
||||
|
||||
delegate: Rectangle {
|
||||
StyledText {
|
||||
text: "No clipboard entries found"
|
||||
anchors.centerIn: parent
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Theme.surfaceVariantText
|
||||
visible: filteredClipboardModel.count === 0
|
||||
}
|
||||
|
||||
delegate: Rectangle {
|
||||
property string entryType: getEntryType(model.entry)
|
||||
property string entryPreview: getEntryPreview(model.entry)
|
||||
property int entryIndex: index + 1
|
||||
@@ -729,8 +746,6 @@ DankModal {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -198,21 +198,41 @@ DankModal {
|
||||
}
|
||||
|
||||
// File grid
|
||||
ScrollView {
|
||||
GridView {
|
||||
id: fileGrid
|
||||
|
||||
width: parent.width
|
||||
height: parent.height - 80
|
||||
clip: true
|
||||
cellWidth: 150
|
||||
cellHeight: 130
|
||||
cacheBuffer: 260
|
||||
|
||||
model: folderModel
|
||||
|
||||
GridView {
|
||||
id: fileGrid
|
||||
|
||||
cellWidth: 150
|
||||
cellHeight: 130
|
||||
cacheBuffer: 260 // Only cache ~2 rows worth of items
|
||||
|
||||
model: folderModel
|
||||
ScrollBar.vertical: ScrollBar { policy: ScrollBar.AsNeeded }
|
||||
ScrollBar.horizontal: ScrollBar { policy: ScrollBar.AlwaysOff }
|
||||
|
||||
delegate: StyledRect {
|
||||
property real wheelMultiplier: 1.8
|
||||
property int wheelBaseStep: 160
|
||||
|
||||
WheelHandler {
|
||||
target: null
|
||||
onWheel: (ev) => {
|
||||
let dy = ev.pixelDelta.y !== 0
|
||||
? ev.pixelDelta.y
|
||||
: (ev.angleDelta.y / 120) * fileGrid.wheelBaseStep;
|
||||
if (ev.inverted) dy = -dy;
|
||||
|
||||
const maxY = Math.max(0, fileGrid.contentHeight - fileGrid.height);
|
||||
fileGrid.contentY = Math.max(0, Math.min(maxY,
|
||||
fileGrid.contentY - dy * fileGrid.wheelMultiplier));
|
||||
|
||||
ev.accepted = true;
|
||||
}
|
||||
}
|
||||
|
||||
delegate: StyledRect {
|
||||
id: delegateRoot
|
||||
|
||||
required property bool fileIsDir
|
||||
@@ -292,7 +312,6 @@ DankModal {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -91,18 +91,36 @@ DankModal {
|
||||
}
|
||||
|
||||
// Network Details
|
||||
ScrollView {
|
||||
Flickable {
|
||||
width: parent.width
|
||||
height: parent.height - 140
|
||||
clip: true
|
||||
ScrollBar.vertical.policy: ScrollBar.AsNeeded
|
||||
ScrollBar.horizontal.policy: ScrollBar.AlwaysOff
|
||||
contentWidth: width
|
||||
contentHeight: detailsRect.height
|
||||
|
||||
Flickable {
|
||||
contentWidth: parent.width
|
||||
contentHeight: detailsRect.height
|
||||
ScrollBar.vertical: ScrollBar { policy: ScrollBar.AsNeeded }
|
||||
ScrollBar.horizontal: ScrollBar { policy: ScrollBar.AlwaysOff }
|
||||
|
||||
Rectangle {
|
||||
property real wheelMultiplier: 1.8
|
||||
property int wheelBaseStep: 160
|
||||
|
||||
WheelHandler {
|
||||
target: null
|
||||
onWheel: (ev) => {
|
||||
let dy = ev.pixelDelta.y !== 0
|
||||
? ev.pixelDelta.y
|
||||
: (ev.angleDelta.y / 120) * parent.wheelBaseStep;
|
||||
if (ev.inverted) dy = -dy;
|
||||
|
||||
const maxY = Math.max(0, parent.contentHeight - parent.height);
|
||||
parent.contentY = Math.max(0, Math.min(maxY,
|
||||
parent.contentY - dy * parent.wheelMultiplier));
|
||||
|
||||
ev.accepted = true;
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: detailsRect
|
||||
|
||||
width: parent.width
|
||||
@@ -124,8 +142,6 @@ DankModal {
|
||||
lineHeight: 1.5
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ Rectangle {
|
||||
property var process: null
|
||||
property var contextMenu: null
|
||||
|
||||
width: parent.width
|
||||
width: parent ? parent.width : 0
|
||||
height: 40
|
||||
radius: Theme.cornerRadiusLarge
|
||||
color: processMouseArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08) : "transparent"
|
||||
|
||||
@@ -45,7 +45,11 @@ Column {
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: SysMonitorService.setSortBy("name")
|
||||
onClicked: {
|
||||
processListView.captureAnchor();
|
||||
SysMonitorService.setSortBy("name");
|
||||
processListView.restoreAnchor();
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on color {
|
||||
@@ -76,7 +80,11 @@ Column {
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: SysMonitorService.setSortBy("cpu")
|
||||
onClicked: {
|
||||
processListView.captureAnchor();
|
||||
SysMonitorService.setSortBy("cpu");
|
||||
processListView.restoreAnchor();
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on color {
|
||||
@@ -107,7 +115,11 @@ Column {
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: SysMonitorService.setSortBy("memory")
|
||||
onClicked: {
|
||||
processListView.captureAnchor();
|
||||
SysMonitorService.setSortBy("memory");
|
||||
processListView.restoreAnchor();
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on color {
|
||||
@@ -139,7 +151,11 @@ Column {
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: SysMonitorService.setSortBy("pid")
|
||||
onClicked: {
|
||||
processListView.captureAnchor();
|
||||
SysMonitorService.setSortBy("pid");
|
||||
processListView.restoreAnchor();
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on color {
|
||||
@@ -169,7 +185,11 @@ Column {
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: SysMonitorService.toggleSortOrder()
|
||||
onClicked: {
|
||||
processListView.captureAnchor();
|
||||
SysMonitorService.toggleSortOrder();
|
||||
processListView.restoreAnchor();
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on color {
|
||||
@@ -183,23 +203,74 @@ Column {
|
||||
|
||||
}
|
||||
|
||||
ScrollView {
|
||||
ListView {
|
||||
id: processListView
|
||||
|
||||
width: parent.width
|
||||
height: parent.height - 24 // Subtract header height
|
||||
height: parent.height - columnHeaders.height
|
||||
clip: true
|
||||
ScrollBar.vertical.policy: ScrollBar.AsNeeded
|
||||
ScrollBar.horizontal.policy: ScrollBar.AlwaysOff
|
||||
spacing: 4
|
||||
model: SysMonitorService.processes
|
||||
|
||||
ListView {
|
||||
id: processListView
|
||||
delegate: ProcessListItem {
|
||||
process: modelData
|
||||
contextMenu: root.contextMenu
|
||||
}
|
||||
|
||||
anchors.fill: parent
|
||||
model: SysMonitorService.processes
|
||||
spacing: 4
|
||||
ScrollBar.vertical: ScrollBar { policy: ScrollBar.AsNeeded }
|
||||
ScrollBar.horizontal: ScrollBar { policy: ScrollBar.AlwaysOff }
|
||||
|
||||
delegate: ProcessListItem {
|
||||
process: modelData
|
||||
contextMenu: root.contextMenu
|
||||
property real wheelMultiplier: 1.8
|
||||
property int wheelBaseStep: 160
|
||||
|
||||
WheelHandler {
|
||||
target: null
|
||||
onWheel: (ev) => {
|
||||
let dy = ev.pixelDelta.y !== 0
|
||||
? ev.pixelDelta.y
|
||||
: (ev.angleDelta.y / 120) * processListView.wheelBaseStep;
|
||||
if (ev.inverted) dy = -dy;
|
||||
|
||||
const maxY = Math.max(0, processListView.contentHeight - processListView.height);
|
||||
processListView.contentY = Math.max(0, Math.min(maxY,
|
||||
processListView.contentY - dy * processListView.wheelMultiplier));
|
||||
|
||||
ev.accepted = true;
|
||||
}
|
||||
}
|
||||
|
||||
property string keyRoleName: "pid"
|
||||
property var _anchorKey: undefined
|
||||
property real _anchorOffset: 0
|
||||
|
||||
function captureAnchor() {
|
||||
const y = contentY + 1;
|
||||
const idx = indexAt(0, y);
|
||||
if (idx < 0 || !model || idx >= model.length) return;
|
||||
_anchorKey = model[idx][keyRoleName];
|
||||
const it = itemAtIndex(idx);
|
||||
_anchorOffset = it ? (y - it.y) : 0;
|
||||
}
|
||||
|
||||
function restoreAnchor() {
|
||||
Qt.callLater(function() {
|
||||
if (_anchorKey === undefined || !model) return;
|
||||
|
||||
var i = -1;
|
||||
for (var j = 0; j < model.length; ++j) {
|
||||
if (model[j][keyRoleName] === _anchorKey) { i = j; break; }
|
||||
}
|
||||
if (i < 0) return;
|
||||
|
||||
positionViewAtIndex(i, ListView.Beginning);
|
||||
const maxY = Math.max(0, contentHeight - height);
|
||||
contentY = Math.max(0, Math.min(maxY, contentY + _anchorOffset - 1));
|
||||
});
|
||||
}
|
||||
|
||||
onModelChanged: {
|
||||
if (model && model.length > 0) {
|
||||
restoreAnchor();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,55 @@ Singleton {
|
||||
|
||||
signal volumeChanged()
|
||||
|
||||
function displayName(node) {
|
||||
if (!node) return ""
|
||||
|
||||
if (node.properties && node.properties["device.description"]) {
|
||||
return node.properties["device.description"]
|
||||
}
|
||||
|
||||
if (node.description && node.description !== node.name) {
|
||||
return node.description
|
||||
}
|
||||
|
||||
if (node.nickname && node.nickname !== node.name) {
|
||||
return node.nickname
|
||||
}
|
||||
|
||||
if (node.name.includes("analog-stereo")) return "Built-in Speakers"
|
||||
else if (node.name.includes("bluez")) return "Bluetooth Audio"
|
||||
else if (node.name.includes("usb")) return "USB Audio"
|
||||
else if (node.name.includes("hdmi")) return "HDMI Audio"
|
||||
|
||||
return node.name
|
||||
}
|
||||
|
||||
function subtitle(name) {
|
||||
if (!name) return ""
|
||||
|
||||
if (name.includes('usb-')) {
|
||||
if (name.includes('SteelSeries')) {
|
||||
return "USB Gaming Headset"
|
||||
} else if (name.includes('Generic')) {
|
||||
return "USB Audio Device"
|
||||
}
|
||||
return "USB Audio"
|
||||
} else if (name.includes('pci-')) {
|
||||
if (name.includes('01_00.1') || name.includes('01:00.1')) {
|
||||
return "NVIDIA GPU Audio"
|
||||
}
|
||||
return "PCI Audio"
|
||||
} else if (name.includes('bluez')) {
|
||||
return "Bluetooth Audio"
|
||||
} else if (name.includes('analog')) {
|
||||
return "Built-in Audio"
|
||||
} else if (name.includes('hdmi')) {
|
||||
return "HDMI Audio"
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
PwObjectTracker {
|
||||
objects: [Pipewire.defaultAudioSink, Pipewire.defaultAudioSource]
|
||||
}
|
||||
|
||||
@@ -145,16 +145,36 @@ Rectangle {
|
||||
border.width: 1
|
||||
radius: Theme.cornerRadiusSmall
|
||||
|
||||
ScrollView {
|
||||
ListView {
|
||||
anchors.fill: parent
|
||||
anchors.margins: Theme.spacingS
|
||||
clip: true
|
||||
model: root.options
|
||||
spacing: 2
|
||||
|
||||
ListView {
|
||||
model: root.options
|
||||
spacing: 2
|
||||
ScrollBar.vertical: ScrollBar { policy: ScrollBar.AsNeeded }
|
||||
ScrollBar.horizontal: ScrollBar { policy: ScrollBar.AlwaysOff }
|
||||
|
||||
delegate: Rectangle {
|
||||
property real wheelMultiplier: 1.8
|
||||
property int wheelBaseStep: 160
|
||||
|
||||
WheelHandler {
|
||||
target: null
|
||||
onWheel: (ev) => {
|
||||
let dy = ev.pixelDelta.y !== 0
|
||||
? ev.pixelDelta.y
|
||||
: (ev.angleDelta.y / 120) * parent.wheelBaseStep;
|
||||
if (ev.inverted) dy = -dy;
|
||||
|
||||
const maxY = Math.max(0, parent.contentHeight - parent.height);
|
||||
parent.contentY = Math.max(0, Math.min(maxY,
|
||||
parent.contentY - dy * parent.wheelMultiplier));
|
||||
|
||||
ev.accepted = true;
|
||||
}
|
||||
}
|
||||
|
||||
delegate: Rectangle {
|
||||
width: ListView.view.width
|
||||
height: 32
|
||||
radius: Theme.cornerRadiusSmall
|
||||
@@ -196,8 +216,6 @@ Rectangle {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -4,10 +4,8 @@ import Quickshell
|
||||
import Quickshell.Widgets
|
||||
import qs.Common
|
||||
|
||||
ScrollView {
|
||||
GridView {
|
||||
id: gridView
|
||||
|
||||
property alias model: grid.model
|
||||
property int currentIndex: 0
|
||||
property int columns: 4
|
||||
property bool adaptiveColumns: false
|
||||
@@ -26,15 +24,15 @@ ScrollView {
|
||||
|
||||
// Ensure the current item is visible
|
||||
function ensureVisible(index) {
|
||||
if (index < 0 || index >= grid.count)
|
||||
if (index < 0 || index >= gridView.count)
|
||||
return ;
|
||||
|
||||
var itemY = Math.floor(index / grid.actualColumns) * grid.cellHeight;
|
||||
var itemBottom = itemY + grid.cellHeight;
|
||||
if (itemY < grid.contentY)
|
||||
grid.contentY = itemY;
|
||||
else if (itemBottom > grid.contentY + grid.height)
|
||||
grid.contentY = itemBottom - grid.height;
|
||||
var itemY = Math.floor(index / gridView.actualColumns) * gridView.cellHeight;
|
||||
var itemBottom = itemY + gridView.cellHeight;
|
||||
if (itemY < gridView.contentY)
|
||||
gridView.contentY = itemY;
|
||||
else if (itemBottom > gridView.contentY + gridView.height)
|
||||
gridView.contentY = itemBottom - gridView.height;
|
||||
}
|
||||
|
||||
onCurrentIndexChanged: {
|
||||
@@ -43,31 +41,47 @@ ScrollView {
|
||||
|
||||
}
|
||||
clip: true
|
||||
ScrollBar.vertical.policy: ScrollBar.AsNeeded
|
||||
ScrollBar.horizontal.policy: ScrollBar.AlwaysOff
|
||||
|
||||
GridView {
|
||||
id: grid
|
||||
ScrollBar.vertical: ScrollBar { policy: ScrollBar.AsNeeded }
|
||||
ScrollBar.horizontal: ScrollBar { policy: ScrollBar.AlwaysOff }
|
||||
|
||||
property int baseCellWidth: adaptiveColumns ? Math.max(minCellWidth, Math.min(maxCellWidth, width / columns)) : (width - Theme.spacingS * 2) / columns
|
||||
property int baseCellHeight: baseCellWidth + 20
|
||||
property int actualColumns: adaptiveColumns ? Math.floor(width / cellWidth) : columns
|
||||
property int remainingSpace: width - (actualColumns * cellWidth)
|
||||
property real wheelMultiplier: 1.8
|
||||
property int wheelBaseStep: 160
|
||||
|
||||
anchors.fill: parent
|
||||
anchors.margins: Theme.spacingS
|
||||
cellWidth: baseCellWidth
|
||||
cellHeight: baseCellHeight
|
||||
leftMargin: Math.max(Theme.spacingS, remainingSpace / 2)
|
||||
rightMargin: leftMargin
|
||||
focus: true
|
||||
interactive: true
|
||||
flickDeceleration: 300
|
||||
maximumFlickVelocity: 30000
|
||||
WheelHandler {
|
||||
target: null
|
||||
onWheel: (ev) => {
|
||||
let dy = ev.pixelDelta.y !== 0
|
||||
? ev.pixelDelta.y
|
||||
: (ev.angleDelta.y / 120) * gridView.wheelBaseStep;
|
||||
if (ev.inverted) dy = -dy;
|
||||
|
||||
delegate: Rectangle {
|
||||
width: grid.cellWidth - cellPadding
|
||||
height: grid.cellHeight - cellPadding
|
||||
const maxY = Math.max(0, gridView.contentHeight - gridView.height);
|
||||
gridView.contentY = Math.max(0, Math.min(maxY,
|
||||
gridView.contentY - dy * gridView.wheelMultiplier));
|
||||
|
||||
ev.accepted = true;
|
||||
}
|
||||
}
|
||||
|
||||
property int baseCellWidth: adaptiveColumns ? Math.max(minCellWidth, Math.min(maxCellWidth, width / columns)) : (width - Theme.spacingS * 2) / columns
|
||||
property int baseCellHeight: baseCellWidth + 20
|
||||
property int actualColumns: adaptiveColumns ? Math.floor(width / cellWidth) : columns
|
||||
property int remainingSpace: width - (actualColumns * cellWidth)
|
||||
|
||||
anchors.margins: Theme.spacingS
|
||||
cellWidth: baseCellWidth
|
||||
cellHeight: baseCellHeight
|
||||
leftMargin: Math.max(Theme.spacingS, remainingSpace / 2)
|
||||
rightMargin: leftMargin
|
||||
focus: true
|
||||
interactive: true
|
||||
flickDeceleration: 300
|
||||
maximumFlickVelocity: 30000
|
||||
|
||||
delegate: Rectangle {
|
||||
width: gridView.cellWidth - cellPadding
|
||||
height: gridView.cellHeight - cellPadding
|
||||
radius: Theme.cornerRadiusLarge
|
||||
color: currentIndex === index ? Theme.primaryPressed : mouseArea.containsMouse ? Theme.primaryHoverLight : Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.03)
|
||||
border.color: currentIndex === index ? Theme.primarySelected : Theme.outlineMedium
|
||||
@@ -78,7 +92,7 @@ ScrollView {
|
||||
spacing: Theme.spacingS
|
||||
|
||||
Item {
|
||||
property int iconSize: Math.min(maxIconSize, Math.max(minIconSize, grid.cellWidth * iconSizeRatio))
|
||||
property int iconSize: Math.min(maxIconSize, Math.max(minIconSize, gridView.cellWidth * iconSizeRatio))
|
||||
|
||||
width: iconSize
|
||||
height: iconSize
|
||||
@@ -116,7 +130,7 @@ ScrollView {
|
||||
|
||||
Text {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
width: grid.cellWidth - 12
|
||||
width: gridView.cellWidth - 12
|
||||
text: model.name || ""
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
@@ -153,6 +167,4 @@ ScrollView {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -4,10 +4,8 @@ import Quickshell
|
||||
import Quickshell.Widgets
|
||||
import qs.Common
|
||||
|
||||
ScrollView {
|
||||
ListView {
|
||||
id: listView
|
||||
|
||||
property alias model: list.model
|
||||
property int currentIndex: 0
|
||||
property int itemHeight: 72
|
||||
property int iconSize: 56
|
||||
@@ -22,15 +20,15 @@ ScrollView {
|
||||
|
||||
// Ensure the current item is visible
|
||||
function ensureVisible(index) {
|
||||
if (index < 0 || index >= list.count)
|
||||
if (index < 0 || index >= listView.count)
|
||||
return ;
|
||||
|
||||
var itemY = index * (itemHeight + itemSpacing);
|
||||
var itemBottom = itemY + itemHeight;
|
||||
if (itemY < list.contentY)
|
||||
list.contentY = itemY;
|
||||
else if (itemBottom > list.contentY + list.height)
|
||||
list.contentY = itemBottom - list.height;
|
||||
if (itemY < listView.contentY)
|
||||
listView.contentY = itemY;
|
||||
else if (itemBottom > listView.contentY + listView.height)
|
||||
listView.contentY = itemBottom - listView.height;
|
||||
}
|
||||
|
||||
onCurrentIndexChanged: {
|
||||
@@ -39,24 +37,39 @@ ScrollView {
|
||||
|
||||
}
|
||||
clip: true
|
||||
ScrollBar.vertical.policy: ScrollBar.AlwaysOn
|
||||
ScrollBar.horizontal.policy: ScrollBar.AlwaysOff
|
||||
|
||||
ListView {
|
||||
id: list
|
||||
ScrollBar.vertical: ScrollBar { policy: ScrollBar.AlwaysOn }
|
||||
ScrollBar.horizontal: ScrollBar { policy: ScrollBar.AlwaysOff }
|
||||
|
||||
anchors.fill: parent
|
||||
anchors.margins: itemSpacing
|
||||
spacing: listView.itemSpacing
|
||||
focus: true
|
||||
interactive: true
|
||||
currentIndex: listView.currentIndex
|
||||
flickDeceleration: 600
|
||||
maximumFlickVelocity: 30000
|
||||
property real wheelMultiplier: 1.8
|
||||
property int wheelBaseStep: 160
|
||||
|
||||
delegate: Rectangle {
|
||||
width: list.width
|
||||
height: itemHeight
|
||||
WheelHandler {
|
||||
target: null
|
||||
onWheel: (ev) => {
|
||||
let dy = ev.pixelDelta.y !== 0
|
||||
? ev.pixelDelta.y
|
||||
: (ev.angleDelta.y / 120) * listView.wheelBaseStep;
|
||||
if (ev.inverted) dy = -dy;
|
||||
|
||||
const maxY = Math.max(0, listView.contentHeight - listView.height);
|
||||
listView.contentY = Math.max(0, Math.min(maxY,
|
||||
listView.contentY - dy * listView.wheelMultiplier));
|
||||
|
||||
ev.accepted = true;
|
||||
}
|
||||
}
|
||||
|
||||
anchors.margins: itemSpacing
|
||||
spacing: itemSpacing
|
||||
focus: true
|
||||
interactive: true
|
||||
flickDeceleration: 600
|
||||
maximumFlickVelocity: 30000
|
||||
|
||||
delegate: Rectangle {
|
||||
width: listView.width
|
||||
height: itemHeight
|
||||
radius: Theme.cornerRadiusLarge
|
||||
color: ListView.isCurrentItem ? Theme.primaryPressed : mouseArea.containsMouse ? Theme.primaryHoverLight : Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.03)
|
||||
border.color: ListView.isCurrentItem ? Theme.primarySelected : Theme.outlineMedium
|
||||
@@ -153,6 +166,4 @@ ScrollView {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user