Libplasma

Slider.qml
1/*
2 SPDX-FileCopyrightText: 2016 Marco Martin <mart@kde.org>
3 SPDX-FileCopyrightText: 2022 ivan (@ratijas) tkachenko <me@ratijas.tk>
4
5 SPDX-License-Identifier: LGPL-2.0-or-later
6*/
7
8import QtQuick
9import QtQuick.Templates as T
10import org.kde.ksvg as KSvg
11//NOTE: importing PlasmaCore is necessary in order to make KSvg load the current Plasma Theme
12import org.kde.plasma.core as PlasmaCore
13import org.kde.kirigami as Kirigami
14import "private" as P
15
16T.Slider {
17 id: control
18
19 implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
20 implicitHandleWidth + leftPadding + rightPadding)
21 implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
22 implicitHandleHeight + topPadding + bottomPadding)
23
24 snapMode: T.Slider.SnapOnRelease
25 hoverEnabled: true
26
27 layer.enabled: opacity < 1
28 opacity: control.enabled ? 1 : 0.5
29
30 KSvg.Svg {
31 id: sliderSvg
32 imagePath: "widgets/slider"
33 // FIXME
34 colorSet: control.Kirigami.Theme.colorSet
35 }
36
37 // `wheelEnabled: true` doesn't work since it doesn't snap to tickmarks,
38 // so we have to implement the scroll handling ourselves. See
39 // https://bugreports.qt.io/browse/QTBUG-93081
40 MouseArea {
41 property int wheelDelta: 0
42
43 anchors {
44 fill: parent
45 leftMargin: control.leftPadding
46 rightMargin: control.rightPadding
47 }
48 LayoutMirroring.enabled: false
49
50 acceptedButtons: Qt.NoButton
51
52 onWheel: wheel => {
53 const lastValue = control.value
54 // We want a positive delta to increase the slider for up/right scrolling,
55 // independently of the scrolling inversion setting
56 // The x-axis is also inverted (scrolling right produce negative values)
57 const delta = (wheel.angleDelta.y || -wheel.angleDelta.x) * (wheel.inverted ? -1 : 1)
58 wheelDelta += delta;
59 // magic number 120 for common "one click"
60 // See: https://doc.qt.io/qt-5/qml-qtquick-wheelevent.html#angleDelta-prop
61 while (wheelDelta >= 120) {
62 wheelDelta -= 120;
63 control.increase();
64 }
65 while (wheelDelta <= -120) {
66 wheelDelta += 120;
67 control.decrease();
68 }
69 if (lastValue !== control.value) {
70 control.moved();
71 }
72 }
73 }
74
75 handle: Item {
76 x: Math.round(control.leftPadding + (horizontal ? control.visualPosition * (control.availableWidth - width) : (control.availableWidth - width) / 2))
77 y: Math.round(control.topPadding + (horizontal ? (control.availableHeight - height) / 2 : control.visualPosition * (control.availableHeight - height)))
78
79 implicitWidth: sliderSvg.hasElement("hint-handle-size") ? sliderSvg.elementSize("hint-handle-size").width : firstHandle.implicitWidth
80 implicitHeight: sliderSvg.hasElement("hint-handle-size") ? sliderSvg.elementSize("hint-handle-size").height : firstHandle.implicitHeight
81
83 id: shadow
84 z: -1
85 anchors.centerIn: parent
86 implicitWidth: naturalSize.width
87 implicitHeight: naturalSize.height
88 svg: sliderSvg
89 elementId: control.horizontal ? "horizontal-slider-shadow" : "vertical-slider-shadow"
90 visible: enabled && !control.pressed
91 }
93 id: firstHandle
94 anchors.centerIn: parent
95 implicitWidth: naturalSize.width
96 implicitHeight: naturalSize.height
97 svg: sliderSvg
98 elementId: control.horizontal ? "horizontal-slider-handle" : "vertical-slider-handle"
99 }
100 KSvg.SvgItem {
101 anchors.centerIn: parent
102 implicitWidth: naturalSize.width
103 implicitHeight: naturalSize.height
104 svg: sliderSvg
105 elementId: control.horizontal ? "horizontal-slider-focus" : "vertical-slider-focus"
106 visible: opacity > 0
107 opacity: control.visualFocus
108 Behavior on opacity {
109 enabled: Kirigami.Units.longDuration > 0
110 NumberAnimation {
111 duration: Kirigami.Units.longDuration
112 easing.type: Easing.OutCubic
113 }
114 }
115 }
116 KSvg.SvgItem {
117 anchors.centerIn: parent
118 implicitWidth: naturalSize.width
119 implicitHeight: naturalSize.height
120 svg: sliderSvg
121 elementId: control.horizontal ? "horizontal-slider-hover" : "vertical-slider-hover"
122 visible: opacity > 0
123 opacity: control.hovered
124 Behavior on opacity {
125 enabled: control.hovered && Kirigami.Units.longDuration > 0
126 NumberAnimation {
127 duration: Kirigami.Units.longDuration
128 easing.type: Easing.OutCubic
129 }
130 }
131 }
132 }
133
134 background: KSvg.FrameSvgItem {
135 imagePath: "widgets/slider"
136 prefix: "groove"
137 implicitWidth: control.horizontal ? Kirigami.Units.gridUnit * 12 : fixedMargins.left + fixedMargins.right
138 implicitHeight: control.vertical ? Kirigami.Units.gridUnit * 12 : fixedMargins.top + fixedMargins.bottom
139
140 width: control.horizontal ? Math.max(fixedMargins.left + fixedMargins.right, control.availableWidth) : implicitWidth
141 height: control.vertical ? Math.max(fixedMargins.top + fixedMargins.bottom, control.availableHeight) : implicitHeight
142 x: control.leftPadding + (control.horizontal ? 0 : Math.round((control.availableWidth - width) / 2))
143 y: control.topPadding + (control.vertical ? 0 : Math.round((control.availableHeight - height) / 2))
144
146 id: grooveFill
147 imagePath: "widgets/slider"
148 prefix: "groove-highlight"
149
150 LayoutMirroring.enabled: control.mirrored
151 anchors.left: parent.left
152 anchors.bottom: parent.bottom
153 // The general idea is to extend the groove at least up to the middle of a handle, but don't overextend it at the end.
154 width: control.horizontal ? Math.max(fixedMargins.left + fixedMargins.right, Math.round(control.position * (control.availableWidth - control.handle.width / 2) + (control.handle.width / 2))) : parent.width
155 height: control.vertical ? Math.max(fixedMargins.top + fixedMargins.bottom, Math.round(control.position * (control.availableHeight - control.handle.height / 2) + (control.handle.height / 2))) : parent.height
156 }
157
158 Loader {
159 id: tickLoader
160 readonly property int stepCount: (control.to - control.from) / control.stepSize
161 visible: stepCount > 0 && stepCount <= 20
162 active: visible
163 anchors {
164 left: control.horizontal ? parent.left : parent.right
165 top: control.vertical ? parent.top : parent.bottom
166 leftMargin: control.horizontal ? Math.round(control.handle.width / 2) : 1
167 topMargin: control.vertical ? Math.round(control.handle.height / 2) : 1
168 }
169 width: control.horizontal ? parent.width - control.handle.width : control.background.x
170 height: control.vertical ? parent.height - control.handle.height : control.background.y
171 sourceComponent: Grid {
172 anchors.fill: parent
173 rows: control.vertical ? tickLoader.stepCount + 1 : 1
174 columns: control.horizontal ? tickLoader.stepCount + 1 : 1
175 spacing: (control.vertical ? height : width - (tickLoader.stepCount + 1)) / tickLoader.stepCount
176 LayoutMirroring.enabled: control.mirrored
177 Repeater {
178 model: tickLoader.stepCount + 1
179 delegate: Rectangle {
180 property bool withinFill: (control.horizontal ? index : stepCount - index) <= control.position * tickLoader.stepCount
181 width: control.vertical ? parent.width : 1
182 height: control.horizontal ? parent.height : 1
183 opacity: withinFill ? 1 : 0.3
184 color: withinFill ? Kirigami.Theme.highlightColor : Kirigami.Theme.textColor
185 }
186 }
187 }
188 }
189 }
190}
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Mon Nov 18 2024 12:10:41 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.