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