import QtQuick import QtQuick3D Node { id: breezyDesktop property var viewportResolution: effect.displayResolution property var screens: root.screens property var fovDetails: root.fovDetails property var monitorPlacements: root.monitorPlacements property int focusedMonitorIndex: -1 Displays { id: displays } function displayAtIndex(index) { if (index < 0 || index >= screens.length) { return null; } return breezyDesktopDisplays.objectAt(index); } Repeater3D { id: breezyDesktopDisplays model: breezyDesktop.screens.length delegate: BreezyDesktopDisplay { screen: breezyDesktop.screens[index] monitorPlacement: breezyDesktop.monitorPlacements[index] property real monitorDistance: effect.allDisplaysDistance property real targetDistance: effect.allDisplaysDistance property real screenRotationY: displays.radianToDegree(monitorPlacement.rotationAngleRadians.y) property real screenRotationX: displays.radianToDegree(monitorPlacement.rotationAngleRadians.x) property matrix4x4 rotationMatrix: { const matrix = Qt.matrix4x4(); matrix.rotate(screenRotationY, Qt.vector3d(0, 1, 0)); matrix.rotate(screenRotationX, Qt.vector3d(1, 0, 0)); return matrix; } property vector3d screenScale: { const geometry = screen.geometry; // apparently the default model unit size is 100x100, so we scale it up to the screen size return Qt.vector3d(geometry.width / 100, geometry.height / 100, 1); } scale: screenScale eulerRotation.y: screenRotationY eulerRotation.x: screenRotationX position: { const displayNwu = monitorPlacement.centerNoRotate .times(monitorDistance / effect.allDisplaysDistance); return rotationMatrix.times(displays.nwuToEusVector(displayNwu)); } } } Timer { interval: 500 // 500ms - 2x per second to avoid running this check too frequently repeat: true running: true onTriggered: { if (effect.imuRotations && effect.imuRotations.length > 0) { let focusedIndex = -1; if (effect.zoomOnFocusEnabled) { focusedIndex = displays.findFocusedMonitor( displays.eusToNwuQuat(effect.imuRotations[0]), breezyDesktop.monitorPlacements.map(monitorVectors => monitorVectors.centerLook), breezyDesktop.focusedMonitorIndex, false, // TODO smooth follow breezyDesktop.fovDetails, breezyDesktop.screens.map(screen => screen.geometry) ); } if (focusedIndex !== breezyDesktop.focusedMonitorIndex) { const unfocusedIndex = breezyDesktop.focusedMonitorIndex; const focusedDisplay = focusedIndex !== -1 ? breezyDesktop.displayAtIndex(focusedIndex) : null; const allDisplaysDistanceBinding = Qt.binding(function() { return effect.allDisplaysDistance; }); const focusedDisplayDistanceBinding = Qt.binding(function() { return effect.focusedDisplayDistance; }); if (focusedDisplay === null) { const unfocusedDisplay = breezyDesktop.displayAtIndex(unfocusedIndex); zoomOutAnimation.target = unfocusedDisplay; zoomOutAnimation.target.targetDistance = effect.allDisplaysDistance; zoomOutAnimation.start(); } else { if (unfocusedIndex === -1) { zoomInAnimation.target = focusedDisplay; focusedDisplay.targetDistance = effect.focusedDisplayDistance; zoomInAnimation.start(); } else { zoomInSeqAnimation.target = focusedDisplay; focusedDisplay.targetDistance = effect.focusedDisplayDistance; const unfocusedDisplay = breezyDesktop.displayAtIndex(unfocusedIndex); zoomOutSeqAnimation.target = unfocusedDisplay; zoomOutSeqAnimation.target.targetDistance = effect.allDisplaysDistance; zoomOnFocusSequence.start(); } } breezyDesktop.focusedMonitorIndex = focusedIndex; } } } } NumberAnimation { id: zoomOutAnimation property: "monitorDistance" to: effect.allDisplaysDistance duration: 150 running: false onFinished: { const unfocusedDisplay = zoomOutAnimation.target; if (unfocusedDisplay) { unfocusedDisplay.monitorDistance = Qt.binding(function() { return effect.allDisplaysDistance; }); } } } NumberAnimation { id: zoomInAnimation property: "monitorDistance" to: effect.focusedDisplayDistance duration: 300 running: false onFinished: { const focusedDisplay = zoomInAnimation.target; if (focusedDisplay) { focusedDisplay.monitorDistance = Qt.binding(function() { return effect.focusedDisplayDistance; }); } } } SequentialAnimation { id: zoomOnFocusSequence running: false onFinished: { const focusedDisplay = zoomInSeqAnimation.target; if (focusedDisplay) { focusedDisplay.monitorDistance = Qt.binding(function() { return effect.focusedDisplayDistance; }); } const unfocusedDisplay = zoomOutSeqAnimation.target; if (unfocusedDisplay) { unfocusedDisplay.monitorDistance = Qt.binding(function() { return effect.allDisplaysDistance; }); } } NumberAnimation { id: zoomOutSeqAnimation property: "monitorDistance" to: effect.allDisplaysDistance duration: 150 } PauseAnimation { duration: 50 } NumberAnimation { id: zoomInSeqAnimation property: "monitorDistance" to: effect.focusedDisplayDistance duration: 300 } } }