Merge branch 'mart/QtControlsSlider'

REVIEW:119974
This commit is contained in:
Marco Martin 2014-08-28 16:14:24 +02:00
commit 85fa280111
3 changed files with 101 additions and 232 deletions

View File

@ -89,6 +89,7 @@ PlasmaComponents.Page {
orientation: Qt.Horizontal
minimumValue: 0
maximumValue: 255
tickmarksEnabled: true
stepSize: 10
Keys.onTabPressed: blueSlider.forceActiveFocus()
}

View File

@ -1,5 +1,6 @@
/*
* Copyright (C) 2011 by Daker Fernandes Pinheiro <dakerfp@gmail.com>
* Copyright (C) 2014 by Marco Martin <mart@kde.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License as
@ -19,66 +20,19 @@
import QtQuick 2.1
import org.kde.plasma.core 2.0 as PlasmaCore
import org.kde.plasma.components 2.0 as PlasmaComponents
import "private" as Private
import QtQuick.Controls 1.2 as QtControls
import "styles" as Styles
// TODO: create a value indicator for plasma?
/**
* An interactive slider component with Plasma look and feel.
*
* @inherit QtQuick.Item
* @inherit QtControls.Slider
*/
Item {
QtControls.Slider {
id: slider
// Common API
/**
* type:real
* How many steps the slider value can be selected within its range value.
*/
property alias stepSize: range.stepSize
/**
* type:real
* Minimum value that the slider's value can assume.
*
* The default value is 0.
*/
property alias minimumValue: range.minimumValue
/**
* type:real
* Maximum value that the slider's value can assume.
*
* The default value is 1.
*/
property alias maximumValue: range.maximumValue
/**
* type:real
* This property holds the value selected inside the minimum to maximum
* range of value.
*
* The default value is 0.
*/
property alias value: range.value
/**
* Orientation for this component.
*
* The orientation can be either Qt.Horizontal or Qt.Vertical.
*
* The default is Qt.Horizontal.
*/
property int orientation: Qt.Horizontal
/**
* type:bool
*
* True if the Slider is being pressed.
*/
property alias pressed: mouseArea.pressed
/**
* This property holds if a value indicator element will be shown while is
* dragged or not.
@ -96,15 +50,14 @@ Item {
*/
property string valueIndicatorText: value
// Plasma API
/**
* type:bool
* This property holds if the slider visualizations has an inverted
* direction.
*
* The default value is false.
* @warning: deprecated and not supported, here for retrocompatibility
*/
property alias inverted: range.inverted
property bool inverted: false
width: contents.isVertical ? theme.mSize(theme.defaultFont).height*1.6 : 200
height: contents.isVertical ? 200 : theme.mSize(theme.defaultFont).height*1.6
@ -114,10 +67,6 @@ Item {
activeFocusOnTab: true
Keys.onUpPressed: { if (contents.isVertical) decrease() }
Keys.onDownPressed: { if (contents.isVertical) increase() }
Keys.onLeftPressed: { if (!contents.isVertical) increase() }
Keys.onRightPressed: { if (!contents.isVertical) decrease() }
function accessibleIncreaseAction() { increase() }
function accessibleDecreaseAction() { decrease() }
@ -138,177 +87,5 @@ Item {
value += stepSize;
}
Item {
id: contents
// Plasma API
property bool animated: units.longDuration > 0
property real handleWidth: handle.naturalSize.width
property real handleHeight: handle.naturalSize.height
// Convenience API
property bool isVertical: orientation == Qt.Vertical
width: contents.isVertical ? slider.height : slider.width
height: contents.isVertical ? slider.width : slider.height
rotation: contents.isVertical ? -90 : 0
anchors.centerIn: parent
PlasmaComponents.RangeModel {
id: range
minimumValue: 0.0
maximumValue: 1.0
value: 0
stepSize: 0.0
inverted: false
positionAtMinimum: -handle.width/8
positionAtMaximum: contents.width - (handle.width/8) * 7
}
PlasmaCore.Svg {
id: grooveSvg
imagePath: "widgets/slider"
}
PlasmaCore.FrameSvgItem {
id: groove
imagePath: "widgets/slider"
prefix: "groove"
//FIXME: frameSvg should have a minimumSize attribute, could be added to kdelibs 4.7(maybe just the qml binding is enough)?
height: margins.top + margins.bottom
anchors {
left: parent.left
right: parent.right
verticalCenter: parent.verticalCenter
}
}
PlasmaCore.FrameSvgItem {
id: highlight
imagePath: "widgets/slider"
prefix: "groove-highlight"
height: groove.height
width: inverted ? groove.width - handle.x - handle.width/4 : fakeHandle.x + handle.width/4
x: inverted ? handle.x + handle.width/4 : 0
anchors.verticalCenter: parent.verticalCenter
//use the same animation when resizing a slider as moving the slider this keeps it in line when using key shortcuts
Behavior on width {
enabled: !mouseArea.drag.active && contents.animated
PropertyAnimation {
duration: behavior.enabled ? units.shortDuration : 0
easing.type: Easing.OutSine
}
}
Behavior on x {
enabled: inverted && !mouseArea.drag.active && contents.animated
PropertyAnimation {
duration: behavior.enabled ? units.shortDuration : 0
easing.type: Easing.OutSine
}
}
visible: range.position > 0 && slider.enabled
}
Private.RoundShadow {
id: shadow
imagePath: "widgets/slider"
focusElement: contents.isVertical ? "vertical-slider-focus" : "horizontal-slider-focus"
hoverElement: contents.isVertical ? "vertical-slider-hover" : "horizontal-slider-hover"
shadowElement: contents.isVertical ? "vertical-slider-shadow" : "horizontal-slider-shadow"
state: slider.activeFocus ? "focus" : (mouseArea.containsMouse ? "hover" : "shadow")
anchors.fill: handle
//We rotate the handle below, we need to rotate the shadow back as well
rotation: contents.isVertical ? 90 : 0
}
PlasmaCore.SvgItem {
id: handle
x: fakeHandle.x
anchors {
verticalCenter: groove.verticalCenter
}
width: contents.handleWidth
height: contents.handleHeight
//Rotate the handle back for vertical slider so all the handles have the same shadow effect
rotation: contents.isVertical ? 90 : 0
svg: grooveSvg
elementId: contents.isVertical ? "vertical-slider-handle" : "horizontal-slider-handle"
Behavior on x {
id: behavior
enabled: !mouseArea.drag.active && contents.animated
PropertyAnimation {
duration: behavior.enabled ? units.shortDuration : 0
easing.type: Easing.OutSine
}
}
}
Item {
id: fakeHandle
width: handle.width
height: handle.height
}
MouseArea {
id: mouseArea
anchors.fill: parent
enabled: slider.enabled
drag {
target: fakeHandle
axis: Drag.XAxis
minimumX: range.positionAtMinimum
maximumX: range.positionAtMaximum
}
hoverEnabled: true
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 - handle.width / 2
}
slider.forceActiveFocus()
}
onWheel: {
// horizontal scrolling (angleDelta.x) is "inverted"
// this matches QSlider's behavior
var delta = wheel.angleDelta.x ? -wheel.angleDelta.x : wheel.angleDelta.y
if (delta > 0) { // up/right
slider.value += (slider.inverted ? -slider.stepSize : slider.stepSize)
} else if (delta < 0) {
slider.value += (slider.inverted ? slider.stepSize : -slider.stepSize)
}
slider.forceActiveFocus()
}
}
}
Binding {
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
}
Accessible.role: Accessible.Slider
style: Styles.SliderStyle {}
}

View File

@ -0,0 +1,91 @@
/*
* Copyright (C) 2014 by Marco Martin <mart@kde.org>
*
* This program 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, or
* (at your option) any later version.
*
* This program 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 program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 2.010-1301, USA.
*/
import QtQuick 2.1
import QtQuick.Controls.Styles 1.1 as QtQuickControlStyle
import QtQuick.Controls 1.1
import org.kde.plasma.core 2.0 as PlasmaCore
import org.kde.plasma.components 2.0 as PlasmaComponents
import "../private" as Private
QtQuickControlStyle.SliderStyle {
id: styleItem
property Item handleItem
padding { top: 0 ; left: 0 ; right: 0 ; bottom: 0 }
PlasmaCore.Svg {
id: grooveSvg
imagePath: "widgets/slider"
}
handle: Item {
width: handle.naturalSize.width
height: handle.naturalSize.height
Private.RoundShadow {
id: shadow
anchors.fill: parent
imagePath: "widgets/slider"
focusElement: "horizontal-slider-focus"
hoverElement: "horizontal-slider-hover"
shadowElement: "horizontal-slider-shadow"
state: control.activeFocus ? "focus" : (control.hovered ? "hover" : "shadow")
}
PlasmaCore.SvgItem {
id: handle
anchors.fill: parent
svg: grooveSvg
elementId: "horizontal-slider-handle"
}
}
groove: PlasmaCore.FrameSvgItem {
id: groove
imagePath: "widgets/slider"
prefix: "groove"
PlasmaCore.FrameSvgItem {
id: highlight
imagePath: "widgets/slider"
prefix: "groove-highlight"
height: groove.height
width: styleData.handlePosition
anchors.verticalCenter: parent.verticalCenter
visible: value > 0 && slider.enabled
}
}
tickmarks: Repeater {
id: repeater
model: control.stepSize > 0 ? 1 + (control.maximumValue - control.minimumValue) / control.stepSize : 0
Rectangle {
color: theme.textColor
width: 1 ; height: 3
y: repeater.height
//Position ticklines from styleData.handleWidth to width - styleData.handleWidth/2
//position them at an half handle width increment
x: styleData.handleWidth / 2 + index * ((repeater.width - styleData.handleWidth) / (repeater.count>1 ? repeater.count-1 : 1))
}
}
}