2015-11-29 16:13:13 +00:00
|
|
|
/*
|
|
|
|
Copyright 2010 Marco Martin <notmart@gmail.com>
|
|
|
|
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
|
|
modify it under the terms of the GNU Library General Public
|
|
|
|
License as published by the Free Software Foundation; either
|
|
|
|
version 2 of the License, or (at your option) any later version.
|
|
|
|
|
|
|
|
This library is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
Library General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU Library General Public License
|
|
|
|
along with this library; see the file COPYING.LIB. If not, write to
|
|
|
|
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
|
|
Boston, MA 02110-1301, USA.
|
|
|
|
*/
|
|
|
|
|
|
|
|
import QtQuick 2.1
|
|
|
|
import org.kde.plasma.core 2.0 as PlasmaCore
|
|
|
|
import org.kde.plasma.mobilecomponents 0.2
|
|
|
|
import org.kde.plasma.mobilecomponents.private 0.2
|
|
|
|
|
|
|
|
Item {
|
|
|
|
id: main
|
|
|
|
|
|
|
|
property Component delegate
|
|
|
|
property QtObject model
|
|
|
|
|
2015-12-03 23:27:35 +00:00
|
|
|
property int pageSize: Math.floor(iconView.width / main.delegateWidth) * Math.floor(iconView.height / main.delegateHeight)
|
|
|
|
property int delegateWidth: Units.iconSizes.huge + Units.gridUnit * 2
|
|
|
|
property int delegateHeight: Units.iconSizes.huge + Units.gridUnit * 2
|
2015-11-29 16:13:13 +00:00
|
|
|
property alias currentPage: iconView.currentIndex
|
2015-12-03 23:27:35 +00:00
|
|
|
property int pagesCount: Math.ceil(model.count / pageSize)
|
2015-11-29 16:13:13 +00:00
|
|
|
property int count: model.count
|
|
|
|
property alias contentX: iconView.contentX
|
|
|
|
clip: true
|
|
|
|
|
|
|
|
function positionViewAtIndex(index)
|
|
|
|
{
|
|
|
|
iconView.positionViewAtIndex(index / pageSize, ListView.Beginning)
|
|
|
|
}
|
|
|
|
|
|
|
|
Timer {
|
|
|
|
id: resizeTimer
|
|
|
|
running: true
|
|
|
|
interval: 100
|
|
|
|
onTriggered: {
|
2015-12-03 23:27:35 +00:00
|
|
|
main.pageSize = Math.floor(iconView.width / main.delegateWidth) * Math.floor(iconView.height / main.delegateHeight)
|
2015-11-29 16:13:13 +00:00
|
|
|
if (iconView.currentItem) {
|
|
|
|
iconView.currentItem.width = iconView.width
|
|
|
|
iconView.currentItem.height = iconView.height
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ListView {
|
|
|
|
id: iconView
|
|
|
|
objectName: "iconView"
|
|
|
|
pressDelay: 200
|
2015-12-03 23:27:35 +00:00
|
|
|
cacheBuffer: Units.gridUnit * 8
|
|
|
|
highlightMoveDuration: Units.shortDuration
|
2015-11-29 16:13:13 +00:00
|
|
|
anchors.fill: parent
|
|
|
|
onWidthChanged: resizeTimer.restart()
|
|
|
|
onHeightChanged: resizeTimer.restart()
|
|
|
|
|
|
|
|
model: main.model ? Math.ceil(main.model.count/main.pageSize) : 0
|
|
|
|
highlightRangeMode: ListView.StrictlyEnforceRange
|
|
|
|
orientation: ListView.Horizontal
|
|
|
|
snapMode: ListView.SnapOneItem
|
|
|
|
boundsBehavior: Flickable.DragOverBounds
|
|
|
|
|
|
|
|
signal clicked(string url)
|
|
|
|
|
|
|
|
delegate: Component {
|
|
|
|
Item {
|
|
|
|
id: delegatePage
|
|
|
|
//Explicitly *not* bind the properties for performance reasons
|
|
|
|
Component.onCompleted: {
|
|
|
|
width = iconView.width
|
|
|
|
height = iconView.height
|
|
|
|
//iconView.cacheBuffer = iconView.width
|
|
|
|
}
|
|
|
|
|
|
|
|
Flow {
|
|
|
|
id: iconFlow
|
|
|
|
width: iconRepeater.suggestedWidth
|
|
|
|
|
|
|
|
anchors {
|
|
|
|
horizontalCenter: parent.horizontalCenter
|
|
|
|
top: parent.top
|
|
|
|
bottom: parent.bottom
|
|
|
|
}
|
|
|
|
property int orientation: ListView.Horizontal
|
|
|
|
|
|
|
|
PagedProxyModel {
|
|
|
|
id: pagedProxyModel
|
|
|
|
sourceModel: main.model
|
|
|
|
currentPage: model.index
|
|
|
|
pageSize: main.pageSize
|
|
|
|
}
|
|
|
|
Repeater {
|
|
|
|
id: iconRepeater
|
|
|
|
model: pagedProxyModel
|
2015-12-03 23:27:35 +00:00
|
|
|
property int columns: Math.min(count, Math.floor(delegatePage.width / main.delegateWidth))
|
|
|
|
property int suggestedWidth: main.delegateWidth * columns
|
2015-11-29 16:13:13 +00:00
|
|
|
//property int suggestedHeight: main.delegateHeight*Math.floor(count/columns)
|
|
|
|
|
|
|
|
delegate: main.delegate
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Loader {
|
|
|
|
id: scrollArea
|
|
|
|
visible: main.model && Math.ceil(main.model.count/main.pageSize) > 1
|
|
|
|
anchors {
|
|
|
|
left: parent.left
|
|
|
|
right: parent.right
|
|
|
|
bottom: parent.bottom
|
|
|
|
}
|
2015-12-03 23:27:35 +00:00
|
|
|
height: Math.max(16, iconView.height - Math.floor(iconView.height / delegateHeight) * delegateHeight)
|
2015-11-29 16:13:13 +00:00
|
|
|
|
|
|
|
property int pageCount: main.model ? Math.ceil(main.model.count/main.pageSize) : 0
|
|
|
|
|
|
|
|
sourceComponent: pageCount > 1 ? ((pageCount * 20 > width) ? scrollDotComponent : dotsRow) : undefined
|
|
|
|
function setViewIndex(index)
|
|
|
|
{
|
|
|
|
//animate only if near
|
|
|
|
if (Math.abs(iconView.currentIndex - index) > 1) {
|
|
|
|
iconView.positionViewAtIndex(index, ListView.Beginning)
|
|
|
|
} else {
|
|
|
|
iconView.currentIndex = index
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Component {
|
|
|
|
id: scrollDotComponent
|
|
|
|
MouseArea {
|
|
|
|
anchors.fill: parent
|
|
|
|
property int pendingIndex: 0
|
|
|
|
Rectangle {
|
|
|
|
id: barRectangle
|
|
|
|
color: Theme.textColor
|
|
|
|
height: 4
|
|
|
|
radius: 2
|
|
|
|
anchors {
|
|
|
|
left: parent.left
|
|
|
|
right: parent.right
|
|
|
|
verticalCenter: parent.verticalCenter
|
2015-12-03 23:27:35 +00:00
|
|
|
leftMargin: (parent.width / pageCount / 2)
|
|
|
|
rightMargin: (parent.width / pageCount / 2)
|
2015-11-29 16:13:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
Rectangle {
|
|
|
|
color: Theme.textColor
|
|
|
|
height: 8
|
|
|
|
width: height
|
|
|
|
radius: 4
|
|
|
|
anchors.verticalCenter: parent.verticalCenter
|
2015-12-03 23:27:35 +00:00
|
|
|
x: parent.width / (pageCount / (iconView.currentIndex+1)) - (parent.width / pageCount / 2) - 4
|
2015-11-29 16:13:13 +00:00
|
|
|
Behavior on x {
|
|
|
|
NumberAnimation {
|
2015-12-03 23:27:35 +00:00
|
|
|
duration: Units.shortDuration
|
2015-11-29 16:13:13 +00:00
|
|
|
easing.type: Easing.InOutQuad
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
function setViewIndexFromMouse(x)
|
|
|
|
{
|
|
|
|
pendingIndex = Math.min(pageCount,
|
|
|
|
Math.round(pageCount / (barRectangle.width / Math.max(x - barRectangle.x, 1))))
|
|
|
|
viewPositionTimer.restart()
|
|
|
|
}
|
|
|
|
onPressed: setViewIndexFromMouse(mouse.x)
|
|
|
|
onPositionChanged: setViewIndexFromMouse(mouse.x)
|
|
|
|
|
|
|
|
Timer {
|
|
|
|
id: viewPositionTimer
|
|
|
|
interval: 200
|
|
|
|
onTriggered: setViewIndex(pendingIndex)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Component {
|
|
|
|
id: dotsRow
|
|
|
|
|
|
|
|
Item {
|
|
|
|
Row {
|
|
|
|
anchors.centerIn: parent
|
2015-12-03 23:27:35 +00:00
|
|
|
spacing: units.gridUnit
|
2015-11-29 16:13:13 +00:00
|
|
|
|
|
|
|
Repeater {
|
|
|
|
model: scrollArea.pageCount
|
|
|
|
|
|
|
|
|
|
|
|
Rectangle {
|
|
|
|
width: 6
|
|
|
|
height: 6
|
|
|
|
scale: iconView.currentIndex == index ? 1.5 : 1
|
|
|
|
radius: 5
|
|
|
|
smooth: true
|
|
|
|
opacity: iconView.currentIndex == index ? 0.8: 0.4
|
|
|
|
color: Theme.textColor
|
|
|
|
|
|
|
|
Behavior on scale {
|
|
|
|
NumberAnimation {
|
2015-12-03 23:27:35 +00:00
|
|
|
duration: units.shortDuration
|
2015-11-29 16:13:13 +00:00
|
|
|
easing.type: Easing.InOutQuad
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Behavior on opacity {
|
|
|
|
NumberAnimation {
|
2015-12-03 23:27:35 +00:00
|
|
|
duration: units.shortDuration
|
2015-11-29 16:13:13 +00:00
|
|
|
easing.type: Easing.InOutQuad
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
MouseArea {
|
|
|
|
anchors {
|
|
|
|
fill: parent
|
2015-12-03 23:27:35 +00:00
|
|
|
margins: Units.gridUnit / 2
|
2015-11-29 16:13:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
onClicked: {
|
|
|
|
setViewIndex(index)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|