/*SPDX-FileCopyrightText: Joshua Goins <joshua.goins@kdab.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.Control {id: rootproperty point controlPoint1property point controlPoint2property bool isDefault: trueimplicitWidth: 220implicitHeight: 220leftPadding: 0rightPadding: 0topPadding: 0bottomPadding: 0clip: truefunction forceReloadControlPoints(): void {firstControlCircle.controlPoint = controlPoint1;secondControlCircle.controlPoint = controlPoint2;}background: Rectangle {color: Kirigami.Theme.backgroundColorKirigami.Theme.inherit: falseKirigami.Theme.colorSet: Kirigami.Theme.View}contentItem: Item {// Vertical grid linesRepeater {id: verticalRepeatermodel: 4delegate: Shape {anchors.fill: parentpreferredRendererType: Shape.CurveRendererKirigami.Theme.inherit: falseKirigami.Theme.colorSet: Kirigami.Theme.WindowShapePath {strokeWidth: 1strokeColor: Kirigami.Theme.backgroundColorfillColor: "transparent"startX: line.xstartY: 0PathLine {id: linex: index * (root.width / verticalRepeater.count)y: root.height}}}}// Horizontal grid linesRepeater {id: horizontalRepeatermodel: 4delegate: Shape {anchors.fill: parentpreferredRendererType: Shape.CurveRendererKirigami.Theme.inherit: falseKirigami.Theme.colorSet: Kirigami.Theme.WindowShapePath {strokeWidth: 1strokeColor: Kirigami.Theme.backgroundColorfillColor: "transparent"startX: 0startY: line.yPathLine {id: linex: root.widthy: index * (root.height / horizontalRepeater.count)}}}}Shape {anchors.fill: parentpreferredRendererType: Shape.CurveRendererShapePath {id: pathstrokeWidth: 2strokeColor: kcm.defaultsIndicatorsVisible && !root.isDefault ? Kirigami.Theme.neutralTextColor : (root.activeFocus ? Kirigami.Theme.highlightColor : Kirigami.Theme.disabledTextColor)fillColor: Qt.alpha(strokeColor, 0.2)simplify: truestartX: -2startY: root.height + 2PathCubic {x: root.width + 2y: 0control1X: root.width * controlPoint1.xcontrol1Y: root.height * (1.0 - controlPoint1.y)control2X: root.width * controlPoint2.xcontrol2Y: root.height * (1.0 - controlPoint2.y)}PathLine {x: root.width + 2y: root.height + 2}}// line to first control pointShapePath {strokeWidth: 1strokeColor: Kirigami.Theme.disabledTextColorstartX: 0.0startY: root.heightPathLine {x: root.width * controlPoint1.xy: root.height * (1.0 - controlPoint1.y)}}// line to second control pointShapePath {strokeWidth: 1strokeColor: Kirigami.Theme.disabledTextColorstartX: root.widthstartY: 0.0PathLine {x: root.width * controlPoint2.xy: root.height * (1.0 - controlPoint2.y)}}}component ControlCircle: Rectangle {id: circlerequired property point controlPointwidth: 15height: widthradius: widthcolor: Kirigami.Theme.disabledTextColorx: (root.width * controlPoint.x) - (width / 2)y: (root.height * (1.0 - controlPoint.y)) - (height / 2)DragHandler {target: null // Do not update the item position, we want to control that ourselvescursorShape: Qt.DragMoveCursoronActiveChanged: {if (active) {root.forceActiveFocus(Qt.MouseFocusReason);}}xAxis {minimum: 0.0maximum: root.widthonActiveValueChanged: delta => {let point = controlPoint;const newDelta = delta / root.width;const newPosX = point.x * root.width + delta;if (newPosX > xAxis.minimum && newPosX < xAxis.maximum) {point.x += newDelta;circle.setPoint(point);}}}// QtQuick's origin is at the top-left, while the curve's coordinate space is in the bottom-left hence all the flips.yAxis {minimum: 0.0maximum: root.heightonActiveValueChanged: delta => {let point = controlPoint;const newDelta = delta / root.height;const newPosY = (1.0 - point.y) * root.height + delta;if (newPosY > yAxis.minimum && newPosY < yAxis.maximum) {point.y += -newDelta; // we're flipping here because of the aforementioned coordinate space differencecircle.setPoint(point);}}}}}ControlCircle {id: firstControlCirclecontrolPoint: controlPoint1function setPoint(newPoint: point): void {controlPoint1 = newPoint;}}ControlCircle {id: secondControlCirclecontrolPoint: controlPoint2function setPoint(newPoint: point): void {controlPoint2 = newPoint;}}TapHandler {onTapped: root.forceActiveFocus(Qt.MouseFocusReason)}}}