diff --git a/interface/resources/qml/desktop/Desktop.qml b/interface/resources/qml/desktop/Desktop.qml index eb80f2a7f4..cf6c22b8fd 100644 --- a/interface/resources/qml/desktop/Desktop.qml +++ b/interface/resources/qml/desktop/Desktop.qml @@ -4,6 +4,7 @@ import QtQuick.Dialogs 1.2 as OriginalDialogs; import "../dialogs" import "../menus" +import "../js/Utils.js" as Utils // This is our primary 'desktop' object to which all VR dialogs and // windows will be childed. @@ -18,11 +19,18 @@ FocusScope { // The VR version of the primary menu property var rootMenu: Menu { objectName: "rootMenu" } + readonly property alias zLevels: zLevels + QtObject { + id: zLevels; + readonly property real normal: 0 + readonly property real top: 2000 + readonly property real modal: 4000 + readonly property real menu: 8000 + } + QtObject { id: d - readonly property int zBasisNormal: 0 - readonly property int zBasisAlwaysOnTop: 4096 - readonly property int zBasisModal: 8192 + readonly property var messageDialogBuilder: Component { MessageDialog { } } function findChild(item, name) { for (var i = 0; i < item.children.length; ++i) { @@ -75,15 +83,12 @@ FocusScope { return currentWindows; } - function getDesktopWindow(item) { return findParentMatching(item, isTopLevelWindow) } function fixupZOrder(windows, basis, topWindow) { - windows.sort(function(a, b){ - return a.z - b.z; - }); + windows.sort(function(a, b){ return a.z - b.z; }); if ((topWindow.z >= basis) && (windows[windows.length - 1] === topWindow)) { return; @@ -122,33 +127,22 @@ FocusScope { return lastTargetZ; } - function raiseWindow(item) { - var targetWindow = getDesktopWindow(item); - if (!targetWindow) { - console.warn("Could not find top level window for " + item); - return; - } - - if (!desktop) { - console.warn("Could not find desktop for window " + targetWindow); - return; - } - + function raiseWindow(targetWindow) { var predicate; var zBasis; if (isModalWindow(targetWindow)) { predicate = isModalWindow; - zBasis = zBasisModal + zBasis = zLevels.modal } else if (isAlwaysOnTopWindow(targetWindow)) { predicate = function(window) { return (isAlwaysOnTopWindow(window) && !isModalWindow(window)); } - zBasis = zBasisAlwaysOnTop + zBasis = zLevels.top } else { predicate = function(window) { return (!isAlwaysOnTopWindow(window) && !isModalWindow(window)); } - zBasis = zBasisNormal + zBasis = zLevels.normal } var windows = getTopLevelWindows(predicate); @@ -157,11 +151,64 @@ FocusScope { } function raise(item) { - d.raiseWindow(item); + var targetWindow = d.getDesktopWindow(item); + if (!targetWindow) { + console.warn("Could not find top level window for " + item); + return; + } + + // Fix up the Z-order (takes into account if this is a modal window) + d.raiseWindow(targetWindow); + var setFocus = true; + if (!d.isModalWindow(targetWindow)) { + var modalWindows = d.getTopLevelWindows(d.isModalWindow); + if (modalWindows.length) { + setFocus = false; + } + } + + if (setFocus) { + focus = true; + } + + reposition(targetWindow); } + function reposition(item) { + 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 windowRect = targetWindow.framedRect(); + var minPosition = Qt.vector2d(-windowRect.x, -windowRect.y); + var maxPosition = Qt.vector2d(desktop.width - windowRect.width, desktop.height - windowRect.height); + var newPosition; + if (targetWindow.x === -1 && targetWindow.y === -1) { + // Set initial window position + newPosition = Utils.randomPosition(minPosition, maxPosition); + } else { + newPosition = Utils.clampVector(Qt.vector2d(targetWindow.x, targetWindow.y), minPosition, maxPosition); + } + targetWindow.x = newPosition.x; + targetWindow.y = newPosition.y; + } + + function repositionAll() { + var windows = d.getTopLevelWindows(); + for (var i = 0; i < windows.length; ++i) { + reposition(windows[i]); + } + } + + onHeightChanged: repositionAll(); + onWidthChanged: repositionAll(); - Component { id: messageDialogBuilder; MessageDialog { } } function messageBox(properties) { return messageDialogBuilder.createObject(desktop, properties); } @@ -232,8 +279,6 @@ FocusScope { z: 9999; visible: false; color: "red" ColorAnimation on color { from: "#7fffff00"; to: "#7f0000ff"; duration: 1000; loops: 9999 } } - - } diff --git a/interface/resources/qml/js/Utils.js b/interface/resources/qml/js/Utils.js new file mode 100644 index 0000000000..417c8c1641 --- /dev/null +++ b/interface/resources/qml/js/Utils.js @@ -0,0 +1,16 @@ + +function clamp(value, min, max) { + return Math.min(Math.max(value, min), max); +} + +function clampVector(value, min, max) { + return Qt.vector2d( + clamp(value.x, min.x, max.x), + clamp(value.y, min.y, max.y)) +} + +function randomPosition(min, max) { + return Qt.vector2d( + Math.random() * (max.x - min.x), + Math.random() * (max.y - min.y)); +} diff --git a/interface/resources/qml/menus/MenuMouseHandler.qml b/interface/resources/qml/menus/MenuMouseHandler.qml index d22b30e8d9..bb2cc7d459 100644 --- a/interface/resources/qml/menus/MenuMouseHandler.qml +++ b/interface/resources/qml/menus/MenuMouseHandler.qml @@ -5,7 +5,6 @@ import "." Item { id: root - property int zBasis: 9000 anchors.fill: parent MouseArea { @@ -94,7 +93,7 @@ Item { function buildMenu(items, targetPosition) { var model = toModel(items); // Menu's must be childed to desktop for Z-ordering - var newMenu = menuViewMaker.createObject(desktop, { model: model, z: topMenu ? topMenu.z + 1 : zBasis }); + var newMenu = menuViewMaker.createObject(desktop, { model: model, z: topMenu ? topMenu.z + 1 : desktop.zLevels.menu }); if (targetPosition) { newMenu.x = targetPosition.x newMenu.y = targetPosition.y - newMenu.height / 3 * 1 diff --git a/interface/resources/qml/windows/Frame.qml b/interface/resources/qml/windows/Frame.qml index 4bcf3998f4..0ada0028e4 100644 --- a/interface/resources/qml/windows/Frame.qml +++ b/interface/resources/qml/windows/Frame.qml @@ -1,6 +1,7 @@ import QtQuick 2.5 import "../controls" +import "../js/Utils.js" as Utils Item { id: frame @@ -34,7 +35,7 @@ Item { function deltaSize(dx, dy) { var newSize = Qt.vector2d(window.width + dx, window.height + dy); - newSize = clampVector(newSize, window.minSize, window.maxSize); + newSize = Utils.clampVector(newSize, window.minSize, window.maxSize); window.width = newSize.x window.height = newSize.y } diff --git a/interface/resources/qml/windows/Window.qml b/interface/resources/qml/windows/Window.qml index 21bd8f3dec..8fe45f2227 100644 --- a/interface/resources/qml/windows/Window.qml +++ b/interface/resources/qml/windows/Window.qml @@ -19,6 +19,7 @@ Fadable { // decorations can extend outside it. implicitHeight: content.height implicitWidth: content.width + x: -1; y: -1 property int modality: Qt.NonModal @@ -71,15 +72,11 @@ Fadable { // frame styles, like a full desktop frame to simulate a modal window property var frame: DefaultFrame { } - Component.onCompleted: raise(); children: [ frame, content, activator ] - Component.onDestruction: { - content.destroy(); - console.log("Destroyed " + window); - windowDestroyed(); - } + Component.onCompleted: raise(); + Component.onDestruction: windowDestroyed(); onParentChanged: raise(); onVisibleChanged: { @@ -96,9 +93,6 @@ Fadable { function raise() { if (visible && parent) { desktop.raise(window) - if (!focus) { - focus = true; - } } } @@ -118,15 +112,15 @@ Fadable { visible = false; } - function clamp(value, min, max) { - return Math.min(Math.max(value, min), max); + function framedRect() { + if (!frame || !frame.decoration) { + return Qt.rect(0, 0, window.width, window.height) + } + return Qt.rect(frame.decoration.anchors.leftMargin, frame.decoration.anchors.topMargin, + window.width - frame.decoration.anchors.leftMargin - frame.decoration.anchors.rightMargin, + window.height - frame.decoration.anchors.topMargin - frame.decoration.anchors.bottomMargin) } - function clampVector(value, min, max) { - return Qt.vector2d( - clamp(value.x, min.x, max.x), - clamp(value.y, min.y, max.y)) - } Keys.onPressed: { switch(event.key) { diff --git a/tests/ui/qml/main.qml b/tests/ui/qml/main.qml index b343d2404e..c970cd711b 100644 --- a/tests/ui/qml/main.qml +++ b/tests/ui/qml/main.qml @@ -7,7 +7,6 @@ import "../../../interface/resources/qml" import "../../../interface/resources/qml/windows" import "../../../interface/resources/qml/dialogs" import "../../../interface/resources/qml/hifi" -import "../../../interface/resources/qml/hifi/dialogs" ApplicationWindow { id: appWindow @@ -184,6 +183,7 @@ ApplicationWindow { Window { id: yellow + objectName: "Yellow" closable: true visible: true resizable: true