diff --git a/declarativeimports/plasmacomponents/ScrollBar.qml b/declarativeimports/plasmacomponents/ScrollBar.qml index 16084d8b4..552e6511e 100644 --- a/declarativeimports/plasmacomponents/ScrollBar.qml +++ b/declarativeimports/plasmacomponents/ScrollBar.qml @@ -1,5 +1,5 @@ /* -* Copyright (C) 2010 by Marco Martin +* Copyright (C) 2011 by Daker Fernandes Pinheiro * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as @@ -17,91 +17,179 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -import Qt 4.7 +import QtQuick 1.0 import org.kde.plasma.core 0.1 as PlasmaCore - -PlasmaCore.FrameSvgItem { - id: scrollBar - width: orientation==Qt.Horizontal?200:22 - height: orientation==Qt.Horizontal?22:200 +import QtQuick 1.0 +import org.kde.plasma.core 0.1 as PlasmaCore - property int minimum: 0 - property int maximum: 100 - property int value: 0 - property string orientation: Qt.Horizontal +// TODO: add support mouse wheel and key events +Item { + id: scrollbar - onValueChanged: { - if (drag.state != "dragging") { - if (orientation == Qt.Horizontal) { - drag.x = (value/(maximum-minimum))*(scrollBar.width - drag.width) - } else { - drag.y = (value/(maximum-minimum))*(scrollBar.height - drag.height) - } - } - } + // Common API + property Flickable flickableItem: null - imagePath: "widgets/scrollbar" - prefix: orientation==Qt.Horizontal?"background-horizontal":"background-vertical" + // Plasma API + property int orientation: Qt.Horizontal + property bool animated: false + property bool inverted: false + property bool updateValueWhileDragging: true + property alias stepSize: range.stepSize + property alias pressed: mouseArea.pressed - PlasmaCore.FrameSvgItem { - id: drag - anchors.top: orientation==Qt.Horizontal?parent.top:null - anchors.bottom: orientation==Qt.Horizontal?parent.bottom:null - anchors.left: orientation==Qt.Horizontal?null:parent.left - anchors.right: orientation==Qt.Horizontal?null:parent.right - state: "normal" - width: (orientation == Qt.Horizontal)?Math.max(12, (parent.width*1/(scrollBar.maximum-scrollBar.minimum))):0 - height: (orientation != Qt.Horizontal)?Math.max(12, (parent.height*1/(scrollBar.maximum-scrollBar.minimum))):0 - x: 0 - y: 0 - onXChanged: { - if (orientation == Qt.Horizontal && state == "dragging") { - value = (maximum - minimum)*(x/(scrollBar.width-width)) + // Convinience API + property bool _isVertical: orientation == Qt.Vertical + + width: _isVertical ? 22 : 200 + height: _isVertical ? 200 : 22 + + visible: flickableItem && handle.width < contents.width + + Item { + id: contents + + width: _isVertical ? scrollbar.height : scrollbar.width + height: _isVertical ? scrollbar.width : scrollbar.height + rotation: _isVertical ? -90 : 0 + + anchors.centerIn: parent + + PlasmaCore.RangeModel { + id: range + + minimumValue: 0 + maximumValue: { + var diff; + if (_isVertical) + diff = flickableItem.contentHeight - flickableItem.height; + else + diff = flickableItem.contentWidth - flickableItem.width; + + return Math.max(0, diff); } - } - onYChanged: { - if (orientation != Qt.Horizontal && state == "dragging") { - value = (maximum - minimum)*(x/(scrollBar.height-height)) + stepSize: 0.0 + inverted: _isVertical ? !scrollbar.inverted : scrollbar.inverted + positionAtMinimum: 0 + handle.width / 2 + positionAtMaximum: contents.width - handle.width / 2 + value: _isVertical ? flickableItem.contentY : flickableItem.contentX + onValueChanged: { + if (flickableItem.flicking) + return; + + if (_isVertical) + flickableItem.contentY = value; + else + flickableItem.contentX = value; } + position: handle.x + onPositionChanged: { handle.x = position; } + } - - Behavior on x { - NumberAnimation { - duration: 200 - } - } - Behavior on y { - NumberAnimation { - duration: 200 - } - } - - imagePath: "widgets/scrollbar" - prefix: "slider" - MouseArea { + + PlasmaCore.FrameSvgItem { + id: groove + anchors.fill: parent - hoverEnabled: true - - drag.target: parent; - drag.axis: orientation == Qt.Horizontal?"XAxis":"YAxis" - drag.minimumX: 0; - drag.maximumX: scrollBar.width-drag.width; - drag.minimumY: 0; - drag.maximumY: scrollBar.height-drag.height; - - onEntered: drag.prefix = "mouseover-slider" - onExited: drag.prefix = "slider" + imagePath: "widgets/scrollbar" + prefix: "background-horizontal" + } + + PlasmaCore.FrameSvgItem { + id: handle + + transform: Translate { x: - handle.width / 2 } + x: fakeHandle.x + anchors.verticalCenter: groove.verticalCenter + width: { + var ratio; + if (_isVertical) + ratio = flickableItem.visibleArea.heightRatio; + else + ratio = flickableItem.visibleArea.widthRatio; + + return ratio * parent.width; + } + height: parent.height - margins.top // TODO: check mergin + imagePath: "widgets/scrollbar" + prefix: { + if (scrollbar.pressed) + return "sunken-slider"; + + if (scrollbar.activeFocus || mouseArea.containsMouse) + return "mouseover-slider"; + else + return "slider"; + } + + Behavior on x { + id: behavior + enabled: !mouseArea.drag.active && scrollbar.animated && + !flickableItem.flicking + + PropertyAnimation { + duration: behavior.enabled ? 150 : 0 + easing.type: Easing.OutSine + } + } + } + + Item { + id: fakeHandle + width: handle.width + height: handle.height + transform: Translate { x: - handle.width / 2 } + } + + MouseArea { + id: mouseArea + + anchors.fill: parent + drag { + target: fakeHandle + axis: Drag.XAxis + minimumX: range.positionAtMinimum + maximumX: range.positionAtMaximum + } + onPressed: { - drag.prefix = "sunken-slider" - drag.state = "dragging" + // Clamp the value + var newX = Math.max(mouse.x, drag.minimumX); + newX = Math.min(newX, drag.maximumX); + + // Debounce the press: a press event inside the handler will not + // change its position, the user needs to drag it. + if (Math.abs(newX - fakeHandle.x) > handle.width / 2) + range.position = newX; + + scrollbar.forceActiveFocus(); } onReleased: { - containsMouse?drag.prefix = "mouseover-slider":drag.prefix = "slider" - drag.state = "normal" + // If we don't update while dragging, this is the only + // moment that the range is updated. + if (!scrollbar.updateValueWhileDragging) + range.position = fakeHandle.x; } } } + + // Range position normally follow fakeHandle, except when + // 'updateValueWhileDragging' is false. In this case it will only follow + // if the user is not pressing the handle. + Binding { + when: updateValueWhileDragging || !mouseArea.pressed + target: range + property: "position" + value: fakeHandle.x + } + + // During the drag, we simply ignore position set from the range, this + // means that setting a value while dragging will not "interrupt" the + // dragging activity. + Binding { + when: !mouseArea.drag.active + target: fakeHandle + property: "x" + value: range.position + } } - - diff --git a/declarativeimports/test/ComponentsGallery.qml b/declarativeimports/test/ComponentsGallery.qml index 91c814a1b..2d20294e9 100644 --- a/declarativeimports/test/ComponentsGallery.qml +++ b/declarativeimports/test/ComponentsGallery.qml @@ -26,10 +26,11 @@ Rectangle { color: "lightgrey" Flickable { - id: buttonPage + id: page anchors.fill: parent - contentWidth: 1200 + contentWidth: 2200 + contentHeight: 600 Row { x: 30 @@ -211,6 +212,71 @@ Rectangle { text: slider2.value } } + Column { + spacing: 20 + + Text { + font.pixelSize: 20 + text: "Scroll Bar" + } + + ListView { + id: scrollList + + width: 200 + height: 200 + clip: true + model: 100 + delegate: Text { + width: 200 + height: 18 + text: index + } + + PlasmaComponents.ScrollBar { + orientation: Qt.Vertical + flickableItem: parent + animated: true + anchors { + top: parent.top + right: parent.right + bottom: horizontalScrollBar.top + } + } + + Rectangle { + anchors.fill: parent + color: "grey" + opacity: 0.3 + } + } + } + + } + } + + PlasmaComponents.ScrollBar { + id: horizontalScrollBar + + flickableItem: page + animated: true + anchors { + left: parent.left + right: verticalScrollBar.left + bottom: parent.bottom + } + } + + PlasmaComponents.ScrollBar { + id: verticalScrollBar + + orientation: Qt.Vertical + flickableItem: page + animated: true + anchors { + top: parent.top + right: parent.right + bottom: horizontalScrollBar.top } } } \ No newline at end of file