/*SPDX-FileCopyrightText: 2024 Joshua Goins <josh@redstrate.com>SPDX-License-Identifier: GPL-2.0-or-later*/import QtQuickimport QtQuick.Windowimport QtQuick.Layoutsimport QtQuick.Shapesimport QtQuick.Controls as QQC2import org.kde.kirigami as Kirigamiimport org.kde.plasma.tablet.kcm as KCMQQC2.ApplicationWindow {id: rootrequired property KCM.InputDevice devicerequired property KCM.TabletEvents tabletEventsproperty KCM.CalibrationTool tool: KCM.CalibrationTool {onCalibrationCreated: matrix => tool.setCalibrationMatrix(device, matrix)onResetFromSaved: root.device.resetCalibrationMatrix()}property real currentPenToolX: -1property real currentPenToolY: -1title: i18nc("@title", "Pen Calibration")onWidthChanged: tool.width = widthonHeightChanged: tool.height = heightonClosing: {// Make sure to reset it back to default if the user closes the window for any reason and hasn't confirmedif (tool.state === KCM.CalibrationTool.Confirming) {root.device.resetCalibrationMatrix()}}HoverHandler {cursorShape: Qt.BlankCursoracceptedDevices: PointerDevice.Stylusenabled: tool.state !== KCM.CalibrationTool.Testing}Connections {target: tabletEventsfunction onToolDown(hardware_serial_hi: int, hardware_serial_lo: int, x: real, y: real): void {const centerX = root.width / 2;const centerY = root.height / 2;let targetItem = null;if (x < centerX && y < centerY) {targetItem = topLeftAnchor;} else if (x < centerX && y > centerY) {targetItem = bottomLeftAnchor;} else if (x > centerX && y < centerY) {targetItem = topRightAnchor;} else {targetItem = bottomRightAnchor;}// Calculate the distance between the item and the pointconst distance = Math.sqrt(Math.pow(x - targetItem.x, 2) + Math.pow(y - targetItem.y, 2));// Ensure that large distances are culled because they are probably not clicking on the targetif (distance > 100) {return;}if (tool.state === KCM.CalibrationTool.Testing) {root.currentPenToolX = x;root.currentPenToolY = y;} else {tool.calibrate(x, y, targetItem.positionX, targetItem.positionY);}}function onToolUp(hardware_serial_hi: int, hardware_serial_lo: int, x: real, y: real): void {root.currentPenToolX = -1;root.currentPenToolY = -1;}}ColumnLayout {anchors.centerIn: parentspacing: Kirigami.Units.largeSpacingQQC2.Label {horizontalAlignment: Text.AlignHCentertext: {if (tool.state === KCM.CalibrationTool.Confirming) {return xi18nc("@info", "Tap the targets again to confirm the new calibration.<nl/><nl/><b>Will revert to default calibration in %1 seconds unless further action is taken.</b>", tool.resetSecondsLeft)}if (tool.state === KCM.CalibrationTool.Testing) {return xi18nc("@info", "Calibration is completed and saved.<nl/><nl/>Refine the calibration further or close the window.");}return i18nc("@info", "Tap the center of each target.");}}QQC2.Button {visible: tool.state === KCM.CalibrationTool.Testingtext: i18nc("@action:button", "Refine Existing Calibration")icon.name: "edit-redo"onClicked: tool.reset()Layout.alignment: Qt.AlignHCenter}QQC2.Button {text: tool.state === KCM.CalibrationTool.Confirming ? i18nc("@action:button", "Reset and Try Again") : i18nc("@action:button", "Calibrate from Scratch")icon.name: "kt-restore-defaults"focus: truevisible: tool.state === KCM.CalibrationTool.Confirming || tool.state === KCM.CalibrationTool.TestingonClicked: {tool.restoreDefaults(root.device);tool.reset();}Layout.alignment: Qt.AlignHCenter}QQC2.Button {text: tool.state === KCM.CalibrationTool.Testing ? i18nc("@action:button", "Close") : i18nc("@action:button", "Cancel")icon.name: "dialog-cancel"onClicked: root.close()Layout.alignment: Qt.AlignHCenter}}component Target: QQC2.ToolButton {readonly property real positionX: test.Kirigami.ScenePosition.xreadonly property real positionY: test.Kirigami.ScenePosition.yicon.name: "crosshairs"focusPolicy: Qt.NoFocushoverEnabled: falseHoverHandler {cursorShape: Qt.BlankCursoracceptedDevices: PointerDevice.Stylusenabled: tool.state !== KCM.CalibrationTool.Testing}down: {const isX = root.currentPenToolX >= Kirigami.ScenePosition.x && root.currentPenToolX <= Kirigami.ScenePosition.x + width;const isY = root.currentPenToolY >= Kirigami.ScenePosition.y && root.currentPenToolY <= Kirigami.ScenePosition.y + height;return isX && isY;}Item {id: testanchors.centerIn: parent}}component TargetPath: Shape {required property real sourceXrequired property real sourceYrequired property real targetXrequired property real targetYKirigami.Theme.colorSet: Kirigami.Theme.HeaderKirigami.Theme.inherit: falseShapePath {strokeWidth: 1strokeColor: Qt.lighter(Kirigami.Theme.backgroundColor, 1.5)startX: sourceX; startY: sourceYPathLine { x: targetX; y: targetY }}}component PairTargetPath: Item {required property Item anchorvisible: anchor.visibleTargetPath {sourceX: anchor.positionXsourceY: 0targetX: anchor.positionXtargetY: root.height}TargetPath {sourceX: 0sourceY: anchor.positionYtargetX: root.widthtargetY: anchor.positionY}}Target {id: topLeftAnchorvisible: tool.state === KCM.CalibrationTool.Testing || tool.currentTarget === 0anchors {left: parent.leftleftMargin: Kirigami.Units.gridUnit * 4top: parent.toptopMargin: Kirigami.Units.gridUnit * 4}}PairTargetPath {anchor: topLeftAnchor}Target {id: topRightAnchorvisible: tool.state === KCM.CalibrationTool.Testing || tool.currentTarget === 1anchors {right: parent.rightrightMargin: Kirigami.Units.gridUnit * 4top: parent.toptopMargin: Kirigami.Units.gridUnit * 4}}PairTargetPath {anchor: topRightAnchor}Target {id: bottomLeftAnchorvisible: tool.state === KCM.CalibrationTool.Testing || tool.currentTarget === 2anchors {left: parent.leftleftMargin: Kirigami.Units.gridUnit * 4bottom: parent.bottombottomMargin: Kirigami.Units.gridUnit * 4}}PairTargetPath {anchor: bottomLeftAnchor}Target {id: bottomRightAnchorvisible: tool.state === KCM.CalibrationTool.Testing || tool.currentTarget === 3anchors {right: parent.rightrightMargin: Kirigami.Units.gridUnit * 4bottom: parent.bottombottomMargin: Kirigami.Units.gridUnit * 4}}PairTargetPath {anchor: bottomRightAnchor}}