handle repositioning of qml windows

This commit is contained in:
Brad Hefta-Gaub 2016-04-15 19:50:12 -07:00
parent d80bf58021
commit 04df84974c
7 changed files with 154 additions and 21 deletions

View file

@ -4,7 +4,7 @@ import QtWebEngine 1.1
import "controls" import "controls"
import "styles" import "styles"
import "windows" import "windows-uit"
Window { Window {
id: root id: root

View file

@ -21,8 +21,29 @@ FocusScope {
objectName: "desktop" objectName: "desktop"
anchors.fill: parent anchors.fill: parent
onHeightChanged: d.repositionAll(); property vector4d recommendedRect: vector4d(0,0,0,0);
onWidthChanged: d.repositionAll();
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 // Controls and windows can trigger this signal to ensure the desktop becomes visible
// when they're opened. // 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() { function repositionAll() {
var windows = d.getTopLevelWindows(); var windows = d.getTopLevelWindows();
for (var i = 0; i < windows.length; ++i) { for (var i = 0; i < windows.length; ++i) {
reposition(windows[i]); reposition(windows[i]);
} }
// also reposition the avatar inputs window if need be
repositionWindow(getAvatarInputsWindow(), true);
} }
} }
@ -238,32 +270,62 @@ FocusScope {
} }
function reposition(item) { function reposition(item) {
var targetWindow = d.getDesktopWindow(item);
repositionWindow(targetWindow, true);
}
function repositionWindow(targetWindow, forceReposition) {
if (desktop.width === 0 || desktop.height === 0) { if (desktop.width === 0 || desktop.height === 0) {
return; return;
} }
var targetWindow = d.getDesktopWindow(item);
if (!targetWindow) { if (!targetWindow) {
console.warn("Could not find top level window for " + item); console.warn("Could not find top level window for " + item);
return; return;
} }
var recommended = Controller.getRecommendedOverlayRect();
var newPosition = Qt.vector2d(targetWindow.x, targetWindow.y); 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) || // if we asked to force reposition, or if the window is completely outside of the recommended rectangle, reposition it
(targetWindow.y > desktop.height || (targetWindow.y + targetWindow.height) < 0)) { 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.x = -1
newPosition.y = -1 newPosition.y = -1
} }
if (newPosition.x === -1 && newPosition.y === -1) { if (newPosition.x === -1 && newPosition.y === -1) {
// Set initial window position // Set initial window position
// var minPosition = Qt.vector2d(-windowRect.x, -windowRect.y); // var minPosition = Qt.vector2d(-windowRect.x, -windowRect.y);
// var maxPosition = Qt.vector2d(desktop.width - windowRect.width, desktop.height - windowRect.height); // var maxPosition = Qt.vector2d(desktop.width - windowRect.width, desktop.height - windowRect.height);
// newPosition = Utils.clampVector(newPosition, minPosition, maxPosition); // newPosition = Utils.clampVector(newPosition, minPosition, maxPosition);
// newPosition = Utils.randomPosition(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.x = newPosition.x;
targetWindow.y = newPosition.y; targetWindow.y = newPosition.y;

View file

@ -2669,8 +2669,6 @@ void Application::idle(uint64_t now) {
_overlayConductor.setEnabled(Menu::getInstance()->isOptionChecked(MenuOption::Overlays)); _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. // If the offscreen Ui has something active that is NOT the root, then assume it has keyboard focus.
auto offscreenUi = DependencyManager::get<OffscreenUi>(); auto offscreenUi = DependencyManager::get<OffscreenUi>();
if (_keyboardDeviceHasFocus && offscreenUi && offscreenUi->getWindow()->activeFocusItem() != offscreenUi->getRootItem()) { if (_keyboardDeviceHasFocus && offscreenUi && offscreenUi->getWindow()->activeFocusItem() != offscreenUi->getRootItem()) {
@ -4882,23 +4880,41 @@ QRect Application::getRenderingGeometry() const {
} }
glm::uvec2 Application::getUiSize() const { glm::uvec2 Application::getUiSize() const {
return getActiveDisplayPlugin()->getRecommendedUiSize(); glm::uvec2 result;
if (_displayPlugin) {
result = getActiveDisplayPlugin()->getRecommendedUiSize();
}
return result;
} }
glm::uvec4 Application::getRecommendedOverlayRect() const { glm::uvec4 Application::getRecommendedOverlayRect() const {
return getActiveDisplayPlugin()->getRecommendedOverlayRect(); glm::uvec4 result;
if (_displayPlugin) {
result = getActiveDisplayPlugin()->getRecommendedOverlayRect();
}
return result;
} }
QSize Application::getDeviceSize() const { QSize Application::getDeviceSize() const {
return fromGlm(getActiveDisplayPlugin()->getRecommendedRenderSize()); QSize result;
if (_displayPlugin) {
result = fromGlm(getActiveDisplayPlugin()->getRecommendedRenderSize());
}
return result;
} }
bool Application::isThrottleRendering() const { bool Application::isThrottleRendering() const {
return getActiveDisplayPlugin()->isThrottled(); if (_displayPlugin) {
return getActiveDisplayPlugin()->isThrottled();
}
return false;
} }
bool Application::hasFocus() const { bool Application::hasFocus() const {
return getActiveDisplayPlugin()->hasFocus(); if (_displayPlugin) {
return getActiveDisplayPlugin()->hasFocus();
}
return false;
} }
glm::vec2 Application::getViewportDimensions() const { glm::vec2 Application::getViewportDimensions() const {

View file

@ -80,9 +80,9 @@ glm::vec2 ControllerScriptingInterface::getViewportDimensions() const {
return qApp->getUiSize(); return qApp->getUiSize();
} }
glm::vec4 ControllerScriptingInterface::getRecommendedOverlayRect() const { QVariant ControllerScriptingInterface::getRecommendedOverlayRect() const {
auto rect = qApp->getRecommendedOverlayRect(); 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) { controller::InputController* ControllerScriptingInterface::createInputController(const QString& deviceName, const QString& tracker) {

View file

@ -96,7 +96,7 @@ public slots:
virtual void releaseJoystick(int joystickIndex); virtual void releaseJoystick(int joystickIndex);
virtual glm::vec2 getViewportDimensions() const; virtual glm::vec2 getViewportDimensions() const;
virtual glm::vec4 getRecommendedOverlayRect() const; virtual QVariant getRecommendedOverlayRect() const;
/// Factory to create an InputController /// Factory to create an InputController
virtual controller::InputController* createInputController(const QString& deviceName, const QString& tracker); virtual controller::InputController* createInputController(const QString& deviceName, const QString& tracker);

View file

@ -128,7 +128,7 @@ void vec3FromScriptValue(const QScriptValue &object, glm::vec3 &vec3) {
vec3.z = object.property("z").toVariant().toFloat(); 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.x != vec3.x || vec3.y != vec3.y || vec3.z != vec3.z) {
// if vec3 contains a NaN don't try to convert it // if vec3 contains a NaN don't try to convert it
return QVariant(); return QVariant();
@ -140,6 +140,18 @@ QVariant vec3toVariant(const glm::vec3 &vec3) {
return result; 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<glm::vec3>& vector) { QScriptValue qVectorVec3ToScriptValue(QScriptEngine* engine, const QVector<glm::vec3>& vector) {
QScriptValue array = engine->newArray(); QScriptValue array = engine->newArray();
@ -194,6 +206,46 @@ glm::vec3 vec3FromVariant(const QVariant &object) {
return vec3FromVariant(object, valid); 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<float>()) {
v = glm::vec4(object.toFloat());
valid = true;
}
else if (object.canConvert<QVector4D>()) {
auto qvec4 = qvariant_cast<QVector4D>(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<float>() && y.canConvert<float>() && z.canConvert<float>() && w.canConvert<float>()) {
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 quatToScriptValue(QScriptEngine* engine, const glm::quat &quat) {
QScriptValue obj = engine->newObject(); QScriptValue obj = engine->newObject();
if (quat.x != quat.x || quat.y != quat.y || quat.z != quat.z || quat.w != quat.w) { if (quat.x != quat.x || quat.y != quat.y || quat.z != quat.z || quat.w != quat.w) {

View file

@ -43,12 +43,15 @@ void mat4FromScriptValue(const QScriptValue& object, glm::mat4& mat4);
// Vec4 // Vec4
QScriptValue vec4toScriptValue(QScriptEngine* engine, const glm::vec4& vec4); QScriptValue vec4toScriptValue(QScriptEngine* engine, const glm::vec4& vec4);
void vec4FromScriptValue(const QScriptValue& object, 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 // Vec3
QScriptValue vec3toScriptValue(QScriptEngine* engine, const glm::vec3 &vec3); QScriptValue vec3toScriptValue(QScriptEngine* engine, const glm::vec3 &vec3);
void vec3FromScriptValue(const QScriptValue &object, 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, bool& valid);
glm::vec3 vec3FromVariant(const QVariant &object); glm::vec3 vec3FromVariant(const QVariant &object);