Add support for enabling/disabling physical screen mirroring
Option to turn physical displays off not implemented yet
This commit is contained in:
parent
f27fd17b59
commit
40475736c1
|
|
@ -57,6 +57,13 @@
|
||||||
<label>Antialiasing Quality</label>
|
<label>Antialiasing Quality</label>
|
||||||
<description>0=None, 1=Medium, 2=High, 3=Very High</description>
|
<description>0=None, 1=Medium, 2=High, 3=Very High</description>
|
||||||
</entry>
|
</entry>
|
||||||
|
<entry name="PhysicalDisplaysMode" type="Int">
|
||||||
|
<default>1</default>
|
||||||
|
<min>0</min>
|
||||||
|
<max>2</max>
|
||||||
|
<label>Physical Displays On/Off</label>
|
||||||
|
<description>How to handle the physical (built-in) monitors: 0=Off, 1=On - not mirrored in XR, 2=On - mirrored in XR (may impact performance)</description>
|
||||||
|
</entry>
|
||||||
<entry name="RemoveVirtualDisplaysOnDisable" type="Bool">
|
<entry name="RemoveVirtualDisplaysOnDisable" type="Bool">
|
||||||
<default>true</default>
|
<default>true</default>
|
||||||
<label>Remove virtual displays on disable</label>
|
<label>Remove virtual displays on disable</label>
|
||||||
|
|
|
||||||
|
|
@ -203,12 +203,14 @@ void BreezyDesktopEffect::reconfigure(ReconfigureFlags)
|
||||||
int wrap = BreezyDesktopConfig::displayWrappingScheme();
|
int wrap = BreezyDesktopConfig::displayWrappingScheme();
|
||||||
int aaQuality = BreezyDesktopConfig::antialiasingQuality();
|
int aaQuality = BreezyDesktopConfig::antialiasingQuality();
|
||||||
bool removeVD = BreezyDesktopConfig::removeVirtualDisplaysOnDisable();
|
bool removeVD = BreezyDesktopConfig::removeVirtualDisplaysOnDisable();
|
||||||
|
int physDisplaysMode = BreezyDesktopConfig::physicalDisplaysMode();
|
||||||
bool changed = false;
|
bool changed = false;
|
||||||
if (!qFuzzyCompare(m_displayHorizontalOffset, horiz)) { m_displayHorizontalOffset = horiz; changed = true; }
|
if (!qFuzzyCompare(m_displayHorizontalOffset, horiz)) { m_displayHorizontalOffset = horiz; changed = true; }
|
||||||
if (!qFuzzyCompare(m_displayVerticalOffset, vert)) { m_displayVerticalOffset = vert; changed = true; }
|
if (!qFuzzyCompare(m_displayVerticalOffset, vert)) { m_displayVerticalOffset = vert; changed = true; }
|
||||||
if (m_displayWrappingScheme != wrap) { m_displayWrappingScheme = wrap; Q_EMIT displayWrappingSchemeChanged(); }
|
if (m_displayWrappingScheme != wrap) { m_displayWrappingScheme = wrap; Q_EMIT displayWrappingSchemeChanged(); }
|
||||||
if (m_antialiasingQuality != aaQuality) { m_antialiasingQuality = aaQuality; Q_EMIT antialiasingQualityChanged(); }
|
if (m_antialiasingQuality != aaQuality) { m_antialiasingQuality = aaQuality; Q_EMIT antialiasingQualityChanged(); }
|
||||||
if (m_removeVirtualDisplaysOnDisable != removeVD) { m_removeVirtualDisplaysOnDisable = removeVD; Q_EMIT removeVirtualDisplaysOnDisableChanged(); }
|
if (m_removeVirtualDisplaysOnDisable != removeVD) { m_removeVirtualDisplaysOnDisable = removeVD; Q_EMIT removeVirtualDisplaysOnDisableChanged(); }
|
||||||
|
if (m_physicalDisplaysMode != physDisplaysMode) { m_physicalDisplaysMode = physDisplaysMode; Q_EMIT physicalDisplaysModeChanged(); }
|
||||||
if (changed) Q_EMIT displayOffsetChanged();
|
if (changed) Q_EMIT displayOffsetChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -427,6 +429,10 @@ bool BreezyDesktopEffect::removeVirtualDisplaysOnDisable() const {
|
||||||
return m_removeVirtualDisplaysOnDisable;
|
return m_removeVirtualDisplaysOnDisable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int BreezyDesktopEffect::physicalDisplaysMode() const {
|
||||||
|
return m_physicalDisplaysMode;
|
||||||
|
}
|
||||||
|
|
||||||
bool BreezyDesktopEffect::checkParityByte(const char* data) {
|
bool BreezyDesktopEffect::checkParityByte(const char* data) {
|
||||||
const uint8_t parityByte = static_cast<uint8_t>(data[DataView::IMU_PARITY_BYTE[DataView::OFFSET_INDEX]]);
|
const uint8_t parityByte = static_cast<uint8_t>(data[DataView::IMU_PARITY_BYTE[DataView::OFFSET_INDEX]]);
|
||||||
uint8_t parity = 0;
|
uint8_t parity = 0;
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,7 @@ namespace KWin
|
||||||
Q_PROPERTY(bool customBannerEnabled READ customBannerEnabled NOTIFY devicePropertiesChanged)
|
Q_PROPERTY(bool customBannerEnabled READ customBannerEnabled NOTIFY devicePropertiesChanged)
|
||||||
Q_PROPERTY(int antialiasingQuality READ antialiasingQuality NOTIFY antialiasingQualityChanged)
|
Q_PROPERTY(int antialiasingQuality READ antialiasingQuality NOTIFY antialiasingQualityChanged)
|
||||||
Q_PROPERTY(bool removeVirtualDisplaysOnDisable READ removeVirtualDisplaysOnDisable NOTIFY removeVirtualDisplaysOnDisableChanged)
|
Q_PROPERTY(bool removeVirtualDisplaysOnDisable READ removeVirtualDisplaysOnDisable NOTIFY removeVirtualDisplaysOnDisableChanged)
|
||||||
|
Q_PROPERTY(int physicalDisplaysMode READ physicalDisplaysMode NOTIFY physicalDisplaysModeChanged)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
|
@ -75,6 +76,7 @@ namespace KWin
|
||||||
bool customBannerEnabled() const;
|
bool customBannerEnabled() const;
|
||||||
int antialiasingQuality() const;
|
int antialiasingQuality() const;
|
||||||
bool removeVirtualDisplaysOnDisable() const;
|
bool removeVirtualDisplaysOnDisable() const;
|
||||||
|
int physicalDisplaysMode() const;
|
||||||
|
|
||||||
void showCursor();
|
void showCursor();
|
||||||
void hideCursor();
|
void hideCursor();
|
||||||
|
|
@ -104,6 +106,7 @@ namespace KWin
|
||||||
void devicePropertiesChanged();
|
void devicePropertiesChanged();
|
||||||
void antialiasingQualityChanged();
|
void antialiasingQualityChanged();
|
||||||
void removeVirtualDisplaysOnDisableChanged();
|
void removeVirtualDisplaysOnDisableChanged();
|
||||||
|
void physicalDisplaysModeChanged();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
QVariantMap initialProperties(Output *screen) override;
|
QVariantMap initialProperties(Output *screen) override;
|
||||||
|
|
@ -142,6 +145,7 @@ namespace KWin
|
||||||
int m_displayWrappingScheme = 0; // 0=auto,1=horizontal,2=vertical,3=flat
|
int m_displayWrappingScheme = 0; // 0=auto,1=horizontal,2=vertical,3=flat
|
||||||
int m_antialiasingQuality = 3; // 0=None, 1=Medium, 2=High, 3=VeryHigh
|
int m_antialiasingQuality = 3; // 0=None, 1=Medium, 2=High, 3=VeryHigh
|
||||||
bool m_removeVirtualDisplaysOnDisable = true;
|
bool m_removeVirtualDisplaysOnDisable = true;
|
||||||
|
int m_physicalDisplaysMode = 1; // 0=Off,1=On no mirror,2=On mirrored
|
||||||
QList<Output *> m_virtualOutputs;
|
QList<Output *> m_virtualOutputs;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -106,6 +106,7 @@ BreezyDesktopEffectConfig::BreezyDesktopEffectConfig(QObject *parent, const KPlu
|
||||||
connect(ui.kcfg_DisplayVerticalOffset, &QSlider::valueChanged, this, &BreezyDesktopEffectConfig::save);
|
connect(ui.kcfg_DisplayVerticalOffset, &QSlider::valueChanged, this, &BreezyDesktopEffectConfig::save);
|
||||||
connect(ui.kcfg_DisplayWrappingScheme, qOverload<int>(&QComboBox::currentIndexChanged), this, &BreezyDesktopEffectConfig::save);
|
connect(ui.kcfg_DisplayWrappingScheme, qOverload<int>(&QComboBox::currentIndexChanged), this, &BreezyDesktopEffectConfig::save);
|
||||||
connect(ui.kcfg_AntialiasingQuality, qOverload<int>(&QComboBox::currentIndexChanged), this, &BreezyDesktopEffectConfig::save);
|
connect(ui.kcfg_AntialiasingQuality, qOverload<int>(&QComboBox::currentIndexChanged), this, &BreezyDesktopEffectConfig::save);
|
||||||
|
connect(ui.kcfg_PhysicalDisplaysMode, qOverload<int>(&QComboBox::currentIndexChanged), this, &BreezyDesktopEffectConfig::save);
|
||||||
connect(ui.kcfg_RemoveVirtualDisplaysOnDisable, &QCheckBox::toggled, this, &BreezyDesktopEffectConfig::save);
|
connect(ui.kcfg_RemoveVirtualDisplaysOnDisable, &QCheckBox::toggled, this, &BreezyDesktopEffectConfig::save);
|
||||||
|
|
||||||
if (auto label = widget()->findChild<QLabel*>("labelAppNameVersion")) {
|
if (auto label = widget()->findChild<QLabel*>("labelAppNameVersion")) {
|
||||||
|
|
@ -226,6 +227,7 @@ void BreezyDesktopEffectConfig::updateUiFromConfig()
|
||||||
ui.kcfg_DisplayVerticalOffset->setValue(BreezyDesktopConfig::self()->displayVerticalOffset());
|
ui.kcfg_DisplayVerticalOffset->setValue(BreezyDesktopConfig::self()->displayVerticalOffset());
|
||||||
ui.kcfg_DisplayWrappingScheme->setCurrentIndex(BreezyDesktopConfig::self()->displayWrappingScheme());
|
ui.kcfg_DisplayWrappingScheme->setCurrentIndex(BreezyDesktopConfig::self()->displayWrappingScheme());
|
||||||
ui.kcfg_AntialiasingQuality->setCurrentIndex(BreezyDesktopConfig::self()->antialiasingQuality());
|
ui.kcfg_AntialiasingQuality->setCurrentIndex(BreezyDesktopConfig::self()->antialiasingQuality());
|
||||||
|
ui.kcfg_PhysicalDisplaysMode->setCurrentIndex(BreezyDesktopConfig::self()->physicalDisplaysMode());
|
||||||
ui.kcfg_RemoveVirtualDisplaysOnDisable->setChecked(BreezyDesktopConfig::self()->removeVirtualDisplaysOnDisable());
|
ui.kcfg_RemoveVirtualDisplaysOnDisable->setChecked(BreezyDesktopConfig::self()->removeVirtualDisplaysOnDisable());
|
||||||
ui.kcfg_ZoomOnFocusEnabled->setChecked(BreezyDesktopConfig::self()->zoomOnFocusEnabled());
|
ui.kcfg_ZoomOnFocusEnabled->setChecked(BreezyDesktopConfig::self()->zoomOnFocusEnabled());
|
||||||
ui.kcfg_FocusedDisplayDistance->setEnabled(ui.kcfg_ZoomOnFocusEnabled->isChecked());
|
ui.kcfg_FocusedDisplayDistance->setEnabled(ui.kcfg_ZoomOnFocusEnabled->isChecked());
|
||||||
|
|
|
||||||
|
|
@ -267,13 +267,39 @@
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="2" column="0">
|
<item row="2" column="0">
|
||||||
|
<widget class="QLabel" name="labelPhysicalDisplaysMode">
|
||||||
|
<property name="text">
|
||||||
|
<string>Physical Displays On/Off:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="1">
|
||||||
|
<widget class="QComboBox" name="kcfg_PhysicalDisplaysMode">
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Off</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>On - not mirrored in XR</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>On - mirrored in XR (may impact performance)</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="0">
|
||||||
<widget class="QLabel" name="labelDisplayHorizontalOffset">
|
<widget class="QLabel" name="labelDisplayHorizontalOffset">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Display Horizontal Offset:</string>
|
<string>Display Horizontal Offset:</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="2" column="1">
|
<item row="3" column="1">
|
||||||
<widget class="LabeledSlider" name="kcfg_DisplayHorizontalOffset">
|
<widget class="LabeledSlider" name="kcfg_DisplayHorizontalOffset">
|
||||||
<property name="decimalShift">
|
<property name="decimalShift">
|
||||||
<double>2</double>
|
<double>2</double>
|
||||||
|
|
@ -292,14 +318,14 @@
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="3" column="0">
|
<item row="4" column="0">
|
||||||
<widget class="QLabel" name="labelDisplayVerticalOffset">
|
<widget class="QLabel" name="labelDisplayVerticalOffset">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Display Vertical Offset:</string>
|
<string>Display Vertical Offset:</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="3" column="1">
|
<item row="4" column="1">
|
||||||
<widget class="LabeledSlider" name="kcfg_DisplayVerticalOffset">
|
<widget class="LabeledSlider" name="kcfg_DisplayVerticalOffset">
|
||||||
<property name="decimalShift">
|
<property name="decimalShift">
|
||||||
<double>2</double>
|
<double>2</double>
|
||||||
|
|
@ -318,7 +344,7 @@
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="4" column="0" colspan="2">
|
<item row="5" column="0" colspan="2">
|
||||||
<widget class="QCheckBox" name="kcfg_RemoveVirtualDisplaysOnDisable">
|
<widget class="QCheckBox" name="kcfg_RemoveVirtualDisplaysOnDisable">
|
||||||
<property name="visible">
|
<property name="visible">
|
||||||
<bool>false</bool>
|
<bool>false</bool>
|
||||||
|
|
|
||||||
|
|
@ -6,9 +6,9 @@ Node {
|
||||||
id: breezyDesktop
|
id: breezyDesktop
|
||||||
|
|
||||||
property var viewportResolution: effect.displayResolution
|
property var viewportResolution: effect.displayResolution
|
||||||
property var screens: root.screens
|
required property var screens
|
||||||
property var fovDetails: root.fovDetails
|
required property var fovDetails
|
||||||
property var monitorPlacements: root.monitorPlacements
|
required property var monitorPlacements
|
||||||
property int focusedMonitorIndex: -1
|
property int focusedMonitorIndex: -1
|
||||||
|
|
||||||
Displays {
|
Displays {
|
||||||
|
|
@ -31,8 +31,8 @@ Node {
|
||||||
|
|
||||||
property real monitorDistance: effect.allDisplaysDistance
|
property real monitorDistance: effect.allDisplaysDistance
|
||||||
property real targetDistance: effect.allDisplaysDistance
|
property real targetDistance: effect.allDisplaysDistance
|
||||||
property real screenRotationY: displays.radianToDegree(monitorPlacement.rotationAngleRadians.y)
|
property real screenRotationY: displays.radianToDegree(monitorPlacement?.rotationAngleRadians.y ?? 0)
|
||||||
property real screenRotationX: displays.radianToDegree(monitorPlacement.rotationAngleRadians.x)
|
property real screenRotationX: displays.radianToDegree(monitorPlacement?.rotationAngleRadians.x ?? 0)
|
||||||
property matrix4x4 rotationMatrix: {
|
property matrix4x4 rotationMatrix: {
|
||||||
const matrix = Qt.matrix4x4();
|
const matrix = Qt.matrix4x4();
|
||||||
matrix.rotate(screenRotationY, Qt.vector3d(0, 1, 0));
|
matrix.rotate(screenRotationY, Qt.vector3d(0, 1, 0));
|
||||||
|
|
@ -51,6 +51,8 @@ Node {
|
||||||
eulerRotation.y: screenRotationY
|
eulerRotation.y: screenRotationY
|
||||||
eulerRotation.x: screenRotationX
|
eulerRotation.x: screenRotationX
|
||||||
position: {
|
position: {
|
||||||
|
if (!monitorPlacement) return Qt.vector3d(0, 0, 0);
|
||||||
|
|
||||||
const displayNwu =
|
const displayNwu =
|
||||||
monitorPlacement.centerNoRotate
|
monitorPlacement.centerNoRotate
|
||||||
.times(monitorDistance / effect.allDisplaysDistance);
|
.times(monitorDistance / effect.allDisplaysDistance);
|
||||||
|
|
@ -112,6 +114,19 @@ Node {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// release references to displays and stale indexes
|
||||||
|
onScreensChanged: {
|
||||||
|
breezyDesktop.focusedMonitorIndex = -1;
|
||||||
|
zoomOutAnimation.stop();
|
||||||
|
zoomInAnimation.stop();
|
||||||
|
zoomOnFocusSequence.stop();
|
||||||
|
|
||||||
|
zoomOutAnimation.target = null;
|
||||||
|
zoomInAnimation.target = null;
|
||||||
|
zoomOutSeqAnimation.target = null;
|
||||||
|
zoomInSeqAnimation.target = null;
|
||||||
|
}
|
||||||
|
|
||||||
NumberAnimation {
|
NumberAnimation {
|
||||||
id: zoomOutAnimation
|
id: zoomOutAnimation
|
||||||
property: "monitorDistance"
|
property: "monitorDistance"
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ import QtQuick
|
||||||
import QtQuick3D
|
import QtQuick3D
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: root
|
id: cameraController
|
||||||
|
|
||||||
required property Camera camera
|
required property Camera camera
|
||||||
required property var fovDetails
|
required property var fovDetails
|
||||||
|
|
@ -13,9 +13,6 @@ Item {
|
||||||
property bool sbsEnabled: effect.sbsEnabled
|
property bool sbsEnabled: effect.sbsEnabled
|
||||||
property bool customBannerEnabled: effect.customBannerEnabled
|
property bool customBannerEnabled: effect.customBannerEnabled
|
||||||
|
|
||||||
implicitWidth: parent.width
|
|
||||||
implicitHeight: parent.height
|
|
||||||
|
|
||||||
Displays {
|
Displays {
|
||||||
id: displays
|
id: displays
|
||||||
}
|
}
|
||||||
|
|
@ -63,7 +60,7 @@ Item {
|
||||||
function updateFOV() {
|
function updateFOV() {
|
||||||
const aspectRatio = displayResolution[0] / displayResolution[1];
|
const aspectRatio = displayResolution[0] / displayResolution[1];
|
||||||
camera.fieldOfView = displays.radianToDegree(displays.diagonalToCrossFOVs(
|
camera.fieldOfView = displays.radianToDegree(displays.diagonalToCrossFOVs(
|
||||||
displays.degreeToRadian(root.diagonalFOV),
|
displays.degreeToRadian(cameraController.diagonalFOV),
|
||||||
aspectRatio
|
aspectRatio
|
||||||
).vertical);
|
).vertical);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,7 @@ QtObject {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function fovDetails(screens, viewportWidth, viewportHeight, viewportDiagonalFOV, lensDistanceRatio, defaultDisplayDistance, wrappingChoice) {
|
function buildFovDetails(screens, viewportWidth, viewportHeight, viewportDiagonalFOV, lensDistanceRatio, defaultDisplayDistance, wrappingChoice) {
|
||||||
const aspect = viewportWidth / viewportHeight;
|
const aspect = viewportWidth / viewportHeight;
|
||||||
const fovRadians = diagonalToCrossFOVs(degreeToRadian(viewportDiagonalFOV), aspect);
|
const fovRadians = diagonalToCrossFOVs(degreeToRadian(viewportDiagonalFOV), aspect);
|
||||||
const defaultDistanceVerticalRadians = 2 * Math.atan(Math.tan(fovRadians.vertical / 2) / defaultDisplayDistance);
|
const defaultDistanceVerticalRadians = 2 * Math.atan(Math.tan(fovRadians.vertical / 2) / defaultDisplayDistance);
|
||||||
|
|
|
||||||
|
|
@ -25,10 +25,10 @@ Item {
|
||||||
|
|
||||||
property real viewportDiagonalFOVDegrees: effect.diagonalFOV
|
property real viewportDiagonalFOVDegrees: effect.diagonalFOV
|
||||||
property var viewportResolution: effect.displayResolution
|
property var viewportResolution: effect.displayResolution
|
||||||
property var screens: KWinComponents.Workspace.screens
|
property bool mirrorPhysicalDisplays: effect.physicalDisplaysMode === 2
|
||||||
// .filter(function(screen) {
|
property var screens: KWinComponents.Workspace.screens.filter(function(screen) {
|
||||||
// return supportedModels.includes(screen.model);
|
return mirrorPhysicalDisplays || screen.name.includes("BreezyDesktop") || supportedModels.some(model => screen.model.includes(model));
|
||||||
// })
|
})
|
||||||
|
|
||||||
// x value for placing the viewport in the middle of all screens
|
// x value for placing the viewport in the middle of all screens
|
||||||
property real screensXMid: {
|
property real screensXMid: {
|
||||||
|
|
@ -62,7 +62,7 @@ Item {
|
||||||
id: displays
|
id: displays
|
||||||
}
|
}
|
||||||
|
|
||||||
property var fovDetails: displays.fovDetails(
|
property var fovDetails: displays.buildFovDetails(
|
||||||
screens,
|
screens,
|
||||||
viewportResolution[0],
|
viewportResolution[0],
|
||||||
viewportResolution[1],
|
viewportResolution[1],
|
||||||
|
|
@ -116,13 +116,16 @@ Item {
|
||||||
|
|
||||||
BreezyDesktop {
|
BreezyDesktop {
|
||||||
id: breezyDesktop
|
id: breezyDesktop
|
||||||
|
screens: root.screens
|
||||||
|
fovDetails: root.fovDetails
|
||||||
|
monitorPlacements: root.monitorPlacements
|
||||||
}
|
}
|
||||||
|
|
||||||
CameraController {
|
CameraController {
|
||||||
id: cameraController
|
id: cameraController
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
camera: camera
|
camera: camera
|
||||||
fovDetails: fovDetails
|
fovDetails: root.fovDetails
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue