Address some z-ordering issues in overlay windows

This commit is contained in:
Brad Davis 2016-01-05 17:16:45 -08:00
parent 95f821d61a
commit 1b82200ecb
7 changed files with 206 additions and 33 deletions

View file

@ -8,33 +8,6 @@ qmlWindow = new OverlayWindow({
visible: true
});
//qmlWindow.eventBridge.webEventReceived.connect(function(data) {
// print("JS Side event received: " + data);
//});
//
//var titles = ["A", "B", "C"];
//var titleIndex = 0;
//
//Script.setInterval(function() {
// qmlWindow.eventBridge.emitScriptEvent("JS Event sent");
// var size = qmlWindow.size;
// var position = qmlWindow.position;
// print("Window visible: " + qmlWindow.visible)
// if (qmlWindow.visible) {
// print("Window size: " + size.x + "x" + size.y)
// print("Window pos: " + position.x + "x" + position.y)
// qmlWindow.setVisible(false);
// } else {
// qmlWindow.setVisible(true);
// qmlWindow.setTitle(titles[titleIndex]);
// qmlWindow.setSize(320 + Math.random() * 100, 240 + Math.random() * 100);
// titleIndex += 1;
// titleIndex %= titles.length;
// }
//}, 2 * 1000);
//
//Script.setTimeout(function() {
// print("Closing script");
// qmlWindow.close();
// Script.stop();
//}, 15 * 1000)
Script.setInterval(function() {
qmlWindow.raise();
}, 2 * 1000);

View file

@ -16,6 +16,7 @@ import "styles"
DialogContainer {
id: root
HifiConstants { id: hifi }
z: 1000
objectName: "AddressBarDialog"

View file

@ -0,0 +1,165 @@
var OFFSCREEN_ROOT_OBJECT_NAME = "desktopRoot"
var OFFSCREEN_WINDOW_OBJECT_NAME = "topLevelWindow"
function findChild(item, name) {
for (var i = 0; i < item.children.length; ++i) {
if (item.children[i].objectName === name) {
return item.children[i];
}
}
return null;
}
function findParent(item, name) {
while (item) {
if (item.objectName === name) {
return item;
}
item = item.parent;
}
return null;
}
function getDesktop(item) {
return findParent(item, OFFSCREEN_ROOT_OBJECT_NAME);
}
function findRootMenu(item) {
item = getDesktop(item);
return item ? item.rootMenu : null;
}
function getTopLevelWindows(item) {
var desktop = getDesktop(item);
var currentWindows = [];
if (!desktop) {
console.log("Could not find desktop for " + item)
return currentWindows;
}
for (var i = 0; i < desktop.children.length; ++i) {
var child = desktop.children[i];
if (Global.OFFSCREEN_WINDOW_OBJECT_NAME === child.objectName) {
var windowId = child.toString();
currentWindows.push(child)
}
}
return currentWindows;
}
function getDesktopWindow(item) {
item = findParent(item, OFFSCREEN_WINDOW_OBJECT_NAME);
return item;
}
function closeWindow(item) {
item = findDialog(item);
if (item) {
item.enabled = false
} else {
console.warn("Could not find top level dialog")
}
}
function findMenuChild(menu, childName) {
if (!menu) {
return null;
}
if (menu.type !== 2) {
console.warn("Tried to find child of a non-menu");
return null;
}
var items = menu.items;
var count = items.length;
for (var i = 0; i < count; ++i) {
var child = items[i];
var name;
switch (child.type) {
case 2:
name = child.title;
break;
case 1:
name = child.text;
break;
default:
break;
}
if (name && name === childName) {
return child;
}
}
}
function findMenu(rootMenu, path) {
if ('string' === typeof(path)) {
path = [ path ]
}
var currentMenu = rootMenu;
for (var i = 0; currentMenu && i < path.length; ++i) {
currentMenu = findMenuChild(currentMenu, path[i]);
}
return currentMenu;
}
function findInRootMenu(item, path) {
return findMenu(findRootMenu(item), path);
}
function menuItemsToListModel(parent, items) {
var newListModel = Qt.createQmlObject('import QtQuick 2.5; ListModel {}', parent);
for (var i = 0; i < items.length; ++i) {
var item = items[i];
switch (item.type) {
case 2:
newListModel.append({"type":item.type, "name": item.title, "item": item})
break;
case 1:
newListModel.append({"type":item.type, "name": item.text, "item": item})
break;
case 0:
newListModel.append({"type":item.type, "name": "-----", "item": item})
break;
}
}
return newListModel;
}
function raiseWindow(item) {
var targetWindow = getDesktopWindow(item);
if (!targetWindow) {
console.warn("Could not find top level window for " + item);
return;
}
var desktop = getDesktop(targetWindow);
if (!desktop) {
//console.warn("Could not find desktop for window " + targetWindow);
return;
}
var maxZ = 0;
var minZ = 100000;
var windows = desktop.windows;
windows.sort(function(a, b){
return a.z - b.z;
});
var lastZ = -1;
var lastTargetZ = -1;
for (var i = 0; i < windows.length; ++i) {
var window = windows[i];
if (window.z > lastZ) {
lastZ = window.z;
++lastTargetZ;
}
window.z = lastTargetZ;
}
targetWindow.z = lastTargetZ + 1;
}

View file

@ -5,6 +5,8 @@ import QtWebChannel 1.0
import QtWebSockets 1.0
import "qrc:///qtwebchannel/qwebchannel.js" as WebChannel
import "Global.js" as Global
import "controls"
import "styles"
@ -23,6 +25,10 @@ VrDialog {
contentImplicitWidth: clientArea.implicitWidth
contentImplicitHeight: clientArea.implicitHeight
property alias source: pageLoader.source
function raiseWindow() {
Global.raiseWindow(root)
}
Item {
id: clientArea

View file

@ -2,16 +2,23 @@ import Hifi 1.0
import QtQuick 2.5
import QtQuick.Controls 1.4
import "Global.js" as Global
// This is our primary 'window' object to which all dialogs and controls will
// be childed.
Root {
id: root
objectName: "desktopRoot"
anchors.fill: parent
objectName: Global.OFFSCREEN_ROOT_OBJECT_NAME
anchors.fill: parent;
property var windows: [];
property var rootMenu: Menu {
objectName: "rootMenu"
}
onChildrenChanged: {
windows = Global.getTopLevelWindows(root);
}
onParentChanged: {
forceActiveFocus();
}

View file

@ -3,6 +3,8 @@ import QtQuick.Controls 1.2
import "."
import "../styles"
import "../Global.js" as Global
/*
* FIXME Need to create a client property here so that objects can be
* placed in it without having to think about positioning within the outer
@ -45,9 +47,18 @@ DialogBase {
// trigger making it visible.
if (enabled) {
visible = true;
if (root.parent) {
Global.raiseWindow(root);
}
}
}
onParentChanged: {
if (enabled && parent) {
Global.raiseWindow(root);
}
}
// The actual animator
Behavior on opacity {
NumberAnimation {
@ -60,6 +71,12 @@ DialogBase {
onOpacityChanged: {
visible = (opacity != 0.0);
}
Component.onCompleted: {
if (visible) {
Global.raiseWindow(root);
}
}
// Some dialogs should be destroyed when they become invisible,
// so handle that
@ -118,6 +135,7 @@ DialogBase {
y: root.titleY
width: root.titleWidth
height: root.titleHeight
onClicked: Global.raiseWindow(root)
drag {
target: root

View file

@ -15,6 +15,8 @@
#include <QtScript/QScriptEngine>
#include <QtQuick/QQuickItem>
#include <QtQml/QQmlContext>
#include <QtQml/QQmlEngine>
#include <QtWebSockets/QWebSocketServer>
#include <QtWebSockets/QWebSocket>
@ -141,6 +143,7 @@ QScriptValue QmlWindowClass::internalConstructor(const QString& qmlSource,
Q_ARG(std::function<void(QQmlContext*, QObject*)>, [&](QQmlContext* context, QObject* object) {
setupServer();
retVal = function(context, object);
context->engine()->setObjectOwnership(retVal->_qmlWindow, QQmlEngine::CppOwnership);
registerObject(url.toLower(), retVal);
if (!title.isEmpty()) {
retVal->setTitle(title);
@ -274,7 +277,7 @@ void QmlWindowClass::hasClosed() {
}
void QmlWindowClass::raise() {
// FIXME
QMetaObject::invokeMethod(_qmlWindow, "raiseWindow", Qt::QueuedConnection);
}
#include "QmlWindowClass.moc"