335 lines · 11.5 KB · Text
RawDownload
////  InteractiveWindow.qml////  Created by Thijs Wenker on 2018-06-25//  Copyright 2018 High Fidelity, Inc.////  Distributed under the Apache License, Version 2.0.//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html// import QtQuick 2.3 import "windows" as Windowsimport "controls"import controlsUit 1.0 as Controlsimport "styles"import stylesUit 1.0 Windows.Window {    id: root;    HifiConstants { id: hifi }    title: "InteractiveWindow";    resizable: true;    // Virtual window visibility    shown: false;    focus: true;    property var channel;    // Don't destroy on close... otherwise the JS/C++ will have a dangling pointer    destroyOnCloseButton: false;     signal selfDestruct();     property var additionalFlags: 0;    property var overrideFlags: 0;     property var source;    property var dynamicContent;    property var nativeWindow;     // custom visibility flag for interactiveWindow to proxy virtualWindow.shown / nativeWindow.visible    property var interactiveWindowVisible: true;     property point interactiveWindowPosition;     property size interactiveWindowSize;     // Keyboard control properties in case needed by QML content.    property bool keyboardEnabled: false;    property bool keyboardRaised: false;    property bool punctuationMode: false;     property int presentationMode: 0;     property var initialized: false;    onSourceChanged: {        if (dynamicContent) {            dynamicContent.destroy();            dynamicContent = null;        }        QmlSurface.load(source, contentHolder, function(newObject) {            dynamicContent = newObject;            updateInteractiveWindowSizeForMode();            if (dynamicContent && dynamicContent.anchors) {                dynamicContent.anchors.fill = contentHolder;            }        });    }        Timer {        id: timer        interval: 500;        repeat: false;        onTriggered: {            updateContentParent();        }    }     function updateInteractiveWindowPositionForMode() {        if (presentationMode === Desktop.PresentationMode.VIRTUAL) {            x = interactiveWindowPosition.x;            y = interactiveWindowPosition.y;        } else if (presentationMode === Desktop.PresentationMode.NATIVE && nativeWindow) {            if (interactiveWindowPosition.x === 0 && interactiveWindowPosition.y === 0) {                // default position for native window in center of main application window                nativeWindow.x = Math.floor(Window.x + (Window.innerWidth / 2) - (interactiveWindowSize.width / 2));                nativeWindow.y = Math.floor(Window.y + (Window.innerHeight / 2) - (interactiveWindowSize.height / 2));            } else {                nativeWindow.x = interactiveWindowPosition.x;                nativeWindow.y = interactiveWindowPosition.y;            }        }    }     function updateInteractiveWindowSizeForMode() {        root.width = interactiveWindowSize.width;        root.height = interactiveWindowSize.height;        contentHolder.width = interactiveWindowSize.width;        contentHolder.height = interactiveWindowSize.height;         if (presentationMode === Desktop.PresentationMode.NATIVE && nativeWindow) {            nativeWindow.width = interactiveWindowSize.width;            nativeWindow.height = interactiveWindowSize.height;        }    }     function updateContentParent() {        if (presentationMode === Desktop.PresentationMode.VIRTUAL) {            contentHolder.parent = root;        } else if (presentationMode === Desktop.PresentationMode.NATIVE && nativeWindow) {            contentHolder.parent = nativeWindow.contentItem;        }    }     function setupPresentationMode() {        if (presentationMode === Desktop.PresentationMode.VIRTUAL) {            if (nativeWindow) {                nativeWindow.setVisible(false);            }            updateInteractiveWindowPositionForMode();            shown = interactiveWindowVisible;        } else if (presentationMode === Desktop.PresentationMode.NATIVE) {            shown = false;            if (nativeWindow) {                updateInteractiveWindowPositionForMode();                nativeWindow.setVisible(interactiveWindowVisible);            }        } else if (presentationMode === modeNotSet) {            console.error("presentationMode should be set.");        }    }     Component.onCompleted: {                x = interactiveWindowPosition.x;        y = interactiveWindowPosition.y;        width = interactiveWindowSize.width;        height = interactiveWindowSize.height;         nativeWindow = Qt.createQmlObject('            import QtQuick 2.3;            import QtQuick.Window 2.3;             Window {                id: root;                width: interactiveWindowSize.width                height: interactiveWindowSize.height                // fix for missing content on OSX initial startup with a non-maximized interface window. It seems that in this case, we cannot update                // the content parent during creation of the Window root. This added delay will update the parent after the root has finished loading.                Component.onCompleted: {                    timer.start();                }                 Rectangle {                    color: hifi.colors.baseGray                    anchors.fill: parent                }            }', root, 'InteractiveWindow.qml->nativeWindow');        nativeWindow.title = root.title;        var nativeWindowFlags = Qt.Window |            Qt.WindowTitleHint |            Qt.WindowSystemMenuHint |            Qt.WindowCloseButtonHint |            Qt.WindowMaximizeButtonHint |            Qt.WindowMinimizeButtonHint;        // only use the always on top feature for non Windows OS        if (Qt.platform.os !== "windows" && (root.additionalFlags & Desktop.ALWAYS_ON_TOP)) {            nativeWindowFlags |= Qt.WindowStaysOnTopHint;        }        nativeWindow.flags = root.overrideFlags || nativeWindowFlags;         nativeWindow.x = interactiveWindowPosition.x;        nativeWindow.y = interactiveWindowPosition.y;         nativeWindow.width = interactiveWindowSize.width;        nativeWindow.height = interactiveWindowSize.height;         nativeWindow.xChanged.connect(function() {            if (presentationMode === Desktop.PresentationMode.NATIVE && nativeWindow.visible) {                interactiveWindowPosition = Qt.point(nativeWindow.x, interactiveWindowPosition.y);            }        });                nativeWindow.yChanged.connect(function() {            if (presentationMode === Desktop.PresentationMode.NATIVE && nativeWindow.visible) {                interactiveWindowPosition = Qt.point(interactiveWindowPosition.x, nativeWindow.y);            }        });         nativeWindow.widthChanged.connect(function() {            if (presentationMode === Desktop.PresentationMode.NATIVE && nativeWindow.visible) {                interactiveWindowSize = Qt.size(nativeWindow.width, interactiveWindowSize.height);            }        });                nativeWindow.heightChanged.connect(function() {            if (presentationMode === Desktop.PresentationMode.NATIVE && nativeWindow.visible) {                interactiveWindowSize = Qt.size(interactiveWindowSize.width, nativeWindow.height);            }        });         nativeWindow.closing.connect(function(closeEvent) {            closeEvent.accepted = false;            windowClosed();        });         // finally set the initial window mode:        setupPresentationMode();        updateContentParent();         initialized = true;    }     // Handle message traffic from the script that launched us to the loaded QML    function fromScript(message) {        if (root.dynamicContent && root.dynamicContent.fromScript) {            root.dynamicContent.fromScript(message);        }    }     function show() {        interactiveWindowVisible = true;        raiseWindow();    }     function raiseWindow() {        if (presentationMode === Desktop.PresentationMode.VIRTUAL) {            raise();        } else if (presentationMode === Desktop.PresentationMode.NATIVE && nativeWindow) {            nativeWindow.raise();        }    }     // Handle message traffic from our loaded QML to the script that launched us    signal sendToScript(var message);     // Children of this InteractiveWindow Item are able to request a new width and height    // for the parent Item (this one) and its associated C++ InteractiveWindow using these methods.    function onRequestNewWidth(newWidth) {        interactiveWindowSize.width = newWidth;        updateInteractiveWindowSizeForMode();    }    function onRequestNewHeight(newHeight) {        interactiveWindowSize.height = newHeight;        updateInteractiveWindowSizeForMode();    }        // These signals are used to forward key-related events from the QML to the C++.    signal keyPressEvent(int key, int modifiers);    signal keyReleaseEvent(int key, int modifiers);     onDynamicContentChanged: {        if (dynamicContent && dynamicContent.sendToScript) {            dynamicContent.sendToScript.connect(sendToScript);        }         if (dynamicContent && dynamicContent.requestNewWidth) {            dynamicContent.requestNewWidth.connect(onRequestNewWidth);        }         if (dynamicContent && dynamicContent.requestNewHeight) {            dynamicContent.requestNewHeight.connect(onRequestNewHeight);        }         if (dynamicContent && dynamicContent.keyPressEvent) {            dynamicContent.keyPressEvent.connect(keyPressEvent);        }         if (dynamicContent && dynamicContent.keyReleaseEvent) {            dynamicContent.keyReleaseEvent.connect(keyReleaseEvent);        }    }     onInteractiveWindowVisibleChanged: {        if (presentationMode === Desktop.PresentationMode.VIRTUAL) {            shown = interactiveWindowVisible;        } else if (presentationMode === Desktop.PresentationMode.NATIVE && nativeWindow) {            if (!nativeWindow.visible && interactiveWindowVisible) {                nativeWindow.showNormal();            } else {                nativeWindow.setVisible(interactiveWindowVisible);            }        }    }     onTitleChanged: {        if (nativeWindow) {            nativeWindow.title = title;        }    }     onXChanged: {        if (presentationMode === Desktop.PresentationMode.VIRTUAL) {            interactiveWindowPosition = Qt.point(x, interactiveWindowPosition.y);        }    }     onYChanged: {        if (presentationMode === Desktop.PresentationMode.VIRTUAL) {            interactiveWindowPosition = Qt.point(interactiveWindowPosition.x, y);        }    }     onWidthChanged: {        if (presentationMode === Desktop.PresentationMode.VIRTUAL) {            interactiveWindowSize = Qt.size(width, interactiveWindowSize.height);        }    }     onHeightChanged: {        if (presentationMode === Desktop.PresentationMode.VIRTUAL) {            interactiveWindowSize = Qt.size(interactiveWindowSize.width, height);        }    }     onPresentationModeChanged: {        if (initialized) {            setupPresentationMode();            updateContentParent();        }    }     onWindowClosed: {        // set invisible on close, to make it not re-appear unintended after switching PresentationMode        interactiveWindowVisible = false;         if ((root.additionalFlags & Desktop.CLOSE_BUTTON_HIDES) !== Desktop.CLOSE_BUTTON_HIDES) {            selfDestruct();        }    }     Item {        id: contentHolder        anchors.fill: parent    }}