diff --git a/examples/applets/widgetgallery/contents/ui/Sliders.qml b/examples/applets/widgetgallery/contents/ui/Sliders.qml index 135ee3e8b..9b1eae8a0 100644 --- a/examples/applets/widgetgallery/contents/ui/Sliders.qml +++ b/examples/applets/widgetgallery/contents/ui/Sliders.qml @@ -89,6 +89,7 @@ PlasmaComponents.Page { orientation: Qt.Horizontal minimumValue: 0 maximumValue: 255 + tickmarksEnabled: true stepSize: 10 Keys.onTabPressed: blueSlider.forceActiveFocus() } diff --git a/src/declarativeimports/plasmacomponents/qml/Slider.qml b/src/declarativeimports/plasmacomponents/qml/Slider.qml index c5325909e..676b1cd8a 100644 --- a/src/declarativeimports/plasmacomponents/qml/Slider.qml +++ b/src/declarativeimports/plasmacomponents/qml/Slider.qml @@ -1,5 +1,6 @@ /* * Copyright (C) 2011 by Daker Fernandes Pinheiro +* Copyright (C) 2014 by Marco Martin * * 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 {} } diff --git a/src/declarativeimports/plasmacomponents/qml/styles/SliderStyle.qml b/src/declarativeimports/plasmacomponents/qml/styles/SliderStyle.qml new file mode 100644 index 000000000..0d0323779 --- /dev/null +++ b/src/declarativeimports/plasmacomponents/qml/styles/SliderStyle.qml @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2014 by Marco Martin + * + * 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)) + } + } +}