From 04df84974c7e231e0078b1e8ca1cab048fd64bed Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Fri, 15 Apr 2016 19:50:12 -0700 Subject: [PATCH] handle repositioning of qml windows --- interface/resources/qml/Browser.qml | 2 +- interface/resources/qml/desktop/Desktop.qml | 78 +++++++++++++++++-- interface/src/Application.cpp | 30 +++++-- .../ControllerScriptingInterface.cpp | 4 +- .../scripting/ControllerScriptingInterface.h | 2 +- libraries/shared/src/RegisteredMetaTypes.cpp | 54 ++++++++++++- libraries/shared/src/RegisteredMetaTypes.h | 5 +- 7 files changed, 154 insertions(+), 21 deletions(-) diff --git a/interface/resources/qml/Browser.qml b/interface/resources/qml/Browser.qml index 89ab333a0d..eec3428e97 100644 --- a/interface/resources/qml/Browser.qml +++ b/interface/resources/qml/Browser.qml @@ -4,7 +4,7 @@ import QtWebEngine 1.1 import "controls" import "styles" -import "windows" +import "windows-uit" Window { id: root diff --git a/interface/resources/qml/desktop/Desktop.qml b/interface/resources/qml/desktop/Desktop.qml index beea0d8c64..b312969cbc 100644 --- a/interface/resources/qml/desktop/Desktop.qml +++ b/interface/resources/qml/desktop/Desktop.qml @@ -21,8 +21,29 @@ FocusScope { objectName: "desktop" anchors.fill: parent - onHeightChanged: d.repositionAll(); - onWidthChanged: d.repositionAll(); + property vector4d recommendedRect: vector4d(0,0,0,0); + + onHeightChanged: { + var oldRecommendedRect = recommendedRect; + var newRecommendedRectJS = Controller.getRecommendedOverlayRect(); + var newRecommendedRect = Qt.vector4d(newRecommendedRectJS.x, newRecommendedRectJS.y, newRecommendedRectJS.z, newRecommendedRectJS.w); + if (oldRecommendedRect != Qt.vector4d(0,0,0,0) + && oldRecommendedRect != newRecommendedRect) { + d.repositionAll(); + } + recommendedRect = newRecommendedRect; + } + + onWidthChanged: { + var oldRecommendedRect = recommendedRect; + var newRecommendedRectJS = Controller.getRecommendedOverlayRect(); + var newRecommendedRect = Qt.vector4d(newRecommendedRectJS.x, newRecommendedRectJS.y, newRecommendedRectJS.z, newRecommendedRectJS.w); + if (oldRecommendedRect != Qt.vector4d(0,0,0,0) + && oldRecommendedRect != newRecommendedRect) { + d.repositionAll(); + } + recommendedRect = newRecommendedRect; + } // Controls and windows can trigger this signal to ensure the desktop becomes visible // when they're opened. @@ -202,12 +223,23 @@ FocusScope { // } } + function getAvatarInputsWindow() { + for (var i = 0; i < desktop.children.length; ++i) { + var child = desktop.children[i]; + if (child.objectName === "AvatarInputs") { + return child; + } + } + } function repositionAll() { var windows = d.getTopLevelWindows(); for (var i = 0; i < windows.length; ++i) { reposition(windows[i]); } + + // also reposition the avatar inputs window if need be + repositionWindow(getAvatarInputsWindow(), true); } } @@ -238,32 +270,62 @@ FocusScope { } function reposition(item) { + var targetWindow = d.getDesktopWindow(item); + repositionWindow(targetWindow, true); + } + + function repositionWindow(targetWindow, forceReposition) { if (desktop.width === 0 || desktop.height === 0) { return; } - var targetWindow = d.getDesktopWindow(item); if (!targetWindow) { console.warn("Could not find top level window for " + item); return; } + var recommended = Controller.getRecommendedOverlayRect(); var newPosition = Qt.vector2d(targetWindow.x, targetWindow.y); - // If the window is completely offscreen, reposition it - if ((targetWindow.x > desktop.width || (targetWindow.x + targetWindow.width) < 0) || - (targetWindow.y > desktop.height || (targetWindow.y + targetWindow.height) < 0)) { + + // if we asked to force reposition, or if the window is completely outside of the recommended rectangle, reposition it + if (forceReposition || (targetWindow.x > recommended.z || (targetWindow.x + targetWindow.width) < recommended.x) || + (targetWindow.y > recommended.w || (targetWindow.y + targetWindow.height) < recommended.y)) { newPosition.x = -1 newPosition.y = -1 } + if (newPosition.x === -1 && newPosition.y === -1) { // Set initial window position // var minPosition = Qt.vector2d(-windowRect.x, -windowRect.y); // var maxPosition = Qt.vector2d(desktop.width - windowRect.width, desktop.height - windowRect.height); // newPosition = Utils.clampVector(newPosition, minPosition, maxPosition); // newPosition = Utils.randomPosition(minPosition, maxPosition); - newPosition = Qt.vector2d(desktop.width / 2 - targetWindow.width / 2, - desktop.height / 2 - targetWindow.height / 2); + + // center in new space + //newPosition = Qt.vector2d(desktop.width / 2 - targetWindow.width / 2, + // desktop.height / 2 - targetWindow.height / 2); + + var oldRecommendedRect = recommendedRect; + var oldRecommendedDimmensions = { x: oldRecommendedRect.z - oldRecommendedRect.x, y: oldRecommendedRect.w - oldRecommendedRect.y }; + var newRecommendedRect = Controller.getRecommendedOverlayRect(); + var newRecommendedDimmensions = { x: newRecommendedRect.z - newRecommendedRect.x, y: newRecommendedRect.w - newRecommendedRect.y }; + + var originRelativeX = (targetWindow.x - oldRecommendedRect.x); + var originRelativeY = (targetWindow.y - oldRecommendedRect.y); + if (isNaN(originRelativeX)) { + originRelativeX = 0; + } + if (isNaN(originRelativeY)) { + originRelativeY = 0; + } + var fractionX = Utils.clamp(originRelativeX / oldRecommendedDimmensions.x, 0, 1); + var fractionY = Utils.clamp(originRelativeY / oldRecommendedDimmensions.y, 0, 1); + + var newX = (fractionX * newRecommendedDimmensions.x) + newRecommendedRect.x; + var newY = (fractionY * newRecommendedDimmensions.y) + newRecommendedRect.y; + + newPosition = Qt.vector2d(newX, newY); } targetWindow.x = newPosition.x; targetWindow.y = newPosition.y; diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 573fcabfa8..fb485e6672 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2669,8 +2669,6 @@ void Application::idle(uint64_t now) { _overlayConductor.setEnabled(Menu::getInstance()->isOptionChecked(MenuOption::Overlays)); } - - // If the offscreen Ui has something active that is NOT the root, then assume it has keyboard focus. auto offscreenUi = DependencyManager::get(); if (_keyboardDeviceHasFocus && offscreenUi && offscreenUi->getWindow()->activeFocusItem() != offscreenUi->getRootItem()) { @@ -4882,23 +4880,41 @@ QRect Application::getRenderingGeometry() const { } glm::uvec2 Application::getUiSize() const { - return getActiveDisplayPlugin()->getRecommendedUiSize(); + glm::uvec2 result; + if (_displayPlugin) { + result = getActiveDisplayPlugin()->getRecommendedUiSize(); + } + return result; } glm::uvec4 Application::getRecommendedOverlayRect() const { - return getActiveDisplayPlugin()->getRecommendedOverlayRect(); + glm::uvec4 result; + if (_displayPlugin) { + result = getActiveDisplayPlugin()->getRecommendedOverlayRect(); + } + return result; } QSize Application::getDeviceSize() const { - return fromGlm(getActiveDisplayPlugin()->getRecommendedRenderSize()); + QSize result; + if (_displayPlugin) { + result = fromGlm(getActiveDisplayPlugin()->getRecommendedRenderSize()); + } + return result; } bool Application::isThrottleRendering() const { - return getActiveDisplayPlugin()->isThrottled(); + if (_displayPlugin) { + return getActiveDisplayPlugin()->isThrottled(); + } + return false; } bool Application::hasFocus() const { - return getActiveDisplayPlugin()->hasFocus(); + if (_displayPlugin) { + return getActiveDisplayPlugin()->hasFocus(); + } + return false; } glm::vec2 Application::getViewportDimensions() const { diff --git a/interface/src/scripting/ControllerScriptingInterface.cpp b/interface/src/scripting/ControllerScriptingInterface.cpp index e9349782b5..00a2c624bc 100644 --- a/interface/src/scripting/ControllerScriptingInterface.cpp +++ b/interface/src/scripting/ControllerScriptingInterface.cpp @@ -80,9 +80,9 @@ glm::vec2 ControllerScriptingInterface::getViewportDimensions() const { return qApp->getUiSize(); } -glm::vec4 ControllerScriptingInterface::getRecommendedOverlayRect() const { +QVariant ControllerScriptingInterface::getRecommendedOverlayRect() const { auto rect = qApp->getRecommendedOverlayRect(); - return vec4(rect.x, rect.y, rect.z, rect.w); + return vec4toVariant(vec4(rect.x, rect.y, rect.z, rect.w)); } controller::InputController* ControllerScriptingInterface::createInputController(const QString& deviceName, const QString& tracker) { diff --git a/interface/src/scripting/ControllerScriptingInterface.h b/interface/src/scripting/ControllerScriptingInterface.h index d99237b07d..fc8d125839 100644 --- a/interface/src/scripting/ControllerScriptingInterface.h +++ b/interface/src/scripting/ControllerScriptingInterface.h @@ -96,7 +96,7 @@ public slots: virtual void releaseJoystick(int joystickIndex); virtual glm::vec2 getViewportDimensions() const; - virtual glm::vec4 getRecommendedOverlayRect() const; + virtual QVariant getRecommendedOverlayRect() const; /// Factory to create an InputController virtual controller::InputController* createInputController(const QString& deviceName, const QString& tracker); diff --git a/libraries/shared/src/RegisteredMetaTypes.cpp b/libraries/shared/src/RegisteredMetaTypes.cpp index 953fdb3582..331a8dfd51 100644 --- a/libraries/shared/src/RegisteredMetaTypes.cpp +++ b/libraries/shared/src/RegisteredMetaTypes.cpp @@ -128,7 +128,7 @@ void vec3FromScriptValue(const QScriptValue &object, glm::vec3 &vec3) { vec3.z = object.property("z").toVariant().toFloat(); } -QVariant vec3toVariant(const glm::vec3 &vec3) { +QVariant vec3toVariant(const glm::vec3& vec3) { if (vec3.x != vec3.x || vec3.y != vec3.y || vec3.z != vec3.z) { // if vec3 contains a NaN don't try to convert it return QVariant(); @@ -140,6 +140,18 @@ QVariant vec3toVariant(const glm::vec3 &vec3) { return result; } +QVariant vec4toVariant(const glm::vec4& vec4) { + if (isNaN(vec4.x) || isNaN(vec4.y) || isNaN(vec4.z) || isNaN(vec4.w)) { + // if vec4 contains a NaN don't try to convert it + return QVariant(); + } + QVariantMap result; + result["x"] = vec4.x; + result["y"] = vec4.y; + result["z"] = vec4.z; + result["w"] = vec4.w; + return result; +} QScriptValue qVectorVec3ToScriptValue(QScriptEngine* engine, const QVector& vector) { QScriptValue array = engine->newArray(); @@ -194,6 +206,46 @@ glm::vec3 vec3FromVariant(const QVariant &object) { return vec3FromVariant(object, valid); } +glm::vec4 vec4FromVariant(const QVariant &object, bool& valid) { + glm::vec4 v; + valid = false; + if (!object.isValid() || object.isNull()) { + return v; + } + else if (object.canConvert()) { + v = glm::vec4(object.toFloat()); + valid = true; + } + else if (object.canConvert()) { + auto qvec4 = qvariant_cast(object); + v.x = qvec4.x(); + v.y = qvec4.y(); + v.z = qvec4.z(); + v.w = qvec4.w(); + valid = true; + } + else { + auto map = object.toMap(); + auto x = map["x"]; + auto y = map["y"]; + auto z = map["z"]; + auto w = map["w"]; + if (x.canConvert() && y.canConvert() && z.canConvert() && w.canConvert()) { + v.x = x.toFloat(); + v.y = y.toFloat(); + v.z = z.toFloat(); + v.w = w.toFloat(); + valid = true; + } + } + return v; +} + +glm::vec4 vec4FromVariant(const QVariant &object) { + bool valid = false; + return vec4FromVariant(object, valid); +} + QScriptValue quatToScriptValue(QScriptEngine* engine, const glm::quat &quat) { QScriptValue obj = engine->newObject(); if (quat.x != quat.x || quat.y != quat.y || quat.z != quat.z || quat.w != quat.w) { diff --git a/libraries/shared/src/RegisteredMetaTypes.h b/libraries/shared/src/RegisteredMetaTypes.h index 652ec26fe7..9b699b97c4 100644 --- a/libraries/shared/src/RegisteredMetaTypes.h +++ b/libraries/shared/src/RegisteredMetaTypes.h @@ -43,12 +43,15 @@ void mat4FromScriptValue(const QScriptValue& object, glm::mat4& mat4); // Vec4 QScriptValue vec4toScriptValue(QScriptEngine* engine, const glm::vec4& vec4); void vec4FromScriptValue(const QScriptValue& object, glm::vec4& vec4); +QVariant vec4toVariant(const glm::vec4& vec4); +glm::vec4 vec4FromVariant(const QVariant &object, bool& valid); +glm::vec4 vec4FromVariant(const QVariant &object); // Vec3 QScriptValue vec3toScriptValue(QScriptEngine* engine, const glm::vec3 &vec3); void vec3FromScriptValue(const QScriptValue &object, glm::vec3 &vec3); -QVariant vec3toVariant(const glm::vec3 &vec3); +QVariant vec3toVariant(const glm::vec3& vec3); glm::vec3 vec3FromVariant(const QVariant &object, bool& valid); glm::vec3 vec3FromVariant(const QVariant &object);