From 7cb7c0e276015b51528f7641685fe7b26985653f Mon Sep 17 00:00:00 2001 From: Marco Martin Date: Wed, 9 Nov 2011 16:53:58 +0100 Subject: [PATCH] on desktop, sectionscroller looks like a scrollbar --- .../platformcomponents/touch/ScrollBar.qml | 2 +- .../touch/SectionScroller.qml | 238 ++++++++++++++++++ .../plasmacomponents/qml/ScrollBar.qml | 2 +- .../qml/ScrollBarDelegate.qml | 2 +- .../plasmacomponents/qml/SectionScroller.qml | 95 +------ 5 files changed, 252 insertions(+), 87 deletions(-) create mode 100644 declarativeimports/plasmacomponents/platformcomponents/touch/SectionScroller.qml diff --git a/declarativeimports/plasmacomponents/platformcomponents/touch/ScrollBar.qml b/declarativeimports/plasmacomponents/platformcomponents/touch/ScrollBar.qml index 2650c15ac..964013890 100644 --- a/declarativeimports/plasmacomponents/platformcomponents/touch/ScrollBar.qml +++ b/declarativeimports/plasmacomponents/platformcomponents/touch/ScrollBar.qml @@ -40,7 +40,7 @@ Item { property bool inverted: false property bool animated: true property alias stepSize: range.stepSize - //property alias pressed: mouseArea.pressed + property bool pressed: internalLoader.item.mouseArea?internalLoader.item.mouseArea.pressed:false property real scrollButtonInterval: 50 // Convinience API diff --git a/declarativeimports/plasmacomponents/platformcomponents/touch/SectionScroller.qml b/declarativeimports/plasmacomponents/platformcomponents/touch/SectionScroller.qml new file mode 100644 index 000000000..d93042c3b --- /dev/null +++ b/declarativeimports/plasmacomponents/platformcomponents/touch/SectionScroller.qml @@ -0,0 +1,238 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Components project. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 1.1 +import "SectionScroller.js" as Sections +import org.kde.plasma.core 0.1 as PlasmaCore + +/** + * It's similar to a ScrollBar or a ScrollDecorator. + * It's interactive and works on ListViews that have section.property set, + * so its contents are categorized. + * An indicator will say to what category the user scrolled to. + * + * Useful for things like address books or things sorted by date. + * Don't use with models too big (thousands of items) because implies + * loading all the items to memory, as well loses precision. + */ +Item { + id: root + + /** + * The listview this scroll indicator will work on + */ + property ListView listView + + onListViewChanged: { + if (listView && listView.model) + internal.initDirtyObserver(); + } + + Connections { + target: listView + onModelChanged: { + if (listView && listView.model) { + internal.initDirtyObserver() + } + } + onMovementStarted: root.opacity = 1 + onMovementEnded: { + if (!dragArea.pressed) { + fadeTimer.restart() + } + } + } + + width: 48 + opacity: 0 + Behavior on opacity { + NumberAnimation { + duration: 250 + } + } + + anchors { + right: listView.right + top: listView.top + bottom: listView.bottom + } + + Timer { + id: fadeTimer + interval: 4000 + repeat: false + running: false + onTriggered: { + root.opacity = 0 + } + } + + RangeModel { + id: range + + minimumValue: 0 + maximumValue: Math.max(0, listView.contentHeight - listView.height) + stepSize: 0 + //inverted: true + positionAtMinimum: handle.height / 2 + positionAtMaximum: root.height - handle.height - handle.height / 2 + value: listView.contentY + onValueChanged: { + if (listView.moving) { + return + } else { + listView.contentY = value + } + } + //position: handle.y + onPositionChanged: { + if (!dragArea.pressed) { + handle.y = position + } + } + } + + Rectangle { + anchors.fill: parent + color: Qt.rgba(0,0,0,0.3) + } + + Rectangle { + id: handle + width: 6 + height: 6 + color: theme.textColor + opacity: 0.7 + anchors.horizontalCenter: parent.horizontalCenter + border { + width: 1 + color: theme.backgroundColor + } + onYChanged: { + if (dragArea.pressed) { + range.position = y + } + sectionLabel.text = Sections.closestSection(y/listView.height) + } + Behavior on y { + NumberAnimation { + duration: 150 + } + } + } + PlasmaCore.FrameSvgItem { + imagePath: "widgets/tooltip" + width: childrenRect.width + margins.left + margins.right + height: childrenRect.height + margins.top + margins.bottom + Label { + id: sectionLabel + font.pointSize: theme.defaultFont.pointSize*3 + x: parent.margins.left + y: parent.margins.top + } + y: Math.min(root.height-height, Math.max(0, handle.y - height/2)) + anchors { + //verticalCenter: handle.verticalCenter + right: parent.left + } + opacity: dragArea.pressed?1:0 + Behavior on opacity { + NumberAnimation { + duration: 250 + } + } + } + /*Repeater { + id: sectionsRepeater + delegate: Label { + anchors.horizontalCenter: parent.horizontalCenter + text: Sections._sections[modelData] + y: Sections._sectionData[modelData].index*(listView.height/listView.model.count) + } + }*/ + MouseArea { + id: dragArea + anchors.fill: parent + enabled: scrollbar.enabled + drag { + target: handle + axis: Drag.YAxis + minimumY: range.positionAtMinimum + maximumY: range.positionAtMaximum + } + onPressed: { + mouse.accepted = true + handle.y = mouse.y + } + onReleased: fadeTimer.restart() + + } + + QtObject { + id: internal + + function initDirtyObserver() { + Sections.initSectionData(listView); + function dirtyObserver() { + if (!internal.modelDirty) { + internal.modelDirty = true; + dirtyTimer.running = true; + } + } + + if (listView.model.countChanged) + listView.model.countChanged.connect(dirtyObserver); + + if (listView.model.itemsChanged) + listView.model.itemsChanged.connect(dirtyObserver); + + if (listView.model.itemsInserted) + listView.model.itemsInserted.connect(dirtyObserver); + + if (listView.model.itemsMoved) + listView.model.itemsMoved.connect(dirtyObserver); + + if (listView.model.itemsRemoved) + listView.model.itemsRemoved.connect(dirtyObserver); + + sectionsRepeater.model = Sections._sections.length + } + } +} diff --git a/declarativeimports/plasmacomponents/qml/ScrollBar.qml b/declarativeimports/plasmacomponents/qml/ScrollBar.qml index 01831d088..edd82aa15 100644 --- a/declarativeimports/plasmacomponents/qml/ScrollBar.qml +++ b/declarativeimports/plasmacomponents/qml/ScrollBar.qml @@ -40,7 +40,7 @@ Item { property bool inverted: false property bool animated: true property alias stepSize: range.stepSize - //property alias pressed: mouseArea.pressed + property bool pressed: internalLoader.item.mouseArea?internalLoader.item.mouseArea.pressed:false property real scrollButtonInterval: 50 // Convinience API diff --git a/declarativeimports/plasmacomponents/qml/ScrollBarDelegate.qml b/declarativeimports/plasmacomponents/qml/ScrollBarDelegate.qml index 9323841e4..69eaaf329 100644 --- a/declarativeimports/plasmacomponents/qml/ScrollBarDelegate.qml +++ b/declarativeimports/plasmacomponents/qml/ScrollBarDelegate.qml @@ -115,7 +115,7 @@ PlasmaCore.FrameSvgItem { anchors { left: _isVertical ? undefined : parent.left verticalCenter: _isVertical ? undefined : parent.verticalCenter - top: _isVertical ? 0 : undefined + top: _isVertical ? parent.top : undefined horizontalCenter: _isVertical ? parent.horizontalCenter : undefined } height: 18 diff --git a/declarativeimports/plasmacomponents/qml/SectionScroller.qml b/declarativeimports/plasmacomponents/qml/SectionScroller.qml index d93042c3b..6ae7067a1 100644 --- a/declarativeimports/plasmacomponents/qml/SectionScroller.qml +++ b/declarativeimports/plasmacomponents/qml/SectionScroller.qml @@ -72,16 +72,9 @@ Item { internal.initDirtyObserver() } } - onMovementStarted: root.opacity = 1 - onMovementEnded: { - if (!dragArea.pressed) { - fadeTimer.restart() - } - } } - width: 48 - opacity: 0 + width: 22 Behavior on opacity { NumberAnimation { duration: 250 @@ -94,15 +87,6 @@ Item { bottom: listView.bottom } - Timer { - id: fadeTimer - interval: 4000 - repeat: false - running: false - onTriggered: { - root.opacity = 0 - } - } RangeModel { id: range @@ -111,51 +95,18 @@ Item { maximumValue: Math.max(0, listView.contentHeight - listView.height) stepSize: 0 //inverted: true - positionAtMinimum: handle.height / 2 - positionAtMaximum: root.height - handle.height - handle.height / 2 + positionAtMinimum: root.width*2 + positionAtMaximum: root.height - root.width*2 value: listView.contentY - onValueChanged: { - if (listView.moving) { - return - } else { - listView.contentY = value - } - } - //position: handle.y - onPositionChanged: { - if (!dragArea.pressed) { - handle.y = position - } - } + onPositionChanged: sectionLabel.text = Sections.closestSection(position/listView.height) + } - Rectangle { + ScrollBar { + id: scrollBar + flickableItem: listView anchors.fill: parent - color: Qt.rgba(0,0,0,0.3) - } - - Rectangle { - id: handle - width: 6 - height: 6 - color: theme.textColor - opacity: 0.7 - anchors.horizontalCenter: parent.horizontalCenter - border { - width: 1 - color: theme.backgroundColor - } - onYChanged: { - if (dragArea.pressed) { - range.position = y - } - sectionLabel.text = Sections.closestSection(y/listView.height) - } - Behavior on y { - NumberAnimation { - duration: 150 - } - } + interactive: true } PlasmaCore.FrameSvgItem { imagePath: "widgets/tooltip" @@ -167,43 +118,19 @@ Item { x: parent.margins.left y: parent.margins.top } - y: Math.min(root.height-height, Math.max(0, handle.y - height/2)) + y: Math.min(root.height-height-scrollBar.width, Math.max(scrollBar.width, range.position - height/2)) anchors { //verticalCenter: handle.verticalCenter right: parent.left } - opacity: dragArea.pressed?1:0 + opacity: sectionLabel.text && scrollBar.pressed?1:0 Behavior on opacity { NumberAnimation { duration: 250 } } } - /*Repeater { - id: sectionsRepeater - delegate: Label { - anchors.horizontalCenter: parent.horizontalCenter - text: Sections._sections[modelData] - y: Sections._sectionData[modelData].index*(listView.height/listView.model.count) - } - }*/ - MouseArea { - id: dragArea - anchors.fill: parent - enabled: scrollbar.enabled - drag { - target: handle - axis: Drag.YAxis - minimumY: range.positionAtMinimum - maximumY: range.positionAtMaximum - } - onPressed: { - mouse.accepted = true - handle.y = mouse.y - } - onReleased: fadeTimer.restart() - } QtObject { id: internal