/*SPDX-FileCopyrightText: 2018 Roman Gilg <subdiff@gmail.com>SPDX-FileCopyrightText: 2018 Furkan Tokac <furkantokac34@gmail.com>SPDX-License-Identifier: GPL-2.0-or-later*/import QtQuick 2.7import QtQuick.Controls 2.0 as QQC2import QtQuick.Layouts 1.3 as Layoutsimport QtQuick.Window 2.15import org.kde.kcm 1.1 as KCMimport org.kde.kirigami 2.14 as Kirigamiimport org.kde.kquickcontrols 2.0import "components"Kirigami.ApplicationItem {id: rootpageStack.globalToolBar.style: Kirigami.ApplicationHeaderStyle.NonepageStack.columnView.columnResizeMode: Kirigami.ColumnView.SingleColumnpageStack.defaultColumnWidth: Kirigami.Units.gridUnit * 20property size sizeHint: Qt.size(formLayout.width, Math.round(1.3 * formLayout.height))property size minimumSizeHint: Qt.size(formLayout.width/2, Math.round(1.3 * formLayout.height))property alias deviceIndex: deviceSelector.currentIndexsignal changeSignal()property QtObject deviceproperty int deviceCount: backend.deviceCountproperty bool loading: falseenabled: deviceCount > 0function resetModel(index) {deviceCount = backend.deviceCountformLayout.enabled = deviceCountdeviceSelector.enabled = deviceCount > 1loading = trueif (deviceCount) {device = deviceModel[index]deviceSelector.model = deviceModeldeviceSelector.currentIndex = index} else {deviceSelector.model = [""]}loading = false}function syncValuesFromBackend() {loading = truedeviceEnabled.load()leftHanded.load()middleEmulation.load()accelSpeed.load()accelProfile.load()naturalScroll.load()scrollFactor.load()buttonMappings.load()loading = false}pageStack.initialPage: Kirigami.ScrollablePage {spacing: Kirigami.Units.smallSpacingKirigami.FormLayout {id: formLayoutenabled: deviceCount// DeviceQQC2.ComboBox {Kirigami.FormData.label: i18nd("kcmmouse", "Device:")id: deviceSelectorenabled: deviceCount > 1Layouts.Layout.fillWidth: truemodel: deviceModeltextRole: "name"onCurrentIndexChanged: {if (deviceCount) {device = deviceModel[currentIndex]if (!loading) {changeSignal()}}root.syncValuesFromBackend()}}Item {Kirigami.FormData.isSection: false}// GeneralQQC2.CheckBox {Kirigami.FormData.label: i18nd("kcmmouse", "General:")id: deviceEnabledtext: i18nd("kcmmouse", "Device enabled")function load() {if (!formLayout.enabled) {checked = falsereturn}enabled = device.supportsDisableEventschecked = enabled && device.enabled}onCheckedChanged: {if (enabled && !root.loading) {device.enabled = checkedroot.changeSignal()}}ToolTip {text: i18nd("kcmmouse", "Accept input through this device.")}}QQC2.CheckBox {id: leftHandedtext: i18nd("kcmmouse", "Left handed mode")function load() {if (!formLayout.enabled) {checked = falsereturn}enabled = device.supportsLeftHandedchecked = enabled && device.leftHanded}onCheckedChanged: {if (enabled && !root.loading) {device.leftHanded = checkedroot.changeSignal()}}ToolTip {text: i18nd("kcmmouse", "Swap left and right buttons.")}}QQC2.CheckBox {id: middleEmulationtext: i18nd("kcmmouse", "Press left and right buttons for middle-click")function load() {if (!formLayout.enabled) {checked = falsereturn}enabled = device.supportsMiddleEmulationchecked = enabled && device.middleEmulation}onCheckedChanged: {if (enabled && !root.loading) {device.middleEmulation = checkedroot.changeSignal()}}ToolTip {text: i18nd("kcmmouse", "Clicking left and right button simultaneously sends middle button click.")}}Item {Kirigami.FormData.isSection: false}// AccelerationQQC2.Slider {Kirigami.FormData.label: i18nd("kcmmouse", "Pointer speed:")id: accelSpeedfrom: 1to: 11stepSize: 1function load() {enabled = device.supportsPointerAccelerationif (!enabled) {value = 0.2return}// transform libinput's pointer acceleration range [-1, 1] to slider range [1, 11]//value = 4.5 * device.pointerAcceleration + 5.5value = 6 + device.pointerAcceleration / 0.2}onValueChanged: {if (device != undefined && enabled && !root.loading) {// transform slider range [1, 10] to libinput's pointer acceleration range [-1, 1]// by *10 and /10, we ignore the floating points after 1 digit. This prevents from// having a libinput value like 0.60000001device.pointerAcceleration = Math.round(((value-6) * 0.2) * 10) / 10root.changeSignal()}}}Layouts.ColumnLayout {id: accelProfilespacing: Kirigami.Units.smallSpacingKirigami.FormData.label: i18nd("kcmmouse", "Acceleration profile:")Kirigami.FormData.buddyFor: accelProfileFlatfunction load() {enabled = device.supportsPointerAccelerationProfileAdaptiveif (!enabled) {accelProfileAdaptive.checked = falseaccelProfileFlat.checked = falsereturn}if(device.pointerAccelerationProfileAdaptive) {accelProfileAdaptive.checked = trueaccelProfileFlat.checked = false} else {accelProfileAdaptive.checked = falseaccelProfileFlat.checked = true}}function syncCurrent() {if (enabled && !root.loading) {device.pointerAccelerationProfileFlat = accelProfileFlat.checkeddevice.pointerAccelerationProfileAdaptive = accelProfileAdaptive.checkedroot.changeSignal()}}QQC2.RadioButton {id: accelProfileFlattext: i18nd("kcmmouse", "Flat")ToolTip {text: i18nd("kcmmouse", "Cursor moves the same distance as the mouse movement.")}onCheckedChanged: accelProfile.syncCurrent()}QQC2.RadioButton {id: accelProfileAdaptivetext: i18nd("kcmmouse", "Adaptive")ToolTip {text: i18nd("kcmmouse", "Cursor travel distance depends on the mouse movement speed.")}onCheckedChanged: accelProfile.syncCurrent()}}Item {Kirigami.FormData.isSection: false}// ScrollingQQC2.CheckBox {Kirigami.FormData.label: i18nd("kcmmouse", "Scrolling:")id: naturalScrolltext: i18nd("kcmmouse", "Invert scroll direction")function load() {enabled = device.supportsNaturalScrollchecked = enabled && device.naturalScroll}onCheckedChanged: {if (enabled && !root.loading) {device.naturalScroll = checkedroot.changeSignal()}}ToolTip {text: i18nd("kcmmouse", "Touchscreen like scrolling.")}}// Scroll Speed aka scroll FactorLayouts.GridLayout {Kirigami.FormData.label: i18nd("kcm_touchpad", "Scrolling speed:")Kirigami.FormData.buddyFor: scrollFactorcolumns: 3QQC2.Slider {id: scrollFactorfrom: 0to: 14stepSize: 1property variant values : [0.1,0.3,0.5,0.75,1, // default1.5,2,3,4,5,7,9,12,15,20]Layouts.Layout.columnSpan: 3function load() {let index = values.indexOf(device.scrollFactor)if (index === -1) {index = values.indexOf(1);}value = index}onMoved: {device.scrollFactor = values[value]root.changeSignal()}}//row 2QQC2.Label {text: i18ndc("kcmmouse", "Slower Scroll", "Slower")}Item {Layouts.Layout.fillWidth: true}QQC2.Label {text: i18ndc("kcmmouse", "Faster Scroll Speed", "Faster")}}Item {Kirigami.FormData.isSection: true}QQC2.Button {text: i18ndc("kcmmouse", "@action:button", "Re-bind Additional Mouse Buttonsβ¦")visible: buttonMappings.model.length > 0 || Array.prototype.some.call(deviceModel, device => device.supportedButtons & ~(Qt.LeftButton | Qt.RightButton | Qt.MiddleButton))onClicked: root.pageStack.push(buttonPage)}}}Kirigami.ScrollablePage {id: buttonPageMouseArea {// Deliberately using MouseArea on the page instead of a TapHandler on the button, so we can capture clicks anywhereid: buttonCaptureproperty var lastButton: {}anchors.fill: parentenabled: newBinding.checkedpreventStealing: trueacceptedButtons: Qt.AllButtons & ~(Qt.LeftButton | Qt.RightButton | Qt.MiddleButton)onClicked: {lastButton = buttonMappings.extraButtons.find(entry => Qt[entry.buttonName] == mouse.button)newBinding.visible = falsenewKeySequenceItem.visible = truenewKeySequenceItem.startCapturing()}}Layouts.ColumnLayout {Kirigami.FormLayout {id: buttonLayouttwinFormLayouts: otherLayoutRepeater {id: buttonMappingsreadonly property var extraButtons: Array.from({length: 24}, (value,index) => ({buttonName: "ExtraButton" + (index + 1),button: Qt["ExtraButton" + (index + 1)],label: i18ndc("kcmmouse", "@label for assigning an action to a numbered button", "Extra Button %1:", index + 1)}))function load() {model = Qt.binding(() => extraButtons.filter(entry => backend.buttonMapping.hasOwnProperty(entry.buttonName)))}delegate: KeySequenceItem {Kirigami.FormData.label: modelData.labelkeySequence: backend.buttonMapping[modelData.buttonName]modifierlessAllowed: truemultiKeyShortcutsAllowed: falsecheckForConflictsAgainst: ShortcutType.NoneonCaptureFinished: {let copy = backend.buttonMapping;copy[modelData.buttonName] = keySequencebackend.buttonMapping = copyroot.changeSignal()}}}}Kirigami.InlineMessage {id: explanationLabelLayouts.Layout.fillWidth: truevisible: newBinding.checked || newKeySequenceItem.visibletext: newBinding.visible ? i18ndc("kcmmouse","@action:button", "Press the mouse button for which you want to add a key binding") :i18ndc("kcmmouse","@action:button, %1 is the translation of 'Extra Button %1' from above", "Enter the new key combination for %1", buttonCapture.lastButton.label)actions: [Kirigami.Action {icon.name: "dialog-cancel"text: i18ndc("kcmmouse", "@action:button", "Cancel")onTriggered: {newKeySequenceItem.visible = false;newBinding.visible = truenewBinding.checked = false}}]}Kirigami.FormLayout {id: otherLayouttwinFormLayouts: buttonLayoutQQC2.Button {id:newBindingcheckable: truetext: checked ? i18ndc("kcmmouse", "@action:button", "Press a mouse button ") :i18ndc("kcmmouse", "@action:button, Bind a mousebutton to keyboard key(s)", "Add Bindingβ¦")icon.name: "list-add"}KeySequenceItem {id: newKeySequenceItemvisible: falsemodifierlessAllowed: truemultiKeyShortcutsAllowed: falsecheckForConflictsAgainst: ShortcutType.NoneonCaptureFinished: {visible = falsenewBinding.visible = truenewBinding.checked = falselet copy = backend.buttonMapping;copy[buttonCapture.lastButton.buttonName] = keySequencebackend.buttonMapping = copyroot.changeSignal()}}Item {Kirigami.FormData.isSection: true}QQC2.Button {onClicked: root.pageStack.pop()text: i18ndc("kcmmouse", "@action:button", "Go back")icon.name: "go-previous"}}}}}