/*SPDX-FileCopyrightText: 2017 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 org.kde.kcm 1.1 as KCMimport org.kde.kirigami 2.13 as Kirigamiimport org.kde.touchpad.kcm 1.0// TODO: Change ScrollablePage as KCM.SimpleKCM// after rewrite the KCM in KConfigModule.Kirigami.ScrollablePage {id: rootspacing: Kirigami.Units.smallSpacingproperty size minimumSizeHint: Qt.size(formLayout.width/2, deviceSelector.height)property alias deviceIndex: deviceSelector.currentIndexsignal changeSignal()property QtObject touchpadproperty int touchpadCount: backend.touchpadCountproperty bool loading: falsefunction resetModel(index) {touchpadCount = backend.touchpadCountformLayout.enabled = touchpadCountdeviceSelector.enabled = touchpadCount > 1loading = trueif (touchpadCount) {touchpad = deviceModel[index]deviceSelector.model = deviceModeldeviceSelector.currentIndex = index} else {deviceSelector.model = [""]}loading = false}function syncValuesFromBackend() {loading = truedeviceEnabled.load()dwt.load()leftHanded.load()middleEmulation.load()accelSpeedSpinbox.load()accelSpeedSlider.load()accelProfile.load()tapToClick.load()tapAndDrag.load()tapAndDragLock.load()multiTap.load()scrollMethod.load()naturalScroll.load()scrollFactor.load()rightClickMethod.load()middleClickMethod.load()disableHorizontalScrolling.load()loading = false}header: Kirigami.InlineMessage {id: inlineMessage}Connections {target: TouchpadConfigfunction onShowMessage(message, type) {if (touchpadCount === 0) {return}if (message.length !== 0) {inlineMessage.text = messageinlineMessage.type = typeinlineMessage.visible = true} else {inlineMessage.visible = false}}}Kirigami.PlaceholderMessage {text: i18n("No touchpad found")anchors.centerIn: parentvisible: touchpadCount === 0width: parent.width - (Kirigami.Units.largeSpacing * 4)}Kirigami.FormLayout {id: formLayoutvisible: touchpadCount > 0// DeviceQQC2.ComboBox {Kirigami.FormData.label: i18nd("kcm_touchpad", "Device:")id: deviceSelectorvisible: touchpadCount > 1Layouts.Layout.fillWidth: truemodel: deviceModeltextRole: "name"onCurrentIndexChanged: {if (touchpadCount) {touchpad = deviceModel[currentIndex]if (!loading) {changeSignal()}}root.syncValuesFromBackend()}}Item {Kirigami.FormData.isSection: false}// General settingsQQC2.CheckBox {Kirigami.FormData.label: i18nd("kcm_touchpad", "General:")id: deviceEnabledtext: i18nd("kcm_touchpad", "Device enabled")hoverEnabled: trueQQC2.ToolTip {text: i18nd("kcm_touchpad", "Accept input through this device.")visible: parent.hovereddelay: 1000}function load() {if (!formLayout.enabled) {checked = falsereturn}enabled = touchpad.supportsDisableEventschecked = enabled && touchpad.enabled}onCheckedChanged: {if (enabled && !root.loading) {touchpad.enabled = checkedroot.changeSignal()}}}QQC2.CheckBox {id: dwttext: i18nd("kcm_touchpad", "Disable while typing")hoverEnabled: trueQQC2.ToolTip {text: i18nd("kcm_touchpad", "Disable touchpad while typing to prevent accidental inputs.")visible: parent.hovereddelay: 1000}function load() {if (!formLayout.enabled) {checked = falsereturn}enabled = touchpad.supportsDisableWhileTypingchecked = enabled && touchpad.disableWhileTyping}onCheckedChanged: {if (enabled && !root.loading) {touchpad.disableWhileTyping = checkedroot.changeSignal()}}}QQC2.CheckBox {id: leftHandedtext: i18nd("kcm_touchpad", "Left handed mode")hoverEnabled: trueQQC2.ToolTip {text: i18nd("kcm_touchpad", "Swap left and right buttons.")visible: parent.hovereddelay: 1000}function load() {if (!formLayout.enabled) {checked = falsereturn}enabled = touchpad.supportsLeftHandedchecked = enabled && touchpad.leftHanded}onCheckedChanged: {if (enabled && !root.loading) {touchpad.leftHanded = checkedroot.changeSignal()}}}QQC2.CheckBox {id: middleEmulationtext: i18nd("kcm_touchpad", "Press left and right buttons for middle click")hoverEnabled: trueQQC2.ToolTip {text: i18nd("kcm_touchpad", "Clicking left and right button simultaneously sends middle button click.")visible: parent.hovereddelay: 1000}function load() {if (!formLayout.enabled) {checked = falsereturn}enabled = touchpad.supportsMiddleEmulationchecked = enabled && touchpad.middleEmulation}onCheckedChanged: {if (enabled && !root.loading) {touchpad.middleEmulation = checkedroot.changeSignal()}loading = truemiddleClickMethod.load()loading = false}}Item {Kirigami.FormData.isSection: false}// AccelerationLayouts.RowLayout {Kirigami.FormData.label: i18nd("kcm_touchpad", "Pointer acceleration:")id: accelSpeedfunction onAccelSpeedChanged(val) {// check sliderif (val != accelSpeedSlider.accelSpeedValue) {accelSpeedSlider.accelSpeedValue = valaccelSpeedSlider.value = Math.round(6 + (val / 100) / 0.2)}// check spinboxif (val != accelSpeedSpinbox.value) {accelSpeedSpinbox.value = val}// check libinput accelspeedif ((val / 100) != touchpad.pointerAcceleration) {touchpad.pointerAcceleration = val / 100root.changeSignal()}}QQC2.Slider {id: accelSpeedSliderfrom: 1to: 11stepSize: 1property int accelSpeedValue: 0 // [-100, 100]function load() {enabled = touchpad.supportsPointerAccelerationif (!enabled) {return}accelSpeedValue = Math.round(touchpad.pointerAcceleration * 100)// convert libinput pointer acceleration range [-1, 1] to slider range [1, 11]value = Math.round(6 + touchpad.pointerAcceleration / 0.2)}onValueChanged: {if (touchpad != undefined && enabled && !root.loading) {// convert slider range [1, 11] to accelSpeedValue range [-100, 100]accelSpeedValue = Math.round(((value - 6) * 0.2) * 100)accelSpeed.onAccelSpeedChanged(accelSpeedValue)}}}QQC2.SpinBox {id: accelSpeedSpinboxLayouts.Layout.minimumWidth: Kirigami.Units.gridUnit * 4from: -100to: 100stepSize: 1editable: truevalidator: DoubleValidator {bottom: accelSpeedSpinbox.fromtop: accelSpeedSpinbox.to}function load() {enabled = touchpad.supportsPointerAccelerationif (!enabled) {return}// if existing configuration or another application set a value with more than 2 decimals// we reduce the precision to 2value = Math.round(touchpad.pointerAcceleration * 100)}onValueChanged: {if (touchpad != undefined && enabled && !root.loading) {accelSpeed.onAccelSpeedChanged(value)}}textFromValue: function(val, locale) {return Number(val / 100).toLocaleString(locale, "f", 2)}valueFromText: function(text, locale) {return Number.fromLocaleString(locale, text) * 100}}}Layouts.ColumnLayout {Kirigami.FormData.label: i18nd("kcm_touchpad", "Acceleration profile:")Kirigami.FormData.buddyFor: accelProfileFlatid: accelProfilespacing: Kirigami.Units.smallSpacingfunction load() {enabled = touchpad.supportsPointerAccelerationProfileAdaptiveif (!enabled) {accelProfile.visible = falseaccelProfileFlat.checked = falseaccelProfileAdaptive.checked = falsereturn}if(touchpad.pointerAccelerationProfileAdaptive) {accelProfileAdaptive.checked = true} else {accelProfileFlat.checked = true}}function syncCurrent() {if (enabled && !root.loading) {touchpad.pointerAccelerationProfileFlat = accelProfileFlat.checkedtouchpad.pointerAccelerationProfileAdaptive = accelProfileAdaptive.checkedroot.changeSignal()}}QQC2.RadioButton {id: accelProfileFlattext: i18nd("kcm_touchpad", "Flat")hoverEnabled: trueQQC2.ToolTip {text: i18nd("kcm_touchpad", "Cursor moves the same distance as finger.")visible: parent.hovereddelay: 1000}onCheckedChanged: accelProfile.syncCurrent()}QQC2.RadioButton {id: accelProfileAdaptivetext: i18nd("kcm_touchpad", "Adaptive")hoverEnabled: trueQQC2.ToolTip {text: i18nd("kcm_touchpad", "Cursor travel distance depends on movement speed of finger.")visible: parent.hovereddelay: 1000}onCheckedChanged: accelProfile.syncCurrent()}}Item {Kirigami.FormData.isSection: false}// TappingQQC2.CheckBox {Kirigami.FormData.label: i18nd("kcm_touchpad", "Tapping:")id: tapToClicktext: i18nd("kcm_touchpad", "Tap-to-click")hoverEnabled: trueQQC2.ToolTip {text: i18nd("kcm_touchpad", "Single tap is left button click.")visible: parent.hovereddelay: 1000}function load() {enabled = touchpad.tapFingerCount > 0checked = enabled && touchpad.tapToClick}function updateDependents() {loading = truetapAndDrag.load()tapAndDragLock.load()multiTap.load()loading = false}onCheckedChanged: {if (enabled && !root.loading) {touchpad.tapToClick = checkedupdateDependents()root.changeSignal()}}}QQC2.CheckBox {id: tapAndDragtext: i18nd("kcm_touchpad", "Tap-and-drag")hoverEnabled: trueQQC2.ToolTip {text: i18nd("kcm_touchpad", "Sliding over touchpad directly after tap drags.")visible: parent.hovereddelay: 1000}function load() {enabled = touchpad.tapFingerCount > 0 && tapToClick.checkedchecked = enabled && touchpad.tapAndDrag}function updateDependents() {loading = truetapAndDragLock.load()loading = false}onCheckedChanged: {if (enabled && !root.loading) {touchpad.tapAndDrag = checkedupdateDependents()root.changeSignal()}}}QQC2.CheckBox {id: tapAndDragLocktext: i18nd("kcm_touchpad", "Tap-and-drag lock")hoverEnabled: trueQQC2.ToolTip {text: i18nd("kcm_touchpad", "Dragging continues after a short finger lift.")visible: parent.hovereddelay: 1000}function load() {enabled = touchpad.tapFingerCount > 0 && tapAndDrag.checkedchecked = enabled && touchpad.tapDragLock}onCheckedChanged: {if (enabled && !root.loading) {touchpad.tapDragLock = checkedroot.changeSignal()}}}Layouts.ColumnLayout {Kirigami.FormData.label: i18nd("kcm_touchpad", "Two-finger tap:")Kirigami.FormData.buddyFor: multiTapRightClickid: multiTapspacing: Kirigami.Units.smallSpacingfunction load() {enabled = touchpad.supportsLmrTapButtonMap && tapToClick.checkedif (touchpad.tapFingerCount > 2) {multiTapRightClick.text = i18nd("kcm_touchpad", "Right-click (three-finger tap to middle-click)")multiTapRightClickToolTip.text = i18nd("kcm_touchpad", "Tap with two fingers to right-click, tap with three fingers to middle-click.")multiTapMiddleClick.text = i18nd("kcm_touchpad", "Middle-click (three-finger tap right-click)")multiTapMiddleClickToolTip.text = i18nd("kcm_touchpad", "Tap with two fingers to middle-click, tap with three fingers to right-click.")} else {multiTapRightClick.text = i18nd("kcm_touchpad", "Right-click")multiTapRightClickToolTip.text = i18nd("kcm_touchpad", "Tap with two fingers to right-click.")multiTapMiddleClick.text = i18nd("kcm_touchpad", "Middle-click")multiTapMiddleClickToolTip.text = i18nd("kcm_touchpad", "Tap with two fingers to middle-click.")}if (!enabled) {multiTapRightClick.checked = falsemultiTapMiddleClick.checked = falsereturn}if(touchpad.lmrTapButtonMap) {multiTapMiddleClick.checked = true} else {multiTapRightClick.checked = true}}function syncCurrent() {if (enabled && !root.loading) {touchpad.lmrTapButtonMap = multiTapMiddleClick.checkedroot.changeSignal()}}QQC2.RadioButton {id: multiTapRightClick// text: is handled dynamically on load.hoverEnabled: trueQQC2.ToolTip {id: multiTapRightClickToolTipvisible: parent.hovereddelay: 1000// text: is handled dynamically on load.}onCheckedChanged: multiTap.syncCurrent()}QQC2.RadioButton {id: multiTapMiddleClick// text: is handled dynamically on load.hoverEnabled: trueQQC2.ToolTip {id: multiTapMiddleClickToolTipvisible: parent.hovereddelay: 1000// text: is handled dynamically on load.}onCheckedChanged: multiTap.syncCurrent()}}Item {Kirigami.FormData.isSection: false}// ScrollingLayouts.ColumnLayout {Kirigami.FormData.label: i18nd("kcm_touchpad", "Scrolling:")Kirigami.FormData.buddyFor: scrollMethodTwoFingersid: scrollMethodspacing: Kirigami.Units.smallSpacingfunction load() {scrollMethodTwoFingers.enabled = touchpad.supportsScrollTwoFingerscrollMethodTouchpadEdges.enabled = touchpad.supportsScrollEdgeif(scrollMethodTouchpadEdges.enabled && touchpad.scrollEdge) {scrollMethodTouchpadEdges.checked = formLayout.enabled} else {scrollMethodTwoFingers.checked = formLayout.enabled}}function syncCurrent() {if (enabled && !root.loading) {touchpad.scrollTwoFinger = scrollMethodTwoFingers.checkedtouchpad.scrollEdge = scrollMethodTouchpadEdges.checkedroot.changeSignal()}loading = truenaturalScroll.load()loading = false}QQC2.RadioButton {id: scrollMethodTwoFingerstext: i18nd("kcm_touchpad", "Two fingers")hoverEnabled: trueQQC2.ToolTip {text: i18nd("kcm_touchpad", "Slide with two fingers scrolls.")visible: parent.hovereddelay: 1000}}QQC2.RadioButton {id: scrollMethodTouchpadEdgestext: i18nd("kcm_touchpad", "Touchpad edges")hoverEnabled: trueQQC2.ToolTip {text: i18nd("kcm_touchpad", "Slide on the touchpad edges scrolls.")visible: parent.hovereddelay: 1000}onCheckedChanged: scrollMethod.syncCurrent()}}QQC2.CheckBox {id: naturalScrolltext: i18nd("kcm_touchpad", "Invert scroll direction (Natural scrolling)")function load() {enabled = touchpad.supportsNaturalScrollchecked = enabled && touchpad.naturalScroll}onCheckedChanged: {if (enabled && !root.loading) {touchpad.naturalScroll = checkedroot.changeSignal()}}hoverEnabled: trueQQC2.ToolTip {text: i18nd("kcm_touchpad", "Touchscreen like scrolling.")visible: parent.hovereddelay: 1000}}QQC2.CheckBox {id: disableHorizontalScrollingtext: i18nd("kcm_touchpad", "Disable horizontal scrolling")function load() {visible = touchpad.supportsHorizontalScrollingenabled = touchpad.supportsHorizontalScrollingchecked = enabled && !touchpad.horizontalScrolling}onCheckedChanged: {if (enabled && !root.loading) {touchpad.horizontalScrolling = !checkedroot.changeSignal()}}hoverEnabled: trueQQC2.ToolTip {text: i18nd("kcm_touchpad", "Disable horizontal scrolling")visible: parent.hovereddelay: 1000}}// Scroll Speed aka scroll FactorLayouts.GridLayout {Kirigami.FormData.label: i18nd("kcm_touchpad", "Scrolling speed:")Kirigami.FormData.buddyFor: scrollFactorvisible: touchpad.supportsScrollFactorcolumns: 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(touchpad.scrollFactor)if (index === -1) {index = values.indexOf(1);}value = index}onMoved: {touchpad.scrollFactor = values[value]root.changeSignal()}}//row 2QQC2.Label {text: i18ndc("kcm_touchpad", "Slower Scroll", "Slower")}Item {Layouts.Layout.fillWidth: true}QQC2.Label {text: i18ndc("kcm_touchpad", "Faster Scroll Speed", "Faster")}}Item {Kirigami.FormData.isSection: false}Layouts.ColumnLayout {Kirigami.FormData.label: i18nd("kcm_touchpad", "Right-click:")Kirigami.FormData.buddyFor: rightClickMethodAreasid: rightClickMethodspacing: Kirigami.Units.smallSpacingfunction load() {enabled = touchpad.supportsClickMethodAreas && touchpad.supportsClickMethodClickfingervisible = touchpad.supportsClickMethodAreas || touchpad.supportsClickMethodClickfingerrightClickMethodAreas.enabled = touchpad.supportsClickMethodAreasrightClickMethodClickfinger.enabled = touchpad.supportsClickMethodClickfingerif (rightClickMethodAreas.enabled && touchpad.clickMethodAreas) {rightClickMethodAreas.checked = true} else if (rightClickMethodClickfinger.enabled && touchpad.clickMethodClickfinger) {rightClickMethodClickfinger.checked = true}}function syncCurrent() {if (enabled && !root.loading) {touchpad.clickMethodAreas = rightClickMethodAreas.checked && rightClickMethodAreas.visibletouchpad.clickMethodClickfinger = rightClickMethodClickfinger.checked && rightClickMethodClickfinger.visibleroot.changeSignal()}loading = truemiddleClickMethod.load()loading = false}QQC2.RadioButton {id: rightClickMethodAreastext: i18nd("kcm_touchpad", "Press bottom-right corner")hoverEnabled: trueQQC2.ToolTip {text: i18nd("kcm_touchpad", "Software enabled buttons will be added to bottom portion of your touchpad.")visible: parent.hovereddelay: 1000}}QQC2.RadioButton {id: rightClickMethodClickfingertext: i18nd("kcm_touchpad", "Press anywhere with two fingers")hoverEnabled: trueQQC2.ToolTip {text: i18nd("kcm_touchpad", "Tap with two finger to enable right click.")visible: parent.hovereddelay: 1000}onCheckedChanged: rightClickMethod.syncCurrent()}}Item {Kirigami.FormData.isSection: false}Layouts.ColumnLayout {Kirigami.FormData.label: i18nd("kcm_touchpad", "Middle-click: ")Kirigami.FormData.buddyFor: middleSoftwareEmulationid: middleClickMethodspacing: Kirigami.Units.smallSpacingvisible: noMiddleSoftwareEmulation.visible ||middleSoftwareEmulation.visible ||clickfingerMiddleInfoBox.visiblefunction load() {enabled = touchpad.supportsMiddleEmulationif (enabled && touchpad.middleEmulation) {middleSoftwareEmulation.checked = true} else {noMiddleSoftwareEmulation.checked = true}}function syncCurrent() {if (enabled && !root.loading) {touchpad.middleEmulation = middleSoftwareEmulation.checked && middleSoftwareEmulation.visibleroot.changeSignal()}loading = truemiddleEmulation.load()loading = false}QQC2.RadioButton {id: noMiddleSoftwareEmulationtext: i18nd("kcm_touchpad", "Press bottom-middle")visible: rightClickMethodAreas.checkedhoverEnabled: trueQQC2.ToolTip {text: i18nd("kcm_touchpad", "Software enabled middle-button will be added to bottom portion of your touchpad.")visible: parent.hovereddelay: 1000}}QQC2.RadioButton {id: middleSoftwareEmulationtext: i18nd("kcm_touchpad", "Press bottom left and bottom right corners simultaneously")visible: rightClickMethodAreas.checkedhoverEnabled: trueQQC2.ToolTip {text: i18nd("kcm_touchpad", "Clicking left and right button simultaneously sends middle button click.")visible: parent.hovereddelay: 1000}onCheckedChanged: middleClickMethod.syncCurrent()}QQC2.CheckBox {id: clickfingerMiddleInfoBoxtext: i18nd("kcm_touchpad", "Press anywhere with three fingers")checked: trueenabled: falsevisible: rightClickMethodClickfinger.checkedhoverEnabled: trueQQC2.ToolTip {text: i18nd("kcm_touchpad", "Press anywhere with three fingers.")visible: parent.hovereddelay: 1000}}}} // END Kirigami.FormLayout} // END Kirigami.ScrollablePage