1/*
2    SPDX-FileCopyrightText: 2018 Roman Gilg <subdiff@gmail.com>
3    SPDX-FileCopyrightText: 2018 Furkan Tokac <furkantokac34@gmail.com>
4
5    SPDX-License-Identifier: GPL-2.0-or-later
6*/
7
8import QtQuick 2.7
9import QtQuick.Controls 2.0 as Controls
10import QtQuick.Layouts 1.3 as Layouts
11
12import org.kde.kcm 1.1 as KCM
13import org.kde.kirigami 2.4 as Kirigami
14
15import "components"
16
17// TODO: Change ScrollablePage as KCM.SimpleKCM
18// after rewrite the KCM in KConfigModule.
19Kirigami.ScrollablePage {
20    id: root
21
22    spacing: Kirigami.Units.smallSpacing
23
24    property size sizeHint: Qt.size(formLayout.width, Math.round(1.3 * formLayout.height))
25    property size minimumSizeHint: Qt.size(formLayout.width/2, Math.round(1.3 * formLayout.height))
26
27    property alias deviceIndex: deviceSelector.currentIndex
28    signal changeSignal()
29
30    property QtObject device
31    property int deviceCount: backend.deviceCount
32
33    property bool loading: false
34
35    enabled: deviceCount > 0
36
37    function resetModel(index) {
38        deviceCount = backend.deviceCount
39        formLayout.enabled = deviceCount
40        deviceSelector.enabled = deviceCount > 1
41
42        loading = true
43        if (deviceCount) {
44            device = deviceModel[index]
45            deviceSelector.model = deviceModel
46            deviceSelector.currentIndex = index
47            console.log("Configuration of device '" +
48                        (index + 1) + " : " + device.name + "' opened")
49        } else {
50            deviceSelector.model = [""]
51            console.log("No device found")
52        }
53        loading = false
54    }
55
56    function syncValuesFromBackend() {
57        loading = true
58
59        deviceEnabled.load()
60        leftHanded.load()
61        middleEmulation.load()
62        accelSpeed.load()
63        accelProfile.load()
64        naturalScroll.load()
65        scrollFactor.load()
66
67        loading = false
68    }
69
70    Kirigami.FormLayout {
71        id: formLayout
72        enabled: deviceCount
73
74        // Device
75        Controls.ComboBox {
76            Kirigami.FormData.label: i18nd("kcmmouse", "Device:")
77            id: deviceSelector
78            enabled: deviceCount > 1
79            Layouts.Layout.fillWidth: true
80            model: deviceModel
81            textRole: "name"
82
83            onCurrentIndexChanged: {
84                if (deviceCount) {
85                    device = deviceModel[currentIndex]
86                    if (!loading) {
87                        changeSignal()
88                    }
89                    console.log("Configuration of device '" +
90                                (currentIndex+1) + " : " + device.name + "' opened")
91                }
92                root.syncValuesFromBackend()
93            }
94        }
95
96        Item {
97            Kirigami.FormData.isSection: false
98        }
99
100        // General
101        Controls.CheckBox {
102            Kirigami.FormData.label: i18nd("kcmmouse", "General:")
103            id: deviceEnabled
104            text: i18nd("kcmmouse", "Device enabled")
105
106            function load() {
107                if (!formLayout.enabled) {
108                    checked = false
109                    return
110                }
111                enabled = device.supportsDisableEvents
112                checked = enabled && device.enabled
113            }
114
115            onCheckedChanged: {
116                if (enabled && !root.loading) {
117                    device.enabled = checked
118                    root.changeSignal()
119                }
120            }
121
122            ToolTip {
123                text: i18nd("kcmmouse", "Accept input through this device.")
124            }
125        }
126
127        Controls.CheckBox {
128            id: leftHanded
129            text: i18nd("kcmmouse", "Left handed mode")
130
131            function load() {
132                if (!formLayout.enabled) {
133                    checked = false
134                    return
135                }
136                enabled = device.supportsLeftHanded
137                checked = enabled && device.leftHanded
138            }
139
140            onCheckedChanged: {
141                if (enabled && !root.loading) {
142                    device.leftHanded = checked
143                    root.changeSignal()
144                }
145            }
146
147            ToolTip {
148                text: i18nd("kcmmouse", "Swap left and right buttons.")
149            }
150        }
151
152        Controls.CheckBox {
153            id: middleEmulation
154            text: i18nd("kcmmouse", "Press left and right buttons for middle-click")
155
156            function load() {
157                if (!formLayout.enabled) {
158                    checked = false
159                    return
160                }
161                enabled = device.supportsMiddleEmulation
162                checked = enabled && device.middleEmulation
163            }
164
165            onCheckedChanged: {
166                if (enabled && !root.loading) {
167                    device.middleEmulation = checked
168                    root.changeSignal()
169                }
170            }
171
172            ToolTip {
173                text: i18nd("kcmmouse", "Clicking left and right button simultaneously sends middle button click.")
174            }
175        }
176
177        Item {
178            Kirigami.FormData.isSection: false
179        }
180
181        // Acceleration
182        Controls.Slider {
183            Kirigami.FormData.label: i18nd("kcmmouse", "Pointer speed:")
184            id: accelSpeed
185
186            from: 1
187            to: 11
188            stepSize: 1
189
190            function load() {
191                enabled = device.supportsPointerAcceleration
192                if (!enabled) {
193                    value = 0.2
194                    return
195                }
196                // transform libinput's pointer acceleration range [-1, 1] to slider range [1, 11]
197                //value = 4.5 * device.pointerAcceleration + 5.5
198                value = 6 + device.pointerAcceleration / 0.2
199            }
200
201            onValueChanged: {
202                if (device != undefined && enabled && !root.loading) {
203                    // transform slider range [1, 10] to libinput's pointer acceleration range [-1, 1]
204                    // by *10 and /10, we ignore the floating points after 1 digit. This prevents from
205                    // having a libinput value like 0.60000001
206                    device.pointerAcceleration = Math.round(((value-6) * 0.2) * 10) / 10
207                    root.changeSignal()
208                }
209            }
210        }
211
212        Layouts.ColumnLayout {
213            id: accelProfile
214            spacing: Kirigami.Units.smallSpacing
215            Kirigami.FormData.label: i18nd("kcmmouse", "Acceleration profile:")
216            Kirigami.FormData.buddyFor: accelProfileFlat
217
218            function load() {
219                enabled = device.supportsPointerAccelerationProfileAdaptive
220
221                if (!enabled) {
222                    accelProfileAdaptive.checked = false
223                    accelProfileFlat.checked = false
224                    return
225                }
226
227                if(device.pointerAccelerationProfileAdaptive) {
228                    accelProfileAdaptive.checked = true
229                    accelProfileFlat.checked = false
230                } else {
231                    accelProfileAdaptive.checked = false
232                    accelProfileFlat.checked = true
233                }
234            }
235
236            function syncCurrent() {
237                if (enabled && !root.loading) {
238                    device.pointerAccelerationProfileFlat = accelProfileFlat.checked
239                    device.pointerAccelerationProfileAdaptive = accelProfileAdaptive.checked
240                    root.changeSignal()
241                }
242            }
243
244            Controls.RadioButton {
245                id: accelProfileFlat
246                text: i18nd("kcmmouse", "Flat")
247
248                ToolTip {
249                    text: i18nd("kcmmouse", "Cursor moves the same distance as the mouse movement.")
250                }
251                onCheckedChanged: accelProfile.syncCurrent()
252            }
253
254            Controls.RadioButton {
255                id: accelProfileAdaptive
256                text: i18nd("kcmmouse", "Adaptive")
257
258                ToolTip {
259                    text: i18nd("kcmmouse", "Cursor travel distance depends on the mouse movement speed.")
260                }
261                onCheckedChanged: accelProfile.syncCurrent()
262            }
263        }
264
265        Item {
266            Kirigami.FormData.isSection: false
267        }
268
269        // Scrolling
270        Controls.CheckBox {
271            Kirigami.FormData.label: i18nd("kcmmouse", "Scrolling:")
272            id: naturalScroll
273            text: i18nd("kcmmouse", "Invert scroll direction")
274
275            function load() {
276                enabled = device.supportsNaturalScroll
277                checked = enabled && device.naturalScroll
278            }
279
280            onCheckedChanged: {
281                if (enabled && !root.loading) {
282                    device.naturalScroll = checked
283                    root.changeSignal()
284                }
285            }
286
287            ToolTip {
288                text: i18nd("kcmmouse", "Touchscreen like scrolling.")
289            }
290        }
291
292        // Scroll Speed aka scroll Factor
293        Layouts.GridLayout {
294            Kirigami.FormData.label: i18nd("kcm_touchpad", "Scrolling speed:")
295            Kirigami.FormData.buddyFor: scrollFactor
296
297            columns: 3
298
299            Controls.Slider {
300                id: scrollFactor
301
302                from: 0
303                to: 14
304                stepSize: 1
305
306                property variant values : [
307                    0.1,
308                    0.3,
309                    0.5,
310                    0.75,
311                    1, // default
312                    1.5,
313                    2,
314                    3,
315                    4,
316                    5,
317                    7,
318                    9,
319                    12,
320                    15,
321                    20
322                ]
323
324                Layouts.Layout.columnSpan: 3
325
326                function load() {
327                    let index = values.indexOf(device.scrollFactor)
328                    if (index === -1) {
329                        index = values.indexOf(1);
330                    }
331                    value = index
332                }
333
334                onMoved: {
335                    device.scrollFactor = values[value]
336                    root.changeSignal()
337                }
338            }
339
340            //row 2
341            Controls.Label {
342                text: i18nc("Slower Scroll", "Slower")
343            }
344            Item {
345                Layouts.Layout.fillWidth: true
346            }
347            Controls.Label {
348                text: i18nc("Faster Scroll Speed", "Faster")
349            }
350        }
351    }
352}
353