diff --git a/declarativeimports/plasmacomponents/ScrollBar.qml b/declarativeimports/plasmacomponents/ScrollBar.qml index 552e6511e..0943173a1 100644 --- a/declarativeimports/plasmacomponents/ScrollBar.qml +++ b/declarativeimports/plasmacomponents/ScrollBar.qml @@ -20,9 +20,6 @@ import QtQuick 1.0 import org.kde.plasma.core 0.1 as PlasmaCore -import QtQuick 1.0 -import org.kde.plasma.core 0.1 as PlasmaCore - // TODO: add support mouse wheel and key events Item { id: scrollbar @@ -37,9 +34,14 @@ Item { property bool updateValueWhileDragging: true property alias stepSize: range.stepSize property alias pressed: mouseArea.pressed + property real scrollButtonInterval: 50 // Convinience API property bool _isVertical: orientation == Qt.Vertical + property bool _showButtons: stepSize != 0 + property bool _inverted: _isVertical ? + !scrollbar.inverted : scrollbar.inverted + property alias _value: range.value width: _isVertical ? 22 : 200 height: _isVertical ? 200 : 22 @@ -47,149 +49,241 @@ Item { 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); - } - 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; } - + PlasmaCore.Svg { + id: scrollbarSvg + imagePath: "widgets/scrollbar" } - PlasmaCore.FrameSvgItem { - id: groove + PlasmaCore.SvgItem { + id: leftButton - anchors.fill: parent - imagePath: "widgets/scrollbar" - prefix: "background-horizontal" + anchors { + left: parent.left + verticalCenter: parent.verticalCenter + } + height: 18 + width: _showButtons ? 18 : 0 + svg: scrollbarSvg + elementId: { + if (leftMousArea.pressed) + return "sunken-arrow-left"; + + if (scrollbar.activeFocus || leftMousArea.containsMouse) + return "mouseover-arrow-left"; + else + return "arrow-left"; + } + + MouseArea { + id: leftMousArea + + anchors.fill: parent + Timer { + id: leftTimer + interval: scrollbar.scrollButtonInterval; + running: parent.pressed + repeat: true + onTriggered: { + if (_inverted) + _value += stepSize; + else + _value -= stepSize; + } + } + } } - PlasmaCore.FrameSvgItem { - id: handle + PlasmaCore.SvgItem { + id: rightButton - 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; + anchors { + right: parent.right + verticalCenter: parent.verticalCenter } - height: parent.height - margins.top // TODO: check mergin - imagePath: "widgets/scrollbar" - prefix: { - if (scrollbar.pressed) - return "sunken-slider"; + height: 18 + width: _showButtons ? 18 : 0 + svg: scrollbarSvg + elementId: { + if (rightMousArea.pressed) + return "sunken-arrow-right"; - if (scrollbar.activeFocus || mouseArea.containsMouse) - return "mouseover-slider"; + if (scrollbar.activeFocus || rightMousArea.containsMouse) + return "mouseover-arrow-right"; else - return "slider"; + return "arrow-right"; } - Behavior on x { - id: behavior - enabled: !mouseArea.drag.active && scrollbar.animated && - !flickableItem.flicking + MouseArea { + id: rightMousArea - PropertyAnimation { - duration: behavior.enabled ? 150 : 0 - easing.type: Easing.OutSine + anchors.fill: parent + Timer { + id: rightTimer + interval: scrollbar.scrollButtonInterval; + running: parent.pressed; + repeat: true + onTriggered: { + if (_inverted) + _value -= stepSize + else + _value += stepSize; + } } } } Item { - id: fakeHandle - width: handle.width - height: handle.height - transform: Translate { x: - handle.width / 2 } - } + id: contents - MouseArea { - id: mouseArea - - anchors.fill: parent - drag { - target: fakeHandle - axis: Drag.XAxis - minimumX: range.positionAtMinimum - maximumX: range.positionAtMaximum + anchors { + left: leftButton.right + top: parent.top + bottom: parent.bottom + right: rightButton.left } - onPressed: { - // Clamp the value - var newX = Math.max(mouse.x, drag.minimumX); - newX = Math.min(newX, drag.maximumX); + PlasmaCore.RangeModel { + id: range - // 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; + minimumValue: 0 + maximumValue: { + var diff; + if (_isVertical) + diff = flickableItem.contentHeight - flickableItem.height; + else + diff = flickableItem.contentWidth - flickableItem.width; + + return Math.max(0, diff); + } + stepSize: 0.0 + inverted: _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; } - scrollbar.forceActiveFocus(); } - onReleased: { - // If we don't update while dragging, this is the only - // moment that the range is updated. - if (!scrollbar.updateValueWhileDragging) - range.position = fakeHandle.x; + + PlasmaCore.FrameSvgItem { + id: groove + + anchors.fill: parent + 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: { + // 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: { + // 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 - } + // 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 + // 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 2d20294e9..9de934768 100644 --- a/declarativeimports/test/ComponentsGallery.qml +++ b/declarativeimports/test/ComponentsGallery.qml @@ -233,31 +233,34 @@ Rectangle { 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 { + orientation: Qt.Vertical + flickableItem: scrollList + animated: true + stepSize: 40 + scrollButtonInterval: 50 + anchors { + top: scrollList.top + right: scrollList.right + bottom: scrollList.bottom + } + } + } } } PlasmaComponents.ScrollBar { id: horizontalScrollBar + stepSize: 30 + flickableItem: page animated: true anchors { @@ -279,4 +282,4 @@ Rectangle { bottom: horizontalScrollBar.top } } -} \ No newline at end of file +}