146 lines
3.9 KiB
QML
146 lines
3.9 KiB
QML
/*
|
|
SPDX-FileCopyrightText: 2022 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
|
|
|
|
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
|
*/
|
|
|
|
import QtQuick
|
|
import QtQuick3D
|
|
|
|
Item {
|
|
id: root
|
|
|
|
readonly property bool busy: status.useMouse
|
|
|
|
required property Camera camera
|
|
|
|
property quaternion rotation: Quaternion.fromEulerAngles(0, 0, 0)
|
|
property real radius: 2000
|
|
|
|
property real speed: 1
|
|
property real xSpeed: 0.1
|
|
property real ySpeed: 0.1
|
|
|
|
property bool xInvert: false
|
|
property bool yInvert: false
|
|
|
|
implicitWidth: parent.width
|
|
implicitHeight: parent.height
|
|
|
|
onRotationChanged: root.updateCamera();
|
|
onRadiusChanged: root.updateCamera();
|
|
|
|
DragHandler {
|
|
id: dragHandler
|
|
target: null
|
|
acceptedModifiers: Qt.NoModifier
|
|
onCentroidChanged: {
|
|
mouseMoved(Qt.vector2d(centroid.position.x, centroid.position.y), false);
|
|
}
|
|
|
|
onActiveChanged: {
|
|
if (active) {
|
|
mousePressed(Qt.vector2d(centroid.position.x, centroid.position.y));
|
|
} else {
|
|
mouseReleased(Qt.vector2d(centroid.position.x, centroid.position.y));
|
|
}
|
|
}
|
|
}
|
|
|
|
WheelHandler {
|
|
id: wheelHandler
|
|
orientation: Qt.Vertical
|
|
target: null
|
|
onWheel: event => {
|
|
let delta = -event.angleDelta.y * 0.01;
|
|
root.radius += root.radius * 0.1 * delta
|
|
}
|
|
}
|
|
|
|
TapHandler {
|
|
onTapped: root.forceActiveFocus()
|
|
}
|
|
|
|
function mousePressed(newPos) {
|
|
root.forceActiveFocus()
|
|
status.currentPos = newPos
|
|
status.lastPos = newPos
|
|
status.useMouse = true;
|
|
}
|
|
|
|
function mouseReleased(newPos) {
|
|
status.useMouse = false;
|
|
}
|
|
|
|
function mouseMoved(newPos: vector2d) {
|
|
status.currentPos = newPos;
|
|
}
|
|
|
|
function processInputs() {
|
|
if (root.busy) {
|
|
status.processInput();
|
|
}
|
|
}
|
|
|
|
function updateCamera() {
|
|
const eulerRotation = root.rotation.toEulerAngles();
|
|
const theta = (eulerRotation.x + 90) * Math.PI / 180;
|
|
const phi = eulerRotation.y * Math.PI / 180;
|
|
|
|
camera.position = Qt.vector3d(radius * Math.sin(phi) * Math.sin(theta),
|
|
radius * Math.cos(theta),
|
|
radius * Math.cos(phi) * Math.sin(theta));
|
|
camera.rotation = root.rotation;
|
|
}
|
|
|
|
Timer {
|
|
interval: 16
|
|
repeat: true
|
|
running: root.busy
|
|
onTriggered: {
|
|
processInputs();
|
|
}
|
|
}
|
|
|
|
QtObject {
|
|
id: status
|
|
|
|
property bool useMouse: false
|
|
|
|
property real minElevation: -30
|
|
property real maxElevation: 30
|
|
|
|
property vector2d lastPos: Qt.vector2d(0, 0)
|
|
property vector2d currentPos: Qt.vector2d(0, 0)
|
|
|
|
function processInput() {
|
|
if (useMouse) {
|
|
const eulerRotation = root.rotation.toEulerAngles();
|
|
|
|
const pixelDelta = Qt.vector2d(lastPos.x - currentPos.x,
|
|
lastPos.y - currentPos.y);
|
|
lastPos = currentPos;
|
|
|
|
let azimuthDelta = pixelDelta.x * xSpeed
|
|
if (xInvert) {
|
|
azimuthDelta = -azimuthDelta;
|
|
}
|
|
let azimuth = (eulerRotation.y + azimuthDelta) % 360;
|
|
|
|
let elevationDelta = pixelDelta.y * ySpeed
|
|
if (yInvert) {
|
|
elevationDelta = -elevationDelta;
|
|
}
|
|
|
|
let elevation = eulerRotation.x + elevationDelta;
|
|
if (elevation < minElevation) {
|
|
elevation = minElevation;
|
|
} else if (elevation > maxElevation) {
|
|
elevation = maxElevation;
|
|
}
|
|
|
|
root.rotation = Quaternion.fromEulerAngles(elevation, azimuth, 0);
|
|
}
|
|
}
|
|
}
|
|
} |