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 "styles"
import "windows"
import "windows-uit"
Window {
id: root

View file

@ -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;

View file

@ -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<OffscreenUi>();
if (_keyboardDeviceHasFocus && offscreenUi && offscreenUi->getWindow()->activeFocusItem() != offscreenUi->getRootItem()) {
@ -4882,24 +4880,42 @@ 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 {
if (_displayPlugin) {
return getActiveDisplayPlugin()->isThrottled();
}
return false;
}
bool Application::hasFocus() const {
if (_displayPlugin) {
return getActiveDisplayPlugin()->hasFocus();
}
return false;
}
glm::vec2 Application::getViewportDimensions() const {
return toGlm(getDeviceSize());

View file

@ -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) {

View file

@ -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);

View file

@ -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<glm::vec3>& 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<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 obj = engine->newObject();
if (quat.x != quat.x || quat.y != quat.y || quat.z != quat.z || quat.w != quat.w) {

View file

@ -43,6 +43,9 @@ 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);