mirror of
https://github.com/lubosz/overte.git
synced 2025-04-09 02:42:35 +02:00
Cleanup of QML windowing and message boxes
This commit is contained in:
parent
bb02a1eda2
commit
746c388f7a
59 changed files with 3279 additions and 2893 deletions
|
@ -12,37 +12,37 @@ import Hifi 1.0
|
|||
import QtQuick 2.4
|
||||
import "controls"
|
||||
import "styles"
|
||||
import "windows"
|
||||
|
||||
DialogContainer {
|
||||
Window {
|
||||
id: root
|
||||
HifiConstants { id: hifi }
|
||||
z: 1000
|
||||
|
||||
anchors.centerIn: parent
|
||||
objectName: "AddressBarDialog"
|
||||
|
||||
property bool destroyOnInvisible: false
|
||||
property real scale: 1.25 // Make this dialog a little larger than normal
|
||||
destroyOnInvisible: false
|
||||
resizable: false
|
||||
scale: 1.25 // Make this dialog a little larger than normal
|
||||
|
||||
implicitWidth: addressBarDialog.implicitWidth
|
||||
implicitHeight: addressBarDialog.implicitHeight
|
||||
|
||||
x: parent ? parent.width / 2 - width / 2 : 0
|
||||
y: parent ? parent.height / 2 - height / 2 : 0
|
||||
property int maximumX: parent ? parent.width - width : 0
|
||||
property int maximumY: parent ? parent.height - height : 0
|
||||
|
||||
|
||||
Rectangle {
|
||||
id: dragRegion
|
||||
visible: dragMouseArea.containsMouse
|
||||
}
|
||||
width: addressBarDialog.implicitWidth
|
||||
height: addressBarDialog.implicitHeight
|
||||
|
||||
AddressBarDialog {
|
||||
id: addressBarDialog
|
||||
z: dragRegion.z + 1
|
||||
implicitWidth: backgroundImage.width
|
||||
implicitHeight: backgroundImage.height
|
||||
|
||||
Timer {
|
||||
running: root.visible
|
||||
interval: 500
|
||||
repeat: true
|
||||
onTriggered: {
|
||||
if (root.enabled && !addressLine.activeFocus) {
|
||||
addressLine.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Image {
|
||||
id: backgroundImage
|
||||
|
||||
|
@ -52,45 +52,9 @@ DialogContainer {
|
|||
property int inputAreaHeight: 56.0 * root.scale // Height of the background's input area
|
||||
property int inputAreaStep: (height - inputAreaHeight) / 2
|
||||
|
||||
MouseArea {
|
||||
id: dragMouseArea
|
||||
// Drag the icon
|
||||
width: parent.height
|
||||
height: parent.height
|
||||
x: 0
|
||||
y: 0
|
||||
hoverEnabled: true
|
||||
drag {
|
||||
target: root
|
||||
minimumX: -parent.inputAreaStep
|
||||
minimumY: -parent.inputAreaStep
|
||||
maximumX: root.parent ? root.maximumX : 0
|
||||
maximumY: root.parent ? root.maximumY + parent.inputAreaStep : 0
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
MouseArea {
|
||||
// Drag the input rectangle
|
||||
width: parent.width - parent.height
|
||||
height: parent.inputAreaHeight
|
||||
x: parent.height
|
||||
y: parent.inputAreaStep
|
||||
drag {
|
||||
target: root
|
||||
minimumX: -parent.inputAreaStep
|
||||
minimumY: -parent.inputAreaStep
|
||||
maximumX: root.parent ? root.maximumX : 0
|
||||
maximumY: root.parent ? root.maximumY + parent.inputAreaStep : 0
|
||||
}
|
||||
}
|
||||
|
||||
Image {
|
||||
id: backArrow
|
||||
|
||||
source: addressBarDialog.backEnabled ? "../images/left-arrow.svg" : "../images/left-arrow-disabled.svg"
|
||||
|
||||
anchors {
|
||||
fill: parent
|
||||
leftMargin: parent.height + hifi.layout.spacing + 6
|
||||
|
@ -110,9 +74,7 @@ DialogContainer {
|
|||
|
||||
Image {
|
||||
id: forwardArrow
|
||||
|
||||
source: addressBarDialog.forwardEnabled ? "../images/right-arrow.svg" : "../images/right-arrow-disabled.svg"
|
||||
|
||||
anchors {
|
||||
fill: parent
|
||||
leftMargin: parent.height + hifi.layout.spacing * 9
|
||||
|
@ -130,6 +92,7 @@ DialogContainer {
|
|||
}
|
||||
}
|
||||
|
||||
// FIXME replace with TextField
|
||||
TextInput {
|
||||
id: addressLine
|
||||
|
||||
|
@ -139,61 +102,35 @@ DialogContainer {
|
|||
rightMargin: hifi.layout.spacing * 2
|
||||
topMargin: parent.inputAreaStep + hifi.layout.spacing
|
||||
bottomMargin: parent.inputAreaStep + hifi.layout.spacing
|
||||
|
||||
}
|
||||
|
||||
font.pixelSize: hifi.fonts.pixelSize * root.scale * 0.75
|
||||
|
||||
helperText: "Go to: place, @user, /path, network address"
|
||||
|
||||
onAccepted: {
|
||||
event.accepted = true // Generates erroneous error in program log, "ReferenceError: event is not defined".
|
||||
addressBarDialog.loadAddress(addressLine.text)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
onEnabledChanged: {
|
||||
if (enabled) {
|
||||
addressLine.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
|
||||
Timer {
|
||||
running: root.enabled
|
||||
interval: 500
|
||||
repeat: true
|
||||
onTriggered: {
|
||||
if (root.enabled && !addressLine.activeFocus) {
|
||||
addressLine.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onVisibleChanged: {
|
||||
if (!visible) {
|
||||
if (visible) {
|
||||
addressLine.forceActiveFocus()
|
||||
} else {
|
||||
addressLine.text = ""
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function toggleOrGo() {
|
||||
if (addressLine.text == "") {
|
||||
enabled = false
|
||||
} else {
|
||||
if (addressLine.text != "") {
|
||||
addressBarDialog.loadAddress(addressLine.text)
|
||||
}
|
||||
root.close();
|
||||
}
|
||||
|
||||
Keys.onPressed: {
|
||||
switch (event.key) {
|
||||
case Qt.Key_Escape:
|
||||
case Qt.Key_Back:
|
||||
if (enabled) {
|
||||
enabled = false
|
||||
event.accepted = true
|
||||
}
|
||||
root.close()
|
||||
event.accepted = true
|
||||
break
|
||||
case Qt.Key_Enter:
|
||||
case Qt.Key_Return:
|
||||
|
|
|
@ -12,23 +12,23 @@ Window {
|
|||
title: "Browser"
|
||||
resizable: true
|
||||
destroyOnInvisible: true
|
||||
width: 800
|
||||
height: 600
|
||||
|
||||
Component.onCompleted: {
|
||||
enabled = true
|
||||
visible = true
|
||||
addressBar.text = webview.url
|
||||
}
|
||||
|
||||
onParentChanged: {
|
||||
if (visible && enabled) {
|
||||
if (visible) {
|
||||
addressBar.forceActiveFocus();
|
||||
addressBar.selectAll()
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
width: 800
|
||||
height: 600
|
||||
|
||||
anchors.fill: parent
|
||||
Rectangle {
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
|
|
|
@ -1,112 +0,0 @@
|
|||
//
|
||||
// ErrorDialog.qml
|
||||
//
|
||||
// Created by David Rowe on 30 May 2015
|
||||
// Copyright 2015 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 Hifi 1.0
|
||||
import QtQuick 2.4
|
||||
import "controls"
|
||||
import "styles"
|
||||
|
||||
DialogContainer {
|
||||
id: root
|
||||
HifiConstants { id: hifi }
|
||||
|
||||
Component.onCompleted: {
|
||||
enabled = true
|
||||
}
|
||||
|
||||
onParentChanged: {
|
||||
if (visible && enabled) {
|
||||
forceActiveFocus()
|
||||
}
|
||||
}
|
||||
|
||||
implicitWidth: content.implicitWidth
|
||||
implicitHeight: content.implicitHeight
|
||||
|
||||
x: parent ? parent.width / 2 - width / 2 : 0
|
||||
y: parent ? parent.height / 2 - height / 2 : 0
|
||||
|
||||
ErrorDialog {
|
||||
id: content
|
||||
|
||||
implicitWidth: box.width
|
||||
implicitHeight: icon.height + hifi.layout.spacing * 2
|
||||
|
||||
Border {
|
||||
id: box
|
||||
|
||||
width: 512
|
||||
color: "#ebebeb"
|
||||
radius: 2
|
||||
border.width: 1
|
||||
border.color: "#000000"
|
||||
|
||||
Image {
|
||||
id: icon
|
||||
|
||||
source: "../images/address-bar-error-icon.svg"
|
||||
width: 40
|
||||
height: 40
|
||||
anchors {
|
||||
left: parent.left
|
||||
leftMargin: hifi.layout.spacing
|
||||
verticalCenter: parent.verticalCenter
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
id: messageText
|
||||
|
||||
font.pixelSize: hifi.fonts.pixelSize * 0.6
|
||||
font.weight: Font.Bold
|
||||
|
||||
anchors {
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
text: content.text
|
||||
}
|
||||
|
||||
Image {
|
||||
source: "../images/address-bar-error-close.svg"
|
||||
width: 20
|
||||
height: 20
|
||||
anchors {
|
||||
right: parent.right
|
||||
rightMargin: hifi.layout.spacing * 2
|
||||
verticalCenter: parent.verticalCenter
|
||||
}
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
cursorShape: "PointingHandCursor"
|
||||
onClicked: {
|
||||
content.accept()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Keys.onPressed: {
|
||||
if (!enabled) {
|
||||
return
|
||||
}
|
||||
switch (event.key) {
|
||||
case Qt.Key_Escape:
|
||||
case Qt.Key_Back:
|
||||
case Qt.Key_Enter:
|
||||
case Qt.Key_Return:
|
||||
event.accepted = true
|
||||
content.accept()
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,179 +0,0 @@
|
|||
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 findParentMatching(item, predicate) {
|
||||
while (item) {
|
||||
if (predicate(item)) {
|
||||
break;
|
||||
}
|
||||
item = item.parent;
|
||||
}
|
||||
return item;
|
||||
}
|
||||
|
||||
function findParentByName(item, name) {
|
||||
return findParentMatching(item, function(item) {
|
||||
var testName = name;
|
||||
var result = (item.name === testName);
|
||||
return result;
|
||||
});
|
||||
}
|
||||
|
||||
function findRootMenu(item) {
|
||||
item = getDesktop(item);
|
||||
return item ? item.rootMenu : null;
|
||||
}
|
||||
|
||||
function isDesktop(item) {
|
||||
return item.desktopRoot;
|
||||
}
|
||||
|
||||
function isTopLevelWindow(item) {
|
||||
return item.topLevelWindow;
|
||||
}
|
||||
|
||||
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 (isTopLevelWindow(child)) {
|
||||
var windowId = child.toString();
|
||||
currentWindows.push(child)
|
||||
}
|
||||
}
|
||||
return currentWindows;
|
||||
}
|
||||
|
||||
|
||||
function getDesktop(item) {
|
||||
return findParentMatching(item, isDesktop);
|
||||
}
|
||||
|
||||
function getDesktopWindow(item) {
|
||||
return findParentMatching(item, isTopLevelWindow)
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
|
@ -1,11 +1,10 @@
|
|||
import QtQuick 2.5
|
||||
import Hifi 1.0 as Hifi
|
||||
import QtQuick 2.3
|
||||
import QtQuick.Controls 1.2
|
||||
import QtQuick.Controls.Styles 1.3
|
||||
import QtWebEngine 1.1
|
||||
import "controls"
|
||||
|
||||
VrDialog {
|
||||
import "controls"
|
||||
import "windows" as Windows
|
||||
|
||||
Windows.Window {
|
||||
id: root
|
||||
width: 800
|
||||
height: 800
|
||||
|
@ -13,12 +12,10 @@ VrDialog {
|
|||
|
||||
Hifi.InfoView {
|
||||
id: infoView
|
||||
// Fille the client area
|
||||
// Fill the client area
|
||||
anchors.fill: parent
|
||||
anchors.margins: parent.margins
|
||||
anchors.topMargin: parent.topMargin
|
||||
|
||||
WebEngineView {
|
||||
WebView {
|
||||
id: webview
|
||||
objectName: "WebView"
|
||||
anchors.fill: parent
|
||||
|
|
|
@ -12,29 +12,23 @@ import Hifi 1.0
|
|||
import QtQuick 2.4
|
||||
import "controls"
|
||||
import "styles"
|
||||
import "windows"
|
||||
|
||||
DialogContainer {
|
||||
Window {
|
||||
id: root
|
||||
HifiConstants { id: hifi }
|
||||
|
||||
objectName: "LoginDialog"
|
||||
|
||||
property bool destroyOnInvisible: false
|
||||
|
||||
implicitWidth: loginDialog.implicitWidth
|
||||
implicitHeight: loginDialog.implicitHeight
|
||||
|
||||
x: parent ? parent.width / 2 - width / 2 : 0
|
||||
y: parent ? parent.height / 2 - height / 2 : 0
|
||||
property int maximumX: parent ? parent.width - width : 0
|
||||
property int maximumY: parent ? parent.height - height : 0
|
||||
height: loginDialog.implicitHeight
|
||||
width: loginDialog.implicitWidth
|
||||
// FIXME make movable
|
||||
anchors.centerIn: parent
|
||||
destroyOnInvisible: false
|
||||
visible: false
|
||||
|
||||
LoginDialog {
|
||||
id: loginDialog
|
||||
|
||||
implicitWidth: backgroundRectangle.width
|
||||
implicitHeight: backgroundRectangle.height
|
||||
|
||||
readonly property int inputWidth: 500
|
||||
readonly property int inputHeight: 60
|
||||
readonly property int borderWidth: 30
|
||||
|
@ -47,46 +41,8 @@ DialogContainer {
|
|||
width: loginDialog.inputWidth + loginDialog.borderWidth * 2
|
||||
height: loginDialog.inputHeight * 6 + loginDialog.closeMargin * 2
|
||||
radius: loginDialog.closeMargin * 2
|
||||
|
||||
color: "#2c86b1"
|
||||
opacity: 0.85
|
||||
|
||||
MouseArea {
|
||||
width: parent.width
|
||||
height: parent.height
|
||||
anchors {
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
verticalCenter: parent.verticalCenter
|
||||
}
|
||||
drag {
|
||||
target: root
|
||||
minimumX: 0
|
||||
minimumY: 0
|
||||
maximumX: root.parent ? root.maximumX : 0
|
||||
maximumY: root.parent ? root.maximumY : 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Image {
|
||||
id: closeIcon
|
||||
source: "../images/login-close.svg"
|
||||
width: 20
|
||||
height: 20
|
||||
anchors {
|
||||
top: backgroundRectangle.top
|
||||
right: backgroundRectangle.right
|
||||
topMargin: loginDialog.closeMargin
|
||||
rightMargin: loginDialog.closeMargin
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
cursorShape: "PointingHandCursor"
|
||||
onClicked: {
|
||||
root.enabled = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
|
@ -324,18 +280,13 @@ DialogContainer {
|
|||
}
|
||||
}
|
||||
|
||||
onOpacityChanged: {
|
||||
// Set focus once animation is completed so that focus is set at start-up when not logged in
|
||||
if (opacity == 1.0) {
|
||||
username.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
|
||||
onVisibleChanged: {
|
||||
if (!visible) {
|
||||
username.text = ""
|
||||
password.text = ""
|
||||
loginDialog.statusText = ""
|
||||
} else {
|
||||
username.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -343,11 +294,10 @@ DialogContainer {
|
|||
switch (event.key) {
|
||||
case Qt.Key_Escape:
|
||||
case Qt.Key_Back:
|
||||
if (enabled) {
|
||||
enabled = false
|
||||
event.accepted = true
|
||||
}
|
||||
break
|
||||
root.close();
|
||||
event.accepted = true;
|
||||
break;
|
||||
|
||||
case Qt.Key_Enter:
|
||||
case Qt.Key_Return:
|
||||
if (username.activeFocus) {
|
||||
|
|
|
@ -1,45 +0,0 @@
|
|||
import Hifi 1.0
|
||||
import QtQuick 2.3
|
||||
import QtQuick.Controls 1.2
|
||||
import QtQuick.Controls.Styles 1.3
|
||||
import QtWebEngine 1.1
|
||||
import "controls"
|
||||
|
||||
VrDialog {
|
||||
title: "Test Dlg"
|
||||
id: testDialog
|
||||
objectName: "Browser"
|
||||
width: 720
|
||||
height: 720
|
||||
resizable: true
|
||||
|
||||
MarketplaceDialog {
|
||||
id: marketplaceDialog
|
||||
}
|
||||
|
||||
Item {
|
||||
id: clientArea
|
||||
// The client area
|
||||
anchors.fill: parent
|
||||
anchors.margins: parent.margins
|
||||
anchors.topMargin: parent.topMargin
|
||||
|
||||
WebEngineView {
|
||||
objectName: "WebView"
|
||||
id: webview
|
||||
url: "https://metaverse.highfidelity.com/marketplace"
|
||||
anchors.fill: parent
|
||||
onNavigationRequested: {
|
||||
console.log(request.url)
|
||||
if (!marketplaceDialog.navigationRequested(request.url)) {
|
||||
console.log("Application absorbed the request")
|
||||
request.action = WebView.IgnoreRequest;
|
||||
return;
|
||||
}
|
||||
console.log("Application passed on the request")
|
||||
request.action = WebView.AcceptRequest;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,337 +0,0 @@
|
|||
import Hifi 1.0 as Hifi
|
||||
import QtQuick 2.2
|
||||
import QtQuick.Controls 1.2
|
||||
import QtQuick.Dialogs 1.2
|
||||
import "controls"
|
||||
import "styles"
|
||||
|
||||
VrDialog {
|
||||
id: root
|
||||
HifiConstants { id: hifi }
|
||||
property real spacing: hifi.layout.spacing
|
||||
property real outerSpacing: hifi.layout.spacing * 2
|
||||
|
||||
destroyOnCloseButton: true
|
||||
destroyOnInvisible: true
|
||||
contentImplicitWidth: content.implicitWidth
|
||||
contentImplicitHeight: content.implicitHeight
|
||||
|
||||
Component.onCompleted: {
|
||||
enabled = true
|
||||
}
|
||||
|
||||
onParentChanged: {
|
||||
if (visible && enabled) {
|
||||
forceActiveFocus();
|
||||
}
|
||||
}
|
||||
|
||||
Hifi.MessageDialog {
|
||||
id: content
|
||||
clip: true
|
||||
|
||||
x: root.clientX
|
||||
y: root.clientY
|
||||
implicitHeight: contentColumn.implicitHeight + outerSpacing * 2
|
||||
implicitWidth: mainText.implicitWidth + outerSpacing * 2
|
||||
|
||||
Component.onCompleted: {
|
||||
root.title = title
|
||||
}
|
||||
|
||||
onTitleChanged: {
|
||||
root.title = title
|
||||
}
|
||||
|
||||
Column {
|
||||
anchors.fill: parent
|
||||
anchors.margins: 8
|
||||
id: contentColumn
|
||||
spacing: root.outerSpacing
|
||||
|
||||
Item {
|
||||
width: parent.width
|
||||
height: Math.max(icon.height, mainText.height + informativeText.height + root.spacing)
|
||||
|
||||
FontAwesome {
|
||||
id: icon
|
||||
width: content.icon ? 48 : 0
|
||||
height: content.icon ? 48 : 0
|
||||
visible: content.icon ? true : false
|
||||
font.pixelSize: 48
|
||||
verticalAlignment: Text.AlignTop
|
||||
horizontalAlignment: Text.AlignLeft
|
||||
color: iconColor()
|
||||
text: iconSymbol()
|
||||
|
||||
function iconSymbol() {
|
||||
switch (content.icon) {
|
||||
case Hifi.MessageDialog.Information:
|
||||
return "\uF05A"
|
||||
case Hifi.MessageDialog.Question:
|
||||
return "\uF059"
|
||||
case Hifi.MessageDialog.Warning:
|
||||
return "\uF071"
|
||||
case Hifi.MessageDialog.Critical:
|
||||
return "\uF057"
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return content.icon;
|
||||
}
|
||||
function iconColor() {
|
||||
switch (content.icon) {
|
||||
case Hifi.MessageDialog.Information:
|
||||
case Hifi.MessageDialog.Question:
|
||||
return "blue"
|
||||
case Hifi.MessageDialog.Warning:
|
||||
case Hifi.MessageDialog.Critical:
|
||||
return "red"
|
||||
default:
|
||||
break
|
||||
}
|
||||
return "black"
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
id: mainText
|
||||
anchors {
|
||||
left: icon.right
|
||||
leftMargin: root.spacing
|
||||
right: parent.right
|
||||
}
|
||||
text: content.text
|
||||
font.pointSize: 14
|
||||
font.weight: Font.Bold
|
||||
wrapMode: Text.WordWrap
|
||||
}
|
||||
|
||||
Text {
|
||||
id: informativeText
|
||||
anchors {
|
||||
left: icon.right
|
||||
right: parent.right
|
||||
top: mainText.bottom
|
||||
leftMargin: root.spacing
|
||||
topMargin: root.spacing
|
||||
}
|
||||
text: content.informativeText
|
||||
font.pointSize: 14
|
||||
wrapMode: Text.WordWrap
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Flow {
|
||||
id: buttons
|
||||
spacing: root.spacing
|
||||
layoutDirection: Qt.RightToLeft
|
||||
width: parent.width
|
||||
Button {
|
||||
id: okButton
|
||||
text: qsTr("OK")
|
||||
onClicked: content.click(StandardButton.Ok)
|
||||
visible: content.standardButtons & StandardButton.Ok
|
||||
}
|
||||
Button {
|
||||
id: openButton
|
||||
text: qsTr("Open")
|
||||
onClicked: content.click(StandardButton.Open)
|
||||
visible: content.standardButtons & StandardButton.Open
|
||||
}
|
||||
Button {
|
||||
id: saveButton
|
||||
text: qsTr("Save")
|
||||
onClicked: content.click(StandardButton.Save)
|
||||
visible: content.standardButtons & StandardButton.Save
|
||||
}
|
||||
Button {
|
||||
id: saveAllButton
|
||||
text: qsTr("Save All")
|
||||
onClicked: content.click(StandardButton.SaveAll)
|
||||
visible: content.standardButtons & StandardButton.SaveAll
|
||||
}
|
||||
Button {
|
||||
id: retryButton
|
||||
text: qsTr("Retry")
|
||||
onClicked: content.click(StandardButton.Retry)
|
||||
visible: content.standardButtons & StandardButton.Retry
|
||||
}
|
||||
Button {
|
||||
id: ignoreButton
|
||||
text: qsTr("Ignore")
|
||||
onClicked: content.click(StandardButton.Ignore)
|
||||
visible: content.standardButtons & StandardButton.Ignore
|
||||
}
|
||||
Button {
|
||||
id: applyButton
|
||||
text: qsTr("Apply")
|
||||
onClicked: content.click(StandardButton.Apply)
|
||||
visible: content.standardButtons & StandardButton.Apply
|
||||
}
|
||||
Button {
|
||||
id: yesButton
|
||||
text: qsTr("Yes")
|
||||
onClicked: content.click(StandardButton.Yes)
|
||||
visible: content.standardButtons & StandardButton.Yes
|
||||
}
|
||||
Button {
|
||||
id: yesAllButton
|
||||
text: qsTr("Yes to All")
|
||||
onClicked: content.click(StandardButton.YesToAll)
|
||||
visible: content.standardButtons & StandardButton.YesToAll
|
||||
}
|
||||
Button {
|
||||
id: noButton
|
||||
text: qsTr("No")
|
||||
onClicked: content.click(StandardButton.No)
|
||||
visible: content.standardButtons & StandardButton.No
|
||||
}
|
||||
Button {
|
||||
id: noAllButton
|
||||
text: qsTr("No to All")
|
||||
onClicked: content.click(StandardButton.NoToAll)
|
||||
visible: content.standardButtons & StandardButton.NoToAll
|
||||
}
|
||||
Button {
|
||||
id: discardButton
|
||||
text: qsTr("Discard")
|
||||
onClicked: content.click(StandardButton.Discard)
|
||||
visible: content.standardButtons & StandardButton.Discard
|
||||
}
|
||||
Button {
|
||||
id: resetButton
|
||||
text: qsTr("Reset")
|
||||
onClicked: content.click(StandardButton.Reset)
|
||||
visible: content.standardButtons & StandardButton.Reset
|
||||
}
|
||||
Button {
|
||||
id: restoreDefaultsButton
|
||||
text: qsTr("Restore Defaults")
|
||||
onClicked: content.click(StandardButton.RestoreDefaults)
|
||||
visible: content.standardButtons & StandardButton.RestoreDefaults
|
||||
}
|
||||
Button {
|
||||
id: cancelButton
|
||||
text: qsTr("Cancel")
|
||||
onClicked: content.click(StandardButton.Cancel)
|
||||
visible: content.standardButtons & StandardButton.Cancel
|
||||
}
|
||||
Button {
|
||||
id: abortButton
|
||||
text: qsTr("Abort")
|
||||
onClicked: content.click(StandardButton.Abort)
|
||||
visible: content.standardButtons & StandardButton.Abort
|
||||
}
|
||||
Button {
|
||||
id: closeButton
|
||||
text: qsTr("Close")
|
||||
onClicked: content.click(StandardButton.Close)
|
||||
visible: content.standardButtons & StandardButton.Close
|
||||
}
|
||||
Button {
|
||||
id: moreButton
|
||||
text: qsTr("Show Details...")
|
||||
onClicked: content.state = (content.state === "" ? "expanded" : "")
|
||||
visible: content.detailedText.length > 0
|
||||
}
|
||||
Button {
|
||||
id: helpButton
|
||||
text: qsTr("Help")
|
||||
onClicked: content.click(StandardButton.Help)
|
||||
visible: content.standardButtons & StandardButton.Help
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
id: details
|
||||
width: parent.width
|
||||
implicitHeight: detailedText.implicitHeight + root.spacing
|
||||
height: 0
|
||||
clip: true
|
||||
|
||||
anchors {
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
top: contentColumn.bottom
|
||||
topMargin: root.spacing
|
||||
leftMargin: root.outerSpacing
|
||||
rightMargin: root.outerSpacing
|
||||
}
|
||||
|
||||
Flickable {
|
||||
id: flickable
|
||||
contentHeight: detailedText.height
|
||||
anchors.fill: parent
|
||||
anchors.topMargin: root.spacing
|
||||
anchors.bottomMargin: root.outerSpacing
|
||||
TextEdit {
|
||||
id: detailedText
|
||||
text: content.detailedText
|
||||
width: details.width
|
||||
wrapMode: Text.WordWrap
|
||||
readOnly: true
|
||||
selectByMouse: true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
states: [
|
||||
State {
|
||||
name: "expanded"
|
||||
PropertyChanges {
|
||||
target: details
|
||||
height: root.height - contentColumn.height - root.spacing - root.outerSpacing
|
||||
}
|
||||
PropertyChanges {
|
||||
target: content
|
||||
implicitHeight: contentColumn.implicitHeight + root.spacing * 2 +
|
||||
detailedText.implicitHeight + root.outerSpacing * 2
|
||||
}
|
||||
PropertyChanges {
|
||||
target: moreButton
|
||||
text: qsTr("Hide Details")
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
Keys.onPressed: {
|
||||
if (!enabled) {
|
||||
return
|
||||
}
|
||||
|
||||
if (event.modifiers === Qt.ControlModifier)
|
||||
switch (event.key) {
|
||||
case Qt.Key_A:
|
||||
event.accepted = true
|
||||
detailedText.selectAll()
|
||||
break
|
||||
case Qt.Key_C:
|
||||
event.accepted = true
|
||||
detailedText.copy()
|
||||
break
|
||||
case Qt.Key_Period:
|
||||
if (Qt.platform.os === "osx") {
|
||||
event.accepted = true
|
||||
content.reject()
|
||||
}
|
||||
break
|
||||
} else switch (event.key) {
|
||||
case Qt.Key_Escape:
|
||||
case Qt.Key_Back:
|
||||
event.accepted = true
|
||||
content.reject()
|
||||
break
|
||||
|
||||
case Qt.Key_Enter:
|
||||
case Qt.Key_Return:
|
||||
event.accepted = true
|
||||
content.accept()
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,105 +0,0 @@
|
|||
//
|
||||
// Created by Bradley Austin Davis on 2015/11/14
|
||||
// Copyright 2015 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 Hifi 1.0
|
||||
import QtQuick 2.4
|
||||
import "controls"
|
||||
import "styles"
|
||||
|
||||
VrDialog {
|
||||
id: root
|
||||
HifiConstants { id: hifi }
|
||||
|
||||
property real spacing: hifi.layout.spacing
|
||||
property real outerSpacing: hifi.layout.spacing * 2
|
||||
|
||||
objectName: "RecorderDialog"
|
||||
|
||||
destroyOnInvisible: false
|
||||
destroyOnCloseButton: false
|
||||
|
||||
contentImplicitWidth: recorderDialog.width
|
||||
contentImplicitHeight: recorderDialog.height
|
||||
|
||||
RecorderDialog {
|
||||
id: recorderDialog
|
||||
x: root.clientX; y: root.clientY
|
||||
width: 800
|
||||
height: 128
|
||||
signal play()
|
||||
signal rewind()
|
||||
|
||||
onPlay: {
|
||||
console.log("Pressed play")
|
||||
player.isPlaying = !player.isPlaying
|
||||
}
|
||||
|
||||
onRewind: {
|
||||
console.log("Pressed rewind")
|
||||
player.position = 0
|
||||
}
|
||||
|
||||
Row {
|
||||
height: 32
|
||||
ButtonAwesome {
|
||||
id: cmdRecord
|
||||
visible: root.showRecordButton
|
||||
width: 32; height: 32
|
||||
text: "\uf111"
|
||||
iconColor: "red"
|
||||
onClicked: {
|
||||
console.log("Pressed record")
|
||||
status.text = "Recording";
|
||||
}
|
||||
}
|
||||
}
|
||||
Text {
|
||||
id: status
|
||||
anchors.top: parent.top
|
||||
anchors.right: parent.right
|
||||
width: 128
|
||||
text: "Idle"
|
||||
}
|
||||
|
||||
Player {
|
||||
id: player
|
||||
y: root.clientY + 64
|
||||
height: 64
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: parent.bottom
|
||||
|
||||
|
||||
|
||||
// onClicked: {
|
||||
// if (recordTimer.running) {
|
||||
// recordTimer.stop();
|
||||
// }
|
||||
// recordTimer.start();
|
||||
// }
|
||||
Timer {
|
||||
id: recordTimer;
|
||||
interval: 1000; running: false; repeat: false
|
||||
onTriggered: {
|
||||
console.log("Recording: " + MyAvatar.isRecording())
|
||||
MyAvatar.startRecording();
|
||||
console.log("Recording: " + MyAvatar.isRecording())
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
player.play.connect(play)
|
||||
player.rewind.connect(rewind)
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,14 +1,19 @@
|
|||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.4
|
||||
import QtQuick.Dialogs 1.2 as OriginalDialogs;
|
||||
|
||||
import "Global.js" as Global
|
||||
import "dialogs"
|
||||
|
||||
// This is our primary 'desktop' object to which all VR dialogs and
|
||||
// windows will be childed.
|
||||
// This is our primary 'desktop' object to which all VR dialogs and
|
||||
// windows will be childed.
|
||||
Item {
|
||||
id: desktop
|
||||
anchors.fill: parent;
|
||||
onParentChanged: forceActiveFocus();
|
||||
|
||||
// Debugging help for figuring out focus issues
|
||||
property var offscreenWindow;
|
||||
onOffscreenWindowChanged: offscreenWindow.activeFocusItemChanged.connect(onWindowFocusChanged);
|
||||
function onWindowFocusChanged() { console.log("Focus item is " + offscreenWindow.activeFocusItem); }
|
||||
|
||||
// Allows QML/JS to find the desktop through the parent chain
|
||||
property bool desktopRoot: true
|
||||
|
@ -16,16 +21,241 @@ Item {
|
|||
// The VR version of the primary menu
|
||||
property var rootMenu: Menu { objectName: "rootMenu" }
|
||||
|
||||
// List of all top level windows
|
||||
property var windows: [];
|
||||
onChildrenChanged: windows = Global.getTopLevelWindows(desktop);
|
||||
|
||||
// The tool window, one instance
|
||||
property alias toolWindow: toolWindow
|
||||
ToolWindow { id: toolWindow }
|
||||
|
||||
// FIXME support always on top flags
|
||||
function raise(item) {
|
||||
Global.raiseWindow(item);
|
||||
d.raiseWindow(item);
|
||||
}
|
||||
|
||||
Component {
|
||||
id: messageDialogBuilder
|
||||
MessageDialog { }
|
||||
}
|
||||
|
||||
Component {
|
||||
id: nativeMessageDialogBuilder
|
||||
OriginalDialogs.MessageDialog { }
|
||||
}
|
||||
|
||||
function messageBox(properties) {
|
||||
// Debugging: native message dialog for comparison
|
||||
// nativeMessageDialogBuilder.createObject(desktop, properties);
|
||||
return messageDialogBuilder.createObject(desktop, properties);
|
||||
}
|
||||
|
||||
QtObject {
|
||||
id: d
|
||||
|
||||
readonly property int zBasisNormal: 0
|
||||
readonly property int zBasisAlwaysOnTop: 4096
|
||||
readonly property int zBasisModal: 8192
|
||||
|
||||
|
||||
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 findParentMatching(item, predicate) {
|
||||
while (item) {
|
||||
if (predicate(item)) {
|
||||
break;
|
||||
}
|
||||
item = item.parent;
|
||||
}
|
||||
return item;
|
||||
}
|
||||
|
||||
function isDesktop(item) {
|
||||
return item.desktopRoot;
|
||||
}
|
||||
|
||||
function isTopLevelWindow(item) {
|
||||
return item.topLevelWindow;
|
||||
}
|
||||
|
||||
function isAlwaysOnTopWindow(window) {
|
||||
return window.alwaysOnTop;
|
||||
}
|
||||
|
||||
function isModalWindow(window) {
|
||||
return window.modality !== Qt.NonModal;
|
||||
}
|
||||
|
||||
function getTopLevelWindows(predicate) {
|
||||
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 (isTopLevelWindow(child) && (!predicate || predicate(child))) {
|
||||
currentWindows.push(child)
|
||||
}
|
||||
}
|
||||
return currentWindows;
|
||||
}
|
||||
|
||||
|
||||
function getDesktopWindow(item) {
|
||||
return findParentMatching(item, isTopLevelWindow)
|
||||
}
|
||||
|
||||
function fixupZOrder(windows, basis, topWindow) {
|
||||
windows.sort(function(a, b){
|
||||
return a.z - b.z;
|
||||
});
|
||||
|
||||
if ((topWindow.z >= basis) && (windows[windows.length - 1] === topWindow)) {
|
||||
return;
|
||||
}
|
||||
|
||||
var lastZ = -1;
|
||||
var lastTargetZ = basis - 1;
|
||||
for (var i = 0; i < windows.length; ++i) {
|
||||
var window = windows[i];
|
||||
if (!window.visible) {
|
||||
continue
|
||||
}
|
||||
|
||||
if (topWindow && (topWindow === window)) {
|
||||
continue
|
||||
}
|
||||
|
||||
if (window.z > lastZ) {
|
||||
lastZ = window.z;
|
||||
++lastTargetZ;
|
||||
}
|
||||
if (DebugQML) {
|
||||
console.log("Assigning z order " + lastTargetZ + " to " + window)
|
||||
}
|
||||
|
||||
window.z = lastTargetZ;
|
||||
}
|
||||
if (topWindow) {
|
||||
++lastTargetZ;
|
||||
if (DebugQML) {
|
||||
console.log("Assigning z order " + lastTargetZ + " to " + topWindow)
|
||||
}
|
||||
topWindow.z = lastTargetZ;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
var predicate;
|
||||
var zBasis;
|
||||
if (isModalWindow(targetWindow)) {
|
||||
predicate = isModalWindow;
|
||||
zBasis = zBasisModal
|
||||
} else if (isAlwaysOnTopWindow(targetWindow)) {
|
||||
predicate = function(window) {
|
||||
return (isAlwaysOnTopWindow(window) && !isModalWindow(window));
|
||||
}
|
||||
zBasis = zBasisAlwaysOnTop
|
||||
} else {
|
||||
predicate = function(window) {
|
||||
return (!isAlwaysOnTopWindow(window) && !isModalWindow(window));
|
||||
}
|
||||
zBasis = zBasisNormal
|
||||
}
|
||||
|
||||
var windows = getTopLevelWindows(predicate);
|
||||
fixupZOrder(windows, zBasis, targetWindow);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//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;
|
||||
//}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@ Windows.Window {
|
|||
destroyOnInvisible: false
|
||||
closable: false
|
||||
visible: false
|
||||
width: 384; height: 640;
|
||||
property string newTabSource
|
||||
property alias tabView: tabView
|
||||
onParentChanged: {
|
||||
|
@ -43,7 +44,8 @@ Windows.Window {
|
|||
}
|
||||
|
||||
TabView {
|
||||
id: tabView; width: 384; height: 640;
|
||||
anchors.fill: parent
|
||||
id: tabView;
|
||||
onCountChanged: {
|
||||
if (0 == count) {
|
||||
toolWindow.visible = false
|
||||
|
@ -73,13 +75,37 @@ Windows.Window {
|
|||
return i;
|
||||
}
|
||||
}
|
||||
console.warn("Could not find tab for " + source);
|
||||
return -1;
|
||||
}
|
||||
|
||||
function findTabForUrl(source) {
|
||||
var index = findIndexForUrl(source);
|
||||
if (index < 0) {
|
||||
return;
|
||||
}
|
||||
return tabView.getTab(index);
|
||||
}
|
||||
|
||||
function showTabForUrl(source, newVisible) {
|
||||
var index = findIndexForUrl(source);
|
||||
if (index < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
var tab = tabView.getTab(index);
|
||||
if (newVisible) {
|
||||
toolWindow.visible = true
|
||||
tab.enabled = true
|
||||
} else {
|
||||
tab.enabled = false;
|
||||
updateVisiblity();
|
||||
}
|
||||
}
|
||||
|
||||
function removeTabForUrl(source) {
|
||||
var index = findIndexForUrl(source);
|
||||
if (index < 0) {
|
||||
console.warn("Could not find tab for " + source);
|
||||
return;
|
||||
}
|
||||
tabView.removeTab(index);
|
||||
|
|
|
@ -5,21 +5,16 @@ import QtQuick.Controls.Styles 1.3
|
|||
import QtGraphicalEffects 1.0
|
||||
import "controls"
|
||||
import "styles"
|
||||
import "windows"
|
||||
|
||||
DialogContainer {
|
||||
Window {
|
||||
id: root
|
||||
HifiConstants { id: hifi }
|
||||
|
||||
objectName: "UpdateDialog"
|
||||
|
||||
implicitWidth: updateDialog.implicitWidth
|
||||
implicitHeight: updateDialog.implicitHeight
|
||||
|
||||
x: parent ? parent.width / 2 - width / 2 : 0
|
||||
y: parent ? parent.height / 2 - height / 2 : 0
|
||||
property int maximumX: parent ? parent.width - width : 0
|
||||
property int maximumY: parent ? parent.height - height : 0
|
||||
|
||||
width: updateDialog.implicitWidth
|
||||
height: updateDialog.implicitHeight
|
||||
resizable: false
|
||||
anchors.centerIn: parent
|
||||
UpdateDialog {
|
||||
id: updateDialog
|
||||
|
||||
|
|
|
@ -1,9 +1,27 @@
|
|||
import QtQuick 2.3
|
||||
import QtQuick.Controls 1.3 as Original
|
||||
import QtQuick.Controls.Styles 1.3
|
||||
|
||||
import "."
|
||||
import "../styles"
|
||||
|
||||
Original.Button {
|
||||
style: ButtonStyle { }
|
||||
style: ButtonStyle {
|
||||
HifiConstants { id: hifi }
|
||||
padding {
|
||||
top: 8
|
||||
left: 12
|
||||
right: 12
|
||||
bottom: 8
|
||||
}
|
||||
background: Border {
|
||||
anchors.fill: parent
|
||||
}
|
||||
label: Text {
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
text: control.text
|
||||
color: control.enabled ? hifi.colors.text : hifi.colors.disabledText
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,99 +0,0 @@
|
|||
import QtQuick 2.3
|
||||
import QtQuick.Controls 1.2
|
||||
import "."
|
||||
import "../styles"
|
||||
|
||||
Item {
|
||||
id: root
|
||||
objectName: "topLevelWindow"
|
||||
HifiConstants { id: hifi }
|
||||
implicitHeight: contentImplicitHeight + titleBorder.height + hifi.styles.borderWidth
|
||||
implicitWidth: contentImplicitWidth + hifi.styles.borderWidth * 2
|
||||
property string title
|
||||
property int titleSize: titleBorder.height + 12
|
||||
property string frameColor: hifi.colors.hifiBlue
|
||||
property string backgroundColor: hifi.colors.dialogBackground
|
||||
property bool active: false
|
||||
property real contentImplicitWidth: 800
|
||||
property real contentImplicitHeight: 800
|
||||
|
||||
property alias titleBorder: titleBorder
|
||||
readonly property alias titleX: titleBorder.x
|
||||
readonly property alias titleY: titleBorder.y
|
||||
readonly property alias titleWidth: titleBorder.width
|
||||
readonly property alias titleHeight: titleBorder.height
|
||||
|
||||
// readonly property real borderWidth: hifi.styles.borderWidth
|
||||
readonly property real borderWidth: 0
|
||||
property alias clientBorder: clientBorder
|
||||
readonly property real clientX: clientBorder.x + borderWidth
|
||||
readonly property real clientY: clientBorder.y + borderWidth
|
||||
readonly property real clientWidth: clientBorder.width - borderWidth * 2
|
||||
readonly property real clientHeight: clientBorder.height - borderWidth * 2
|
||||
|
||||
/*
|
||||
* Window decorations, with a title bar and frames
|
||||
*/
|
||||
Border {
|
||||
id: windowBorder
|
||||
anchors.fill: parent
|
||||
border.color: root.frameColor
|
||||
border.width: 0
|
||||
color: "#00000000"
|
||||
|
||||
Border {
|
||||
id: titleBorder
|
||||
height: hifi.layout.windowTitleHeight
|
||||
anchors.right: parent.right
|
||||
anchors.left: parent.left
|
||||
border.color: root.frameColor
|
||||
border.width: 0
|
||||
clip: true
|
||||
color: root.active ?
|
||||
hifi.colors.activeWindow.headerBackground :
|
||||
hifi.colors.inactiveWindow.headerBackground
|
||||
|
||||
|
||||
Text {
|
||||
id: titleText
|
||||
color: root.active ?
|
||||
hifi.colors.activeWindow.headerText :
|
||||
hifi.colors.inactiveWindow.headerText
|
||||
text: root.title
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
anchors.fill: parent
|
||||
}
|
||||
} // header border
|
||||
|
||||
// These two rectangles hide the curves between the title area
|
||||
// and the client area
|
||||
Rectangle {
|
||||
y: titleBorder.height - titleBorder.radius
|
||||
height: titleBorder.radius
|
||||
width: titleBorder.width
|
||||
color: titleBorder.color
|
||||
visible: borderWidth == 0
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
y: titleBorder.height
|
||||
width: clientBorder.width
|
||||
height: clientBorder.radius
|
||||
color: clientBorder.color
|
||||
}
|
||||
|
||||
Border {
|
||||
id: clientBorder
|
||||
border.width: 0
|
||||
border.color: root.frameColor
|
||||
color: root.backgroundColor
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.top: titleBorder.bottom
|
||||
anchors.topMargin: -titleBorder.border.width
|
||||
anchors.right: parent.right
|
||||
anchors.left: parent.left
|
||||
} // client border
|
||||
} // window border
|
||||
|
||||
}
|
|
@ -1,65 +0,0 @@
|
|||
//
|
||||
// DialogCommon.qml
|
||||
//
|
||||
// Created by David Rowe on 3 Jun 2015
|
||||
// Copyright 2015 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 Hifi 1.0
|
||||
import QtQuick 2.4
|
||||
import "../styles"
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
property bool destroyOnInvisible: true
|
||||
|
||||
|
||||
// The UI enables an object, rather than manipulating its visibility, so that we can do animations in both directions.
|
||||
// Because visibility and enabled are booleans, they cannot be animated. So when enabled is changed, we modify a property
|
||||
// that can be animated, like scale or opacity, and then when the target animation value is reached, we can modify the
|
||||
// visibility.
|
||||
enabled: false
|
||||
opacity: 0.0
|
||||
|
||||
onEnabledChanged: {
|
||||
opacity = enabled ? 1.0 : 0.0
|
||||
}
|
||||
|
||||
Behavior on opacity {
|
||||
// Animate opacity.
|
||||
NumberAnimation {
|
||||
duration: hifi.effects.fadeInDuration
|
||||
easing.type: Easing.OutCubic
|
||||
}
|
||||
}
|
||||
|
||||
onOpacityChanged: {
|
||||
// Once we're transparent, disable the dialog's visibility.
|
||||
visible = (opacity != 0.0)
|
||||
}
|
||||
|
||||
onVisibleChanged: {
|
||||
if (!visible) {
|
||||
// Some dialogs should be destroyed when they become invisible.
|
||||
if (destroyOnInvisible) {
|
||||
destroy()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Keys.onPressed: {
|
||||
switch(event.key) {
|
||||
case Qt.Key_W:
|
||||
if (event.modifiers == Qt.ControlModifier) {
|
||||
enabled = false
|
||||
event.accepted = true
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,179 +0,0 @@
|
|||
import QtQuick 2.3
|
||||
import QtQuick.Controls 1.2
|
||||
import "."
|
||||
import "../styles"
|
||||
|
||||
/*
|
||||
* 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
|
||||
* window.
|
||||
*
|
||||
* Examine the QML ApplicationWindow.qml source for how it does this
|
||||
*
|
||||
*/
|
||||
DialogBase {
|
||||
id: root
|
||||
HifiConstants { id: hifi }
|
||||
// FIXME better placement via a window manager
|
||||
x: parent ? parent.width / 2 - width / 2 : 0
|
||||
y: parent ? parent.height / 2 - height / 2 : 0
|
||||
|
||||
property bool destroyOnInvisible: false
|
||||
property bool destroyOnCloseButton: true
|
||||
property bool resizable: false
|
||||
|
||||
property int animationDuration: hifi.effects.fadeInDuration
|
||||
property int minX: 256
|
||||
property int minY: 256
|
||||
readonly property int topMargin: root.height - clientBorder.height + hifi.layout.spacing
|
||||
|
||||
/*
|
||||
* Support for animating the dialog in and out.
|
||||
*/
|
||||
enabled: false
|
||||
opacity: 1.0
|
||||
|
||||
// The offscreen UI will enable an object, rather than manipulating it's
|
||||
// visibility, so that we can do animations in both directions. Because
|
||||
// visibility and enabled are boolean flags, they cannot be animated. So when
|
||||
// enabled is change, we modify a property that can be animated, like scale or
|
||||
// opacity, and then when the target animation value is reached, we can
|
||||
// modify the visibility
|
||||
onEnabledChanged: {
|
||||
opacity = enabled ? 1.0 : 0.0
|
||||
// If the dialog is initially invisible, setting opacity doesn't
|
||||
// trigger making it visible.
|
||||
if (enabled) {
|
||||
visible = true;
|
||||
if (root.parent) {
|
||||
Desktop.raise(root);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onParentChanged: {
|
||||
if (enabled && parent) {
|
||||
Global.raiseWindow(root);
|
||||
}
|
||||
}
|
||||
|
||||
// The actual animator
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
duration: animationDuration
|
||||
easing.type: Easing.OutCubic
|
||||
}
|
||||
}
|
||||
|
||||
// Once we're transparent, disable the dialog's visibility
|
||||
onOpacityChanged: {
|
||||
visible = (opacity != 0.0);
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
if (visible) {
|
||||
Global.raiseWindow(root);
|
||||
}
|
||||
}
|
||||
|
||||
// Some dialogs should be destroyed when they become invisible,
|
||||
// so handle that
|
||||
onVisibleChanged: {
|
||||
if (!visible && destroyOnInvisible) {
|
||||
destroy();
|
||||
}
|
||||
}
|
||||
|
||||
// our close function performs the same way as the OffscreenUI class:
|
||||
// don't do anything but manipulate the enabled flag and let the other
|
||||
// mechanisms decide if the window should be destroyed after the close
|
||||
// animation completes
|
||||
function close() {
|
||||
if (destroyOnCloseButton) {
|
||||
destroyOnInvisible = true
|
||||
}
|
||||
enabled = false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Resize support
|
||||
*/
|
||||
function deltaSize(dx, dy) {
|
||||
width = Math.max(width + dx, minX)
|
||||
height = Math.max(height + dy, minY)
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: sizeDrag
|
||||
enabled: root.resizable
|
||||
property int startX
|
||||
property int startY
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: parent.bottom
|
||||
width: 16
|
||||
height: 16
|
||||
z: 1000
|
||||
hoverEnabled: true
|
||||
onPressed: {
|
||||
startX = mouseX
|
||||
startY = mouseY
|
||||
}
|
||||
onPositionChanged: {
|
||||
if (pressed) {
|
||||
root.deltaSize((mouseX - startX), (mouseY - startY))
|
||||
startX = mouseX
|
||||
startY = mouseY
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: titleDrag
|
||||
x: root.titleX
|
||||
y: root.titleY
|
||||
width: root.titleWidth
|
||||
height: root.titleHeight
|
||||
onClicked: Global.raiseWindow(root)
|
||||
|
||||
drag {
|
||||
target: root
|
||||
minimumX: 0
|
||||
minimumY: 0
|
||||
maximumX: root.parent ? root.parent.width - root.width : 0
|
||||
maximumY: root.parent ? root.parent.height - root.height : 0
|
||||
}
|
||||
|
||||
Row {
|
||||
id: windowControls
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.top: parent.top
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: hifi.layout.spacing
|
||||
FontAwesome {
|
||||
id: icon
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
size: root.titleHeight - hifi.layout.spacing * 2
|
||||
color: "red"
|
||||
text: "\uf00d"
|
||||
MouseArea {
|
||||
anchors.margins: hifi.layout.spacing / 2
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
root.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Keys.onPressed: {
|
||||
switch(event.key) {
|
||||
case Qt.Key_W:
|
||||
if (event.modifiers == Qt.ControlModifier) {
|
||||
event.accepted = true
|
||||
enabled = false
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,17 +4,200 @@ import Qt.labs.folderlistmodel 2.1
|
|||
import Qt.labs.settings 1.0
|
||||
|
||||
import ".."
|
||||
import "."
|
||||
import "../windows"
|
||||
import "../styles"
|
||||
|
||||
// Work in progress....
|
||||
DialogBase {
|
||||
Window {
|
||||
id: root
|
||||
Constants { id: vr }
|
||||
property string settingsName: ""
|
||||
HifiConstants { id: hifi }
|
||||
|
||||
signal selectedFile(var file);
|
||||
signal canceled();
|
||||
|
||||
anchors.centerIn: parent
|
||||
resizable: true
|
||||
width: 640
|
||||
height: 480
|
||||
modality: Qt.ApplicationModal
|
||||
property string settingsName: ""
|
||||
property alias folder: folderModel.folder
|
||||
property alias filterModel: selectionType.model
|
||||
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
color: "white"
|
||||
|
||||
Settings {
|
||||
// fixme, combine with a property to allow different saved locations
|
||||
category: "FileOpenLastFolder." + settingsName
|
||||
property alias folder: folderModel.folder
|
||||
}
|
||||
|
||||
TextField {
|
||||
id: currentDirectory
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.top: parent.top
|
||||
anchors.margins: 8
|
||||
readOnly: true
|
||||
text: folderModel.folder
|
||||
}
|
||||
|
||||
Component {
|
||||
id: fileItemDelegate
|
||||
Item {
|
||||
clip: true
|
||||
Text {
|
||||
x: 3
|
||||
id: columnText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
// font.pointSize: 12
|
||||
color: tableView.activeFocus && styleData.row === tableView.currentRow ? "yellow" : styleData.textColor
|
||||
elide: styleData.elideMode
|
||||
text: getText();
|
||||
font.italic: folderModel.get(styleData.row, "fileIsDir") ? true : false
|
||||
|
||||
|
||||
Connections {
|
||||
target: tableView
|
||||
//onCurrentRowChanged: columnText.color = (tableView.activeFocus && styleData.row === tableView.currentRow ? "yellow" : styleData.textColor)
|
||||
}
|
||||
|
||||
function getText() {
|
||||
switch (styleData.column) {
|
||||
//case 1: return Date.fromLocaleString(locale, styleData.value, "yyyy-MM-dd hh:mm:ss");
|
||||
case 2: return folderModel.get(styleData.row, "fileIsDir") ? "" : formatSize(styleData.value);
|
||||
default: return styleData.value;
|
||||
}
|
||||
}
|
||||
|
||||
function formatSize(size) {
|
||||
var suffixes = [ "bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB" ];
|
||||
var suffixIndex = 0
|
||||
while ((size / 1024.0) > 1.1) {
|
||||
size /= 1024.0;
|
||||
++suffixIndex;
|
||||
}
|
||||
|
||||
size = Math.round(size*1000)/1000;
|
||||
size = size.toLocaleString()
|
||||
|
||||
return size + " " + suffixes[suffixIndex];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TableView {
|
||||
id: tableView
|
||||
focus: true
|
||||
model: FolderListModel {
|
||||
id: folderModel
|
||||
showDotAndDotDot: true
|
||||
showDirsFirst: true
|
||||
onFolderChanged: {
|
||||
tableView.currentRow = -1;
|
||||
tableView.positionViewAtRow(0, ListView.Beginning)
|
||||
}
|
||||
}
|
||||
anchors.top: currentDirectory.bottom
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: selectionType.top
|
||||
anchors.margins: 8
|
||||
itemDelegate: fileItemDelegate
|
||||
// rowDelegate: Rectangle {
|
||||
// id: rowDelegate
|
||||
// color: styleData.selected ? "#7f0000ff" : "#00000000"
|
||||
// Connections { target: folderModel; onFolderChanged: rowDelegate.visible = false }
|
||||
// Connections { target: tableView; onCurrentRowChanged: rowDelegate.visible = true; }
|
||||
// }
|
||||
|
||||
TableViewColumn {
|
||||
role: "fileName"
|
||||
title: "Name"
|
||||
width: 400
|
||||
}
|
||||
TableViewColumn {
|
||||
role: "fileModified"
|
||||
title: "Date Modified"
|
||||
width: 200
|
||||
}
|
||||
TableViewColumn {
|
||||
role: "fileSize"
|
||||
title: "Size"
|
||||
width: 200
|
||||
}
|
||||
|
||||
Keys.onReturnPressed: selectCurrentFile();
|
||||
onDoubleClicked: { currentRow = row; selectCurrentFile(); }
|
||||
onCurrentRowChanged: currentSelection.text = model.get(currentRow, "fileName");
|
||||
KeyNavigation.left: cancelButton
|
||||
KeyNavigation.right: selectionType
|
||||
}
|
||||
|
||||
|
||||
TextField {
|
||||
id: currentSelection
|
||||
anchors.right: selectionType.left
|
||||
anchors.rightMargin: 8
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 8
|
||||
anchors.top: selectionType.top
|
||||
}
|
||||
|
||||
ComboBox {
|
||||
id: selectionType
|
||||
anchors.bottom: buttonRow.top
|
||||
anchors.bottomMargin: 8
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 8
|
||||
anchors.left: buttonRow.left
|
||||
|
||||
model: ListModel {
|
||||
ListElement { text: "All Files (*.*)"; filter: "*.*" }
|
||||
}
|
||||
|
||||
onCurrentIndexChanged: {
|
||||
folderModel.nameFilters = [ filterModel.get(currentIndex).filter ]
|
||||
}
|
||||
KeyNavigation.left: tableView
|
||||
KeyNavigation.right: openButton
|
||||
}
|
||||
|
||||
Row {
|
||||
id: buttonRow
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 8
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.bottomMargin: 8
|
||||
layoutDirection: Qt.RightToLeft
|
||||
spacing: 8
|
||||
Button {
|
||||
id: cancelButton
|
||||
text: "Cancel"
|
||||
KeyNavigation.up: selectionType
|
||||
KeyNavigation.left: openButton
|
||||
KeyNavigation.right: tableView.contentItem
|
||||
Keys.onReturnPressed: { canceled(); root.enabled = false }
|
||||
onClicked: { canceled(); close() }
|
||||
}
|
||||
Button {
|
||||
id: openButton
|
||||
text: "Open"
|
||||
enabled: tableView.currentRow != -1 && !folderModel.get(tableView.currentRow, "fileIsDir")
|
||||
onClicked: selectCurrentFile();
|
||||
Keys.onReturnPressed: selectCurrentFile();
|
||||
|
||||
KeyNavigation.up: selectionType
|
||||
KeyNavigation.left: selectionType
|
||||
KeyNavigation.right: cancelButton
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function selectCurrentFile() {
|
||||
var row = tableView.currentRow
|
||||
console.log("Selecting row " + row)
|
||||
|
@ -25,200 +208,11 @@ DialogBase {
|
|||
folderModel.folder = folderModel.get(row, "fileURL");
|
||||
} else {
|
||||
selectedFile(folderModel.get(row, "fileURL"));
|
||||
enabled = false
|
||||
close();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
property var folderModel: FolderListModel {
|
||||
id: folderModel
|
||||
showDotAndDotDot: true
|
||||
showDirsFirst: true
|
||||
folder: "file:///C:/";
|
||||
onFolderChanged: tableView.currentRow = 0
|
||||
}
|
||||
|
||||
property var filterModel: ListModel {
|
||||
ListElement {
|
||||
text: "All Files (*.*)"
|
||||
filter: "*"
|
||||
}
|
||||
ListElement {
|
||||
text: "Javascript Files (*.js)"
|
||||
filter: "*.js"
|
||||
}
|
||||
ListElement {
|
||||
text: "QML Files (*.qml)"
|
||||
filter: "*.qml"
|
||||
}
|
||||
}
|
||||
|
||||
Settings {
|
||||
// fixme, combine with a property to allow different saved locations
|
||||
category: "FileOpenLastFolder." + settingsName
|
||||
property alias folder: folderModel.folder
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: currentDirectoryWrapper
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 8
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 8
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: 8
|
||||
height: currentDirectory.implicitHeight + 8
|
||||
radius: vr.styles.radius
|
||||
color: vr.controls.colors.inputBackground
|
||||
|
||||
TextEdit {
|
||||
enabled: false
|
||||
id: currentDirectory
|
||||
text: folderModel.folder
|
||||
anchors {
|
||||
fill: parent
|
||||
leftMargin: 8
|
||||
rightMargin: 8
|
||||
topMargin: 4
|
||||
bottomMargin: 4
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TableView {
|
||||
id: tableView
|
||||
focus: true
|
||||
model: folderModel
|
||||
anchors.top: currentDirectoryWrapper.bottom
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: selectionType.top
|
||||
anchors.margins: 8
|
||||
itemDelegate: Item {
|
||||
Text {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
font.family: vr.fonts.lightFontName
|
||||
font.pointSize: 12
|
||||
color: tableView.activeFocus && styleData.row === tableView.currentRow ? "yellow" : styleData.textColor
|
||||
elide: styleData.elideMode
|
||||
text: getText();
|
||||
function getText() {
|
||||
switch (styleData.column) {
|
||||
//case 1: return Date.fromLocaleString(locale, styleData.value, "yyyy-MM-dd hh:mm:ss");
|
||||
case 2: return folderModel.get(styleData.row, "fileIsDir") ? "" : formatSize(styleData.value);
|
||||
default: return styleData.value;
|
||||
}
|
||||
}
|
||||
|
||||
function formatSize(size) {
|
||||
var suffixes = [ "bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB" ];
|
||||
var suffixIndex = 0
|
||||
while ((size / 1024.0) > 1.1) {
|
||||
size /= 1024.0;
|
||||
++suffixIndex;
|
||||
}
|
||||
|
||||
size = Math.round(size*1000)/1000;
|
||||
size = size.toLocaleString()
|
||||
|
||||
return size + " " + suffixes[suffixIndex];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TableViewColumn {
|
||||
role: "fileName"
|
||||
title: "Name"
|
||||
width: 400
|
||||
}
|
||||
TableViewColumn {
|
||||
role: "fileModified"
|
||||
title: "Date Modified"
|
||||
width: 200
|
||||
}
|
||||
TableViewColumn {
|
||||
role: "fileSize"
|
||||
title: "Size"
|
||||
width: 200
|
||||
}
|
||||
|
||||
function selectItem(row) {
|
||||
selectCurrentFile()
|
||||
}
|
||||
|
||||
|
||||
Keys.onReturnPressed: selectCurrentFile();
|
||||
onDoubleClicked: { currentRow = row; selectCurrentFile(); }
|
||||
onCurrentRowChanged: currentSelection.text = model.get(currentRow, "fileName");
|
||||
KeyNavigation.left: cancelButton
|
||||
KeyNavigation.right: selectionType
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.right: selectionType.left
|
||||
anchors.rightMargin: 8
|
||||
anchors.top: selectionType.top
|
||||
anchors.bottom: selectionType.bottom
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 8
|
||||
radius: 8
|
||||
color: "#eee"
|
||||
Text {
|
||||
id: currentSelection
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.margins: 8
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
font.family: vr.fonts.mainFontName
|
||||
font.pointSize: 18
|
||||
}
|
||||
}
|
||||
|
||||
ComboBox {
|
||||
id: selectionType
|
||||
anchors.bottom: buttonRow.top
|
||||
anchors.bottomMargin: 8
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 8
|
||||
anchors.left: buttonRow.left
|
||||
model: filterModel
|
||||
onCurrentIndexChanged: folderModel.nameFilters = [
|
||||
filterModel.get(currentIndex).filter
|
||||
]
|
||||
|
||||
KeyNavigation.left: tableView
|
||||
KeyNavigation.right: openButton
|
||||
}
|
||||
|
||||
Row {
|
||||
id: buttonRow
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 8
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.bottomMargin: 8
|
||||
layoutDirection: Qt.RightToLeft
|
||||
spacing: 8
|
||||
Button {
|
||||
id: cancelButton
|
||||
text: "Cancel"
|
||||
KeyNavigation.up: selectionType
|
||||
KeyNavigation.left: openButton
|
||||
KeyNavigation.right: tableView.contentItem
|
||||
Keys.onReturnPressed: { canceled(); root.enabled = false }
|
||||
onClicked: { canceled(); root.enabled = false }
|
||||
}
|
||||
Button {
|
||||
id: openButton
|
||||
text: "Open"
|
||||
enabled: tableView.currentRow != -1 && !folderModel.get(tableView.currentRow, "fileIsDir")
|
||||
KeyNavigation.up: selectionType
|
||||
KeyNavigation.left: selectionType
|
||||
KeyNavigation.right: cancelButton
|
||||
onClicked: selectCurrentFile();
|
||||
Keys.onReturnPressed: selectedFile(folderModel.get(tableView.currentRow, "fileURL"))
|
||||
}
|
||||
}
|
||||
|
||||
Keys.onPressed: {
|
||||
if (event.key === Qt.Key_Backspace && folderModel.parentFolder && folderModel.parentFolder != "") {
|
||||
|
|
341
interface/resources/qml/dialogs/MessageDialog.qml
Normal file
341
interface/resources/qml/dialogs/MessageDialog.qml
Normal file
|
@ -0,0 +1,341 @@
|
|||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.2
|
||||
import QtQuick.Dialogs 1.2 as OriginalDialogs
|
||||
|
||||
import "../controls"
|
||||
import "../styles"
|
||||
import "../windows"
|
||||
|
||||
// FIXME respect default button functionality
|
||||
// FIXME force active focus at all times (modal dialog)
|
||||
Window {
|
||||
id: root
|
||||
HifiConstants { id: hifi }
|
||||
|
||||
implicitWidth: 640
|
||||
implicitHeight: 320
|
||||
destroyOnCloseButton: true
|
||||
destroyOnInvisible: true
|
||||
visible: true
|
||||
modality: Qt.ApplicationModal
|
||||
anchors.centerIn: parent
|
||||
frame: ModalFrame {}
|
||||
|
||||
signal selected(int button);
|
||||
|
||||
function click(button) {
|
||||
console.log("User clicked " + button)
|
||||
clickedButton = button;
|
||||
selected(button);
|
||||
destroy();
|
||||
}
|
||||
|
||||
property alias detailedText: detailedText.text
|
||||
property alias text: mainTextContainer.text
|
||||
property alias informativeText: informativeTextContainer.text
|
||||
onIconChanged: iconHolder.updateIcon();
|
||||
property int buttons: OriginalDialogs.StandardButton.Ok
|
||||
property int icon: OriginalDialogs.StandardIcon.NoIcon
|
||||
property int defaultButton: OriginalDialogs.StandardButton.NoButton;
|
||||
property int clickedButton: OriginalDialogs.StandardButton.NoButton;
|
||||
focus: defaultButton === OriginalDialogs.StandardButton.NoButton
|
||||
|
||||
Rectangle {
|
||||
id: messageBox
|
||||
clip: true
|
||||
anchors.fill: parent
|
||||
radius: 4
|
||||
color: "white"
|
||||
|
||||
QtObject {
|
||||
id: d
|
||||
readonly property real spacing: hifi.layout.spacing
|
||||
readonly property real outerSpacing: hifi.layout.spacing * 2
|
||||
readonly property int minWidth: 480
|
||||
readonly property int maxWdith: 1280
|
||||
readonly property int minHeight: 160
|
||||
readonly property int maxHeight: 720
|
||||
|
||||
function resize() {
|
||||
var targetWidth = iconHolder.width + mainTextContainer.width + d.spacing * 6
|
||||
var targetHeight = mainTextContainer.implicitHeight + informativeTextContainer.implicitHeight + d.spacing * 8 + buttons.height + details.height
|
||||
root.width = (targetWidth < d.minWidth) ? d.minWidth : ((targetWidth > d.maxWdith) ? d.maxWidth : targetWidth)
|
||||
root.height = (targetHeight < d.minHeight) ? d.minHeight: ((targetHeight > d.maxHeight) ? d.maxHeight : targetHeight)
|
||||
}
|
||||
}
|
||||
|
||||
FontAwesome {
|
||||
id: iconHolder
|
||||
size: 48
|
||||
anchors {
|
||||
left: parent.left
|
||||
top: parent.top
|
||||
margins: d.spacing * 2
|
||||
}
|
||||
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
style: Text.Outline; styleColor: "black"
|
||||
Component.onCompleted: updateIcon();
|
||||
function updateIcon() {
|
||||
if (!root) {
|
||||
return;
|
||||
}
|
||||
switch (root.icon) {
|
||||
case OriginalDialogs.StandardIcon.Information:
|
||||
text = "\uF05A";
|
||||
color = "blue";
|
||||
break;
|
||||
|
||||
case OriginalDialogs.StandardIcon.Question:
|
||||
text = "\uF059"
|
||||
color = "blue";
|
||||
break;
|
||||
|
||||
case OriginalDialogs.StandardIcon.Warning:
|
||||
text = "\uF071"
|
||||
color = "yellow";
|
||||
break;
|
||||
|
||||
case OriginalDialogs.StandardIcon.Critical:
|
||||
text = "\uF057"
|
||||
color = "red"
|
||||
break;
|
||||
|
||||
default:
|
||||
text = ""
|
||||
}
|
||||
visible = (text != "");
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
id: mainTextContainer
|
||||
onHeightChanged: d.resize(); onWidthChanged: d.resize();
|
||||
wrapMode: Text.WordWrap
|
||||
font { pointSize: 14; weight: Font.Bold }
|
||||
anchors { left: iconHolder.right; top: parent.top; margins: d.spacing * 2 }
|
||||
}
|
||||
|
||||
Text {
|
||||
id: informativeTextContainer
|
||||
onHeightChanged: d.resize(); onWidthChanged: d.resize();
|
||||
wrapMode: Text.WordWrap
|
||||
font.pointSize: 11
|
||||
anchors { top: mainTextContainer.bottom; right: parent.right; left: iconHolder.right; margins: d.spacing * 2 }
|
||||
}
|
||||
|
||||
Flow {
|
||||
id: buttons
|
||||
focus: true
|
||||
spacing: d.spacing
|
||||
onHeightChanged: d.resize(); onWidthChanged: d.resize();
|
||||
layoutDirection: Qt.RightToLeft
|
||||
anchors { bottom: details.top; right: parent.right; margins: d.spacing * 2; bottomMargin: 0 }
|
||||
Button {
|
||||
id: okButton
|
||||
text: qsTr("OK")
|
||||
focus: root.defaultButton === OriginalDialogs.StandardButton.Ok
|
||||
onClicked: root.click(OriginalDialogs.StandardButton.Ok)
|
||||
visible: root.buttons & OriginalDialogs.StandardButton.Ok
|
||||
|
||||
}
|
||||
Button {
|
||||
id: openButton
|
||||
text: qsTr("Open")
|
||||
focus: root.defaultButton === OriginalDialogs.StandardButton.Open
|
||||
onClicked: root.click(OriginalDialogs.StandardButton.Open)
|
||||
visible: root.buttons & OriginalDialogs.StandardButton.Open
|
||||
}
|
||||
Button {
|
||||
id: saveButton
|
||||
text: qsTr("Save")
|
||||
focus: root.defaultButton === OriginalDialogs.StandardButton.Save
|
||||
onClicked: root.click(OriginalDialogs.StandardButton.Save)
|
||||
visible: root.buttons & OriginalDialogs.StandardButton.Save
|
||||
}
|
||||
Button {
|
||||
id: saveAllButton
|
||||
text: qsTr("Save All")
|
||||
focus: root.defaultButton === OriginalDialogs.StandardButton.SaveAll
|
||||
onClicked: root.click(OriginalDialogs.StandardButton.SaveAll)
|
||||
visible: root.buttons & OriginalDialogs.StandardButton.SaveAll
|
||||
}
|
||||
Button {
|
||||
id: retryButton
|
||||
text: qsTr("Retry")
|
||||
focus: root.defaultButton === OriginalDialogs.StandardButton.Retry
|
||||
onClicked: root.click(OriginalDialogs.StandardButton.Retry)
|
||||
visible: root.buttons & OriginalDialogs.StandardButton.Retry
|
||||
}
|
||||
Button {
|
||||
id: ignoreButton
|
||||
text: qsTr("Ignore")
|
||||
focus: root.defaultButton === OriginalDialogs.StandardButton.Ignore
|
||||
onClicked: root.click(OriginalDialogs.StandardButton.Ignore)
|
||||
visible: root.buttons & OriginalDialogs.StandardButton.Ignore
|
||||
}
|
||||
Button {
|
||||
id: applyButton
|
||||
text: qsTr("Apply")
|
||||
focus: root.defaultButton === OriginalDialogs.StandardButton.Apply
|
||||
onClicked: root.click(OriginalDialogs.StandardButton.Apply)
|
||||
visible: root.buttons & OriginalDialogs.StandardButton.Apply
|
||||
}
|
||||
Button {
|
||||
id: yesButton
|
||||
text: qsTr("Yes")
|
||||
focus: root.defaultButton === OriginalDialogs.StandardButton.Yes
|
||||
onClicked: root.click(OriginalDialogs.StandardButton.Yes)
|
||||
visible: root.buttons & OriginalDialogs.StandardButton.Yes
|
||||
}
|
||||
Button {
|
||||
id: yesAllButton
|
||||
text: qsTr("Yes to All")
|
||||
focus: root.defaultButton === OriginalDialogs.StandardButton.YesToAll
|
||||
onClicked: root.click(OriginalDialogs.StandardButton.YesToAll)
|
||||
visible: root.buttons & OriginalDialogs.StandardButton.YesToAll
|
||||
}
|
||||
Button {
|
||||
id: noButton
|
||||
text: qsTr("No")
|
||||
focus: root.defaultButton === OriginalDialogs.StandardButton.No
|
||||
onClicked: root.click(OriginalDialogs.StandardButton.No)
|
||||
visible: root.buttons & OriginalDialogs.StandardButton.No
|
||||
}
|
||||
Button {
|
||||
id: noAllButton
|
||||
text: qsTr("No to All")
|
||||
focus: root.defaultButton === OriginalDialogs.StandardButton.NoToAll
|
||||
onClicked: root.click(OriginalDialogs.StandardButton.NoToAll)
|
||||
visible: root.buttons & OriginalDialogs.StandardButton.NoToAll
|
||||
}
|
||||
Button {
|
||||
id: discardButton
|
||||
text: qsTr("Discard")
|
||||
focus: root.defaultButton === OriginalDialogs.StandardButton.Discard
|
||||
onClicked: root.click(OriginalDialogs.StandardButton.Discard)
|
||||
visible: root.buttons & OriginalDialogs.StandardButton.Discard
|
||||
}
|
||||
Button {
|
||||
id: resetButton
|
||||
text: qsTr("Reset")
|
||||
focus: root.defaultButton === OriginalDialogs.StandardButton.Reset
|
||||
onClicked: root.click(OriginalDialogs.StandardButton.Reset)
|
||||
visible: root.buttons & OriginalDialogs.StandardButton.Reset
|
||||
}
|
||||
Button {
|
||||
id: restoreDefaultsButton
|
||||
text: qsTr("Restore Defaults")
|
||||
focus: root.defaultButton === OriginalDialogs.StandardButton.RestoreDefaults
|
||||
onClicked: root.click(OriginalDialogs.StandardButton.RestoreDefaults)
|
||||
visible: root.buttons & OriginalDialogs.StandardButton.RestoreDefaults
|
||||
}
|
||||
Button {
|
||||
id: cancelButton
|
||||
text: qsTr("Cancel")
|
||||
focus: root.defaultButton === OriginalDialogs.StandardButton.Cancel
|
||||
onClicked: root.click(OriginalDialogs.StandardButton.Cancel)
|
||||
visible: root.buttons & OriginalDialogs.StandardButton.Cancel
|
||||
}
|
||||
Button {
|
||||
id: abortButton
|
||||
text: qsTr("Abort")
|
||||
focus: root.defaultButton === OriginalDialogs.StandardButton.Abort
|
||||
onClicked: root.click(OriginalDialogs.StandardButton.Abort)
|
||||
visible: root.buttons & OriginalDialogs.StandardButton.Abort
|
||||
}
|
||||
Button {
|
||||
id: closeButton
|
||||
text: qsTr("Close")
|
||||
focus: root.defaultButton === OriginalDialogs.StandardButton.Close
|
||||
onClicked: root.click(OriginalDialogs.StandardButton.Close)
|
||||
visible: root.buttons & OriginalDialogs.StandardButton.Close
|
||||
}
|
||||
Button {
|
||||
id: moreButton
|
||||
text: qsTr("Show Details...")
|
||||
onClicked: { content.state = (content.state === "" ? "expanded" : "")
|
||||
}
|
||||
visible: detailedText && detailedText.length > 0
|
||||
}
|
||||
Button {
|
||||
id: helpButton
|
||||
text: qsTr("Help")
|
||||
focus: root.defaultButton === OriginalDialogs.StandardButton.Help
|
||||
onClicked: root.click(OriginalDialogs.StandardButton.Help)
|
||||
visible: root.buttons & OriginalDialogs.StandardButton.Help
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
id: details
|
||||
width: parent.width
|
||||
implicitHeight: detailedText.implicitHeight + root.spacing
|
||||
height: 0
|
||||
clip: true
|
||||
anchors { bottom: parent.bottom; left: parent.left; right: parent.right; margins: d.spacing * 2 }
|
||||
Flickable {
|
||||
id: flickable
|
||||
contentHeight: detailedText.height
|
||||
anchors.fill: parent
|
||||
anchors.topMargin: root.spacing
|
||||
anchors.bottomMargin: root.outerSpacing
|
||||
TextEdit {
|
||||
id: detailedText
|
||||
width: details.width
|
||||
wrapMode: Text.WordWrap
|
||||
readOnly: true
|
||||
selectByMouse: true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
states: [
|
||||
State {
|
||||
name: "expanded"
|
||||
PropertyChanges { target: root; anchors.fill: undefined }
|
||||
PropertyChanges { target: details; height: 120 }
|
||||
PropertyChanges { target: moreButton; text: qsTr("Hide Details") }
|
||||
}
|
||||
]
|
||||
|
||||
onStateChanged: d.resize()
|
||||
}
|
||||
|
||||
Keys.onPressed: {
|
||||
if (!visible) {
|
||||
return
|
||||
}
|
||||
|
||||
if (event.modifiers === Qt.ControlModifier)
|
||||
switch (event.key) {
|
||||
case Qt.Key_A:
|
||||
event.accepted = true
|
||||
detailedText.selectAll()
|
||||
break
|
||||
case Qt.Key_C:
|
||||
event.accepted = true
|
||||
detailedText.copy()
|
||||
break
|
||||
case Qt.Key_Period:
|
||||
if (Qt.platform.os === "osx") {
|
||||
event.accepted = true
|
||||
content.reject()
|
||||
}
|
||||
break
|
||||
} else switch (event.key) {
|
||||
case Qt.Key_Escape:
|
||||
case Qt.Key_Back:
|
||||
event.accepted = true
|
||||
root.click(OriginalDialogs.StandardButton.Cancel)
|
||||
break
|
||||
|
||||
case Qt.Key_Enter:
|
||||
case Qt.Key_Return:
|
||||
event.accepted = true
|
||||
root.click(OriginalDialogs.StandardButton.Ok)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
|
@ -13,7 +13,6 @@ Window {
|
|||
title: "Running Scripts"
|
||||
resizable: true
|
||||
destroyOnInvisible: true
|
||||
enabled: false
|
||||
x: 40; y: 40
|
||||
|
||||
property var scripts: ScriptDiscoveryService;
|
||||
|
@ -202,7 +201,6 @@ Window {
|
|||
|
||||
TextField {
|
||||
id: selectedScript
|
||||
enabled: true
|
||||
readOnly: true
|
||||
anchors.left: parent.left
|
||||
anchors.right: loadButton.left
|
||||
|
|
167
interface/resources/qml/hifi/MenuOption.qml
Normal file
167
interface/resources/qml/hifi/MenuOption.qml
Normal file
|
@ -0,0 +1,167 @@
|
|||
import QtQuick 2.5
|
||||
|
||||
QtObject {
|
||||
readonly property string aboutApp: "About Interface";
|
||||
readonly property string addRemoveFriends: "Add/Remove Friends...";
|
||||
readonly property string addressBar: "Show Address Bar";
|
||||
readonly property string animations: "Animations...";
|
||||
readonly property string animDebugDrawAnimPose: "Debug Draw Animation";
|
||||
readonly property string animDebugDrawDefaultPose: "Debug Draw Default Pose";
|
||||
readonly property string animDebugDrawPosition: "Debug Draw Position";
|
||||
readonly property string antialiasing: "Antialiasing";
|
||||
readonly property string assetMigration: "ATP Asset Migration";
|
||||
readonly property string atmosphere: "Atmosphere";
|
||||
readonly property string attachments: "Attachments...";
|
||||
readonly property string audioNetworkStats: "Audio Network Stats";
|
||||
readonly property string audioNoiseReduction: "Audio Noise Reduction";
|
||||
readonly property string audioScope: "Show Scope";
|
||||
readonly property string audioScopeFiftyFrames: "Fifty";
|
||||
readonly property string audioScopeFiveFrames: "Five";
|
||||
readonly property string audioScopeFrames: "Display Frames";
|
||||
readonly property string audioScopePause: "Pause Scope";
|
||||
readonly property string audioScopeTwentyFrames: "Twenty";
|
||||
readonly property string audioStatsShowInjectedStreams: "Audio Stats Show Injected Streams";
|
||||
readonly property string audioTools: "Show Level Meter";
|
||||
readonly property string autoMuteAudio: "Auto Mute Microphone";
|
||||
readonly property string avatarReceiveStats: "Show Receive Stats";
|
||||
readonly property string back: "Back";
|
||||
readonly property string bandwidthDetails: "Bandwidth Details";
|
||||
readonly property string binaryEyelidControl: "Binary Eyelid Control";
|
||||
readonly property string bookmarkLocation: "Bookmark Location";
|
||||
readonly property string bookmarks: "Bookmarks";
|
||||
readonly property string cachesSize: "RAM Caches Size";
|
||||
readonly property string calibrateCamera: "Calibrate Camera";
|
||||
readonly property string cameraEntityMode: "Entity Mode";
|
||||
readonly property string centerPlayerInView: "Center Player In View";
|
||||
readonly property string chat: "Chat...";
|
||||
readonly property string collisions: "Collisions";
|
||||
readonly property string comfortMode: "Comfort Mode";
|
||||
readonly property string connexion: "Activate 3D Connexion Devices";
|
||||
readonly property string console_: "Console...";
|
||||
readonly property string controlWithSpeech: "Control With Speech";
|
||||
readonly property string copyAddress: "Copy Address to Clipboard";
|
||||
readonly property string copyPath: "Copy Path to Clipboard";
|
||||
readonly property string coupleEyelids: "Couple Eyelids";
|
||||
readonly property string crashInterface: "Crash Interface";
|
||||
readonly property string debugAmbientOcclusion: "Debug Ambient Occlusion";
|
||||
readonly property string decreaseAvatarSize: "Decrease Avatar Size";
|
||||
readonly property string deleteBookmark: "Delete Bookmark...";
|
||||
readonly property string disableActivityLogger: "Disable Activity Logger";
|
||||
readonly property string disableEyelidAdjustment: "Disable Eyelid Adjustment";
|
||||
readonly property string disableLightEntities: "Disable Light Entities";
|
||||
readonly property string disableNackPackets: "Disable Entity NACK Packets";
|
||||
readonly property string diskCacheEditor: "Disk Cache Editor";
|
||||
readonly property string displayCrashOptions: "Display Crash Options";
|
||||
readonly property string displayHandTargets: "Show Hand Targets";
|
||||
readonly property string displayModelBounds: "Display Model Bounds";
|
||||
readonly property string displayModelTriangles: "Display Model Triangles";
|
||||
readonly property string displayModelElementChildProxies: "Display Model Element Children";
|
||||
readonly property string displayModelElementProxy: "Display Model Element Bounds";
|
||||
readonly property string displayDebugTimingDetails: "Display Timing Details";
|
||||
readonly property string dontDoPrecisionPicking: "Don't Do Precision Picking";
|
||||
readonly property string dontRenderEntitiesAsScene: "Don't Render Entities as Scene";
|
||||
readonly property string echoLocalAudio: "Echo Local Audio";
|
||||
readonly property string echoServerAudio: "Echo Server Audio";
|
||||
readonly property string enable3DTVMode: "Enable 3DTV Mode";
|
||||
readonly property string enableCharacterController: "Enable avatar collisions";
|
||||
readonly property string expandMyAvatarSimulateTiming: "Expand /myAvatar/simulation";
|
||||
readonly property string expandMyAvatarTiming: "Expand /myAvatar";
|
||||
readonly property string expandOtherAvatarTiming: "Expand /otherAvatar";
|
||||
readonly property string expandPaintGLTiming: "Expand /paintGL";
|
||||
readonly property string expandUpdateTiming: "Expand /update";
|
||||
readonly property string faceshift: "Faceshift";
|
||||
readonly property string firstPerson: "First Person";
|
||||
readonly property string fivePointCalibration: "5 Point Calibration";
|
||||
readonly property string fixGaze: "Fix Gaze (no saccade)";
|
||||
readonly property string forward: "Forward";
|
||||
readonly property string frameTimer: "Show Timer";
|
||||
readonly property string fullscreenMirror: "Mirror";
|
||||
readonly property string glowWhenSpeaking: "Glow When Speaking";
|
||||
readonly property string help: "Help...";
|
||||
readonly property string increaseAvatarSize: "Increase Avatar Size";
|
||||
readonly property string independentMode: "Independent Mode";
|
||||
readonly property string inputMenu: "Avatar>Input Devices";
|
||||
readonly property string keyboardMotorControl: "Enable Keyboard Motor Control";
|
||||
readonly property string leapMotionOnHMD: "Leap Motion on HMD";
|
||||
readonly property string loadScript: "Open and Run Script File...";
|
||||
readonly property string loadScriptURL: "Open and Run Script from URL...";
|
||||
readonly property string lodTools: "LOD Tools";
|
||||
readonly property string login: "Login";
|
||||
readonly property string log: "Log";
|
||||
readonly property string logExtraTimings: "Log Extra Timing Details";
|
||||
readonly property string lowVelocityFilter: "Low Velocity Filter";
|
||||
readonly property string meshVisible: "Draw Mesh";
|
||||
readonly property string miniMirror: "Mini Mirror";
|
||||
readonly property string muteAudio: "Mute Microphone";
|
||||
readonly property string muteEnvironment: "Mute Environment";
|
||||
readonly property string muteFaceTracking: "Mute Face Tracking";
|
||||
readonly property string namesAboveHeads: "Names Above Heads";
|
||||
readonly property string noFaceTracking: "None";
|
||||
readonly property string octreeStats: "Entity Statistics";
|
||||
readonly property string onePointCalibration: "1 Point Calibration";
|
||||
readonly property string onlyDisplayTopTen: "Only Display Top Ten";
|
||||
readonly property string outputMenu: "Display";
|
||||
readonly property string packageModel: "Package Model...";
|
||||
readonly property string pair: "Pair";
|
||||
readonly property string physicsShowOwned: "Highlight Simulation Ownership";
|
||||
readonly property string physicsShowHulls: "Draw Collision Hulls";
|
||||
readonly property string pipelineWarnings: "Log Render Pipeline Warnings";
|
||||
readonly property string preferences: "General...";
|
||||
readonly property string quit: "Quit";
|
||||
readonly property string reloadAllScripts: "Reload All Scripts";
|
||||
readonly property string reloadContent: "Reload Content (Clears all caches)";
|
||||
readonly property string renderBoundingCollisionShapes: "Show Bounding Collision Shapes";
|
||||
readonly property string renderFocusIndicator: "Show Eye Focus";
|
||||
readonly property string renderLookAtTargets: "Show Look-at Targets";
|
||||
readonly property string renderLookAtVectors: "Show Look-at Vectors";
|
||||
readonly property string renderResolution: "Scale Resolution";
|
||||
readonly property string renderResolutionOne: "1";
|
||||
readonly property string renderResolutionTwoThird: "2/3";
|
||||
readonly property string renderResolutionHalf: "1/2";
|
||||
readonly property string renderResolutionThird: "1/3";
|
||||
readonly property string renderResolutionQuarter: "1/4";
|
||||
readonly property string renderAmbientLight: "Ambient Light";
|
||||
readonly property string renderAmbientLightGlobal: "Global";
|
||||
readonly property string renderAmbientLight0: "OLD_TOWN_SQUARE";
|
||||
readonly property string renderAmbientLight1: "GRACE_CATHEDRAL";
|
||||
readonly property string renderAmbientLight2: "EUCALYPTUS_GROVE";
|
||||
readonly property string renderAmbientLight3: "ST_PETERS_BASILICA";
|
||||
readonly property string renderAmbientLight4: "UFFIZI_GALLERY";
|
||||
readonly property string renderAmbientLight5: "GALILEOS_TOMB";
|
||||
readonly property string renderAmbientLight6: "VINE_STREET_KITCHEN";
|
||||
readonly property string renderAmbientLight7: "BREEZEWAY";
|
||||
readonly property string renderAmbientLight8: "CAMPUS_SUNSET";
|
||||
readonly property string renderAmbientLight9: "FUNSTON_BEACH_SUNSET";
|
||||
readonly property string resetAvatarSize: "Reset Avatar Size";
|
||||
readonly property string resetSensors: "Reset Sensors";
|
||||
readonly property string runningScripts: "Running Scripts...";
|
||||
readonly property string runTimingTests: "Run Timing Tests";
|
||||
readonly property string scriptEditor: "Script Editor...";
|
||||
readonly property string scriptedMotorControl: "Enable Scripted Motor Control";
|
||||
readonly property string showDSConnectTable: "Show Domain Connection Timing";
|
||||
readonly property string showBordersEntityNodes: "Show Entity Nodes";
|
||||
readonly property string showRealtimeEntityStats: "Show Realtime Entity Stats";
|
||||
readonly property string showWhosLookingAtMe: "Show Who's Looking at Me";
|
||||
readonly property string standingHMDSensorMode: "Standing HMD Sensor Mode";
|
||||
readonly property string simulateEyeTracking: "Simulate";
|
||||
readonly property string sMIEyeTracking: "SMI Eye Tracking";
|
||||
readonly property string stars: "Stars";
|
||||
readonly property string stats: "Stats";
|
||||
readonly property string stopAllScripts: "Stop All Scripts";
|
||||
readonly property string suppressShortTimings: "Suppress Timings Less than 10ms";
|
||||
readonly property string thirdPerson: "Third Person";
|
||||
readonly property string threePointCalibration: "3 Point Calibration";
|
||||
readonly property string throttleFPSIfNotFocus: "Throttle FPS If Not Focus"; // FIXME - this value duplicated in Basic2DWindowOpenGLDisplayPlugin.cpp
|
||||
readonly property string toolWindow: "Tool Window";
|
||||
readonly property string transmitterDrive: "Transmitter Drive";
|
||||
readonly property string turnWithHead: "Turn using Head";
|
||||
readonly property string uploadAsset: "Upload File to Asset Server";
|
||||
readonly property string useAudioForMouth: "Use Audio for Mouth";
|
||||
readonly property string useCamera: "Use Camera";
|
||||
readonly property string velocityFilter: "Velocity Filter";
|
||||
readonly property string visibleToEveryone: "Everyone";
|
||||
readonly property string visibleToFriends: "Friends";
|
||||
readonly property string visibleToNoOne: "No one";
|
||||
readonly property string worldAxes: "World Axes";
|
||||
}
|
||||
|
|
@ -1,23 +0,0 @@
|
|||
import QtQuick 2.4 as Original
|
||||
import QtQuick.Controls.Styles 1.3 as OriginalStyles
|
||||
import "."
|
||||
import "../controls"
|
||||
|
||||
OriginalStyles.ButtonStyle {
|
||||
HifiConstants { id: hifi }
|
||||
padding {
|
||||
top: 8
|
||||
left: 12
|
||||
right: 12
|
||||
bottom: 8
|
||||
}
|
||||
background: Border {
|
||||
anchors.fill: parent
|
||||
}
|
||||
label: Text {
|
||||
verticalAlignment: Original.Text.AlignVCenter
|
||||
horizontalAlignment: Original.Text.AlignHCenter
|
||||
text: control.text
|
||||
color: control.enabled ? hifi.colors.text : hifi.colors.disabledText
|
||||
}
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
import QtQuick 2.4
|
||||
|
||||
Item {
|
||||
property string hifiBlue: "#0e7077"
|
||||
property alias colors: colorsObj
|
||||
|
||||
Item {
|
||||
id: colorsObj
|
||||
property string hifiRed: "red"
|
||||
}
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
ButtonStyle {
|
||||
background: Item { anchors.fill: parent }
|
||||
label: FontAwesome {
|
||||
id: icon
|
||||
font.pointSize: 18
|
||||
property alias unicode: text
|
||||
text: control.text
|
||||
color: control.enabled ? hifi.colors.text : hifi.colors.disabledText
|
||||
}
|
||||
}
|
|
@ -8,27 +8,10 @@ Frame {
|
|||
// The frame fills the parent, which should be the size of the content.
|
||||
// The frame decorations use negative anchor margins to extend beyond
|
||||
anchors.fill: parent
|
||||
// Size of the controls
|
||||
readonly property real iconSize: 24;
|
||||
|
||||
// Convenience accessor for the window
|
||||
property alias window: frame.parent
|
||||
// FIXME needed?
|
||||
property alias decoration: decoration
|
||||
|
||||
Rectangle {
|
||||
anchors { margins: -4 }
|
||||
visible: !decoration.visible
|
||||
anchors.fill: parent;
|
||||
color: "#7f7f7f7f";
|
||||
radius: 3;
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: decoration
|
||||
anchors { margins: -iconSize; topMargin: -iconSize * (window.closable ? 2 : 1); }
|
||||
// FIXME doesn't work
|
||||
// visible: window.activator.containsMouse
|
||||
anchors.fill: parent;
|
||||
color: "#7f7f7f7f";
|
||||
radius: 3;
|
||||
|
@ -36,14 +19,9 @@ Frame {
|
|||
// Allow dragging of the window
|
||||
MouseArea {
|
||||
id: dragMouseArea
|
||||
hoverEnabled: true
|
||||
anchors.fill: parent
|
||||
drag {
|
||||
target: window
|
||||
// minimumX: (decoration.width - window.width) * -1
|
||||
// minimumY: 0
|
||||
// maximumX: (window.parent.width - window.width) - 2 * (decoration.width - window.width)
|
||||
// maximumY: (window.parent.height - window.height) - 2 * (decoration.height - window.height)
|
||||
}
|
||||
drag.target: window
|
||||
}
|
||||
|
||||
Row {
|
||||
|
@ -53,6 +31,7 @@ Frame {
|
|||
anchors.rightMargin: iconSize
|
||||
anchors.topMargin: iconSize / 2
|
||||
spacing: iconSize / 4
|
||||
|
||||
FontAwesome {
|
||||
visible: false
|
||||
text: "\uf08d"
|
||||
|
@ -66,7 +45,6 @@ Frame {
|
|||
onClicked: { frame.pin(); mouse.accepted = false; }
|
||||
}
|
||||
}
|
||||
|
||||
FontAwesome {
|
||||
visible: window.closable
|
||||
text: closeClickArea.containsMouse ? "\uf057" : "\uf05c"
|
||||
|
@ -82,56 +60,6 @@ Frame {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Allow sizing of the window
|
||||
// FIXME works in native QML, doesn't work in Interface
|
||||
MouseArea {
|
||||
id: sizeDrag
|
||||
width: iconSize
|
||||
height: iconSize
|
||||
|
||||
anchors {
|
||||
right: decoration.right;
|
||||
bottom: decoration.bottom
|
||||
bottomMargin: iconSize * 2
|
||||
}
|
||||
property vector2d pressOrigin
|
||||
property vector2d sizeOrigin
|
||||
property bool hid: false
|
||||
onPressed: {
|
||||
console.log("Pressed on size")
|
||||
pressOrigin = Qt.vector2d(mouseX, mouseY)
|
||||
sizeOrigin = Qt.vector2d(window.content.width, window.content.height)
|
||||
hid = false;
|
||||
}
|
||||
onReleased: {
|
||||
if (hid) {
|
||||
window.content.visible = true
|
||||
hid = false;
|
||||
}
|
||||
}
|
||||
|
||||
onPositionChanged: {
|
||||
if (pressed) {
|
||||
if (window.content.visible) {
|
||||
window.content.visible = false;
|
||||
hid = true;
|
||||
}
|
||||
var delta = Qt.vector2d(mouseX, mouseY).minus(pressOrigin);
|
||||
frame.deltaSize(delta.x, delta.y)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FontAwesome {
|
||||
visible: window.resizable
|
||||
rotation: -45
|
||||
anchors { centerIn: sizeDrag }
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
text: "\uf07d"
|
||||
size: iconSize / 3 * 2
|
||||
style: Text.Outline; styleColor: "white"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
57
interface/resources/qml/windows/Fadable.qml
Normal file
57
interface/resources/qml/windows/Fadable.qml
Normal file
|
@ -0,0 +1,57 @@
|
|||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.4
|
||||
import QtGraphicalEffects 1.0
|
||||
import "."
|
||||
import "../styles"
|
||||
|
||||
// Enable window visibility transitions
|
||||
FocusScope {
|
||||
id: root
|
||||
HifiConstants { id: hifi }
|
||||
|
||||
// Should hiding the window destroy it or just hide it?
|
||||
property bool destroyOnInvisible: false
|
||||
|
||||
Component.onCompleted: {
|
||||
fadeTargetProperty = visible ? 1.0 : 0.0
|
||||
}
|
||||
|
||||
// The target property to animate, usually scale or opacity
|
||||
property alias fadeTargetProperty: root.opacity
|
||||
// always start the property at 0 to enable fade in on creation
|
||||
fadeTargetProperty: 0
|
||||
// DO NOT set visible to false or when derived types override it it
|
||||
// will short circuit the fade in on initial visibility
|
||||
// visible: false <--- NO
|
||||
|
||||
// Some dialogs should be destroyed when they become
|
||||
// invisible, so handle that
|
||||
onVisibleChanged: {
|
||||
// If someone directly set the visibility to false
|
||||
// toggle it back on and use the targetVisible flag to transition
|
||||
// via fading.
|
||||
if ((!visible && fadeTargetProperty != 0.0) || (visible && fadeTargetProperty == 0.0)) {
|
||||
var target = visible;
|
||||
visible = !visible;
|
||||
fadeTargetProperty = target ? 1.0 : 0.0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!visible && destroyOnInvisible) {
|
||||
destroy();
|
||||
}
|
||||
}
|
||||
|
||||
// The actual animator
|
||||
Behavior on fadeTargetProperty {
|
||||
NumberAnimation {
|
||||
duration: hifi.effects.fadeInDuration
|
||||
easing.type: Easing.InOutCubic
|
||||
}
|
||||
}
|
||||
|
||||
// Once we're transparent, disable the dialog's visibility
|
||||
onFadeTargetPropertyChanged: {
|
||||
visible = (fadeTargetProperty != 0.0);
|
||||
}
|
||||
}
|
|
@ -1,8 +1,95 @@
|
|||
import QtQuick 2.5
|
||||
|
||||
import "../controls"
|
||||
|
||||
Item {
|
||||
signal close()
|
||||
signal pin()
|
||||
signal raise()
|
||||
signal deltaSize(real dx, real dy)
|
||||
id: frame
|
||||
|
||||
// Convenience accessor for the window
|
||||
property alias window: frame.parent
|
||||
readonly property int iconSize: 24
|
||||
default property var decoration;
|
||||
|
||||
children: [
|
||||
decoration,
|
||||
sizeOutline,
|
||||
debugZ,
|
||||
sizeDrag,
|
||||
]
|
||||
|
||||
Text {
|
||||
id: debugZ
|
||||
visible: DebugQML
|
||||
text: "Z: " + window.z
|
||||
y: -height
|
||||
}
|
||||
|
||||
function close() {
|
||||
window.close();
|
||||
}
|
||||
|
||||
function raise() {
|
||||
window.raise();
|
||||
}
|
||||
|
||||
function deltaSize(dx, dy) {
|
||||
var newSize = Qt.vector2d(window.width + dx, window.height + dy);
|
||||
newSize = clampVector(newSize, window.minSize, window.maxSize);
|
||||
window.width = newSize.x
|
||||
window.height = newSize.y
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: sizeOutline
|
||||
width: window.width
|
||||
height: window.height
|
||||
color: "#00000000"
|
||||
border.width: 4
|
||||
radius: 10
|
||||
visible: !window.content.visible
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: sizeDrag
|
||||
width: iconSize
|
||||
height: iconSize
|
||||
enabled: window.resizable
|
||||
x: window.width
|
||||
y: window.height
|
||||
property vector2d pressOrigin
|
||||
property vector2d sizeOrigin
|
||||
property bool hid: false
|
||||
onPressed: {
|
||||
console.log("Pressed on size")
|
||||
pressOrigin = Qt.vector2d(mouseX, mouseY)
|
||||
sizeOrigin = Qt.vector2d(window.content.width, window.content.height)
|
||||
hid = false;
|
||||
}
|
||||
onReleased: {
|
||||
if (hid) {
|
||||
window.content.visible = true
|
||||
hid = false;
|
||||
}
|
||||
}
|
||||
onPositionChanged: {
|
||||
if (pressed) {
|
||||
if (window.content.visible) {
|
||||
window.content.visible = false;
|
||||
hid = true;
|
||||
}
|
||||
var delta = Qt.vector2d(mouseX, mouseY).minus(pressOrigin);
|
||||
frame.deltaSize(delta.x, delta.y)
|
||||
}
|
||||
}
|
||||
FontAwesome {
|
||||
visible: sizeDrag.enabled
|
||||
rotation: -45
|
||||
anchors { centerIn: parent }
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
text: "\uf07d"
|
||||
size: iconSize / 3 * 2
|
||||
style: Text.Outline; styleColor: "white"
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
29
interface/resources/qml/windows/ModalFrame.qml
Normal file
29
interface/resources/qml/windows/ModalFrame.qml
Normal file
|
@ -0,0 +1,29 @@
|
|||
import QtQuick 2.5
|
||||
|
||||
import "."
|
||||
import "../controls"
|
||||
|
||||
Frame {
|
||||
id: frame
|
||||
// The frame fills the parent, which should be the size of the content.
|
||||
// The frame decorations use negative anchor margins to extend beyond
|
||||
anchors.fill: parent
|
||||
property alias window: frame.parent
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
anchors.margins: -4096
|
||||
visible: window.visible
|
||||
color: "#7f7f7f7f";
|
||||
radius: 3;
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
acceptedButtons: Qt.AllButtons
|
||||
onClicked: { }
|
||||
onDoubleClicked: {}
|
||||
onPressAndHold: {}
|
||||
onReleased: {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,53 +1,48 @@
|
|||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.4
|
||||
import QtGraphicalEffects 1.0
|
||||
|
||||
import "."
|
||||
import "../styles"
|
||||
|
||||
FocusScope {
|
||||
// FIXME how do I set the initial position of a window without
|
||||
// overriding places where the a individual client of the window
|
||||
// might be setting the position with a Settings{} element?
|
||||
|
||||
// FIXME how to I enable dragging without allowing the window to lay outside
|
||||
// of the desktop? How do I ensure when the desktop resizes all the windows
|
||||
// are still at least partially visible?
|
||||
Fadable {
|
||||
id: window
|
||||
HifiConstants { id: hifi }
|
||||
// The Window size is the size of the content, while the frame
|
||||
// decorations can extend outside it. Windows should generally not be
|
||||
// given explicit height / width, but rather be allowed to conform to
|
||||
// their content
|
||||
// decorations can extend outside it.
|
||||
implicitHeight: content.height
|
||||
implicitWidth: content.width
|
||||
|
||||
property bool topLevelWindow: true
|
||||
property int modality: Qt.NonModal
|
||||
|
||||
readonly property bool topLevelWindow: true
|
||||
property string title
|
||||
// Should the window include a close control?
|
||||
// Should the window be closable control?
|
||||
property bool closable: true
|
||||
// Should the window try to remain on top of other windows?
|
||||
property bool alwaysOnTop: false
|
||||
// Should hitting the close button hide or destroy the window?
|
||||
property bool destroyOnCloseButton: true
|
||||
// Should hiding the window destroy it or just hide it?
|
||||
property bool destroyOnInvisible: false
|
||||
// FIXME support for pinned / unpinned pending full design
|
||||
// property bool pinnable: false
|
||||
// property bool pinned: false
|
||||
property bool resizable: false
|
||||
property vector2d minSize: Qt.vector2d(100, 100)
|
||||
property vector2d maxSize: Qt.vector2d(1280, 720)
|
||||
enabled: visible
|
||||
|
||||
// The content to place inside the window, determined by the client
|
||||
default property var content
|
||||
|
||||
|
||||
onContentChanged: {
|
||||
if (content) {
|
||||
content.anchors.fill = window
|
||||
}
|
||||
}
|
||||
|
||||
// Default to a standard frame. Can be overriden to provide custom
|
||||
// frame styles, like a full desktop frame to simulate a modal window
|
||||
property var frame: DefaultFrame {
|
||||
z: -1
|
||||
anchors.fill: parent
|
||||
}
|
||||
|
||||
// This mouse area serves to raise the window. To function, it must live
|
||||
// in the window and have a higher Z-order than the content, but follow
|
||||
// This mouse area serves to raise the window. To function, it must live
|
||||
// in the window and have a higher Z-order than the content, but follow
|
||||
// the position and size of frame decoration
|
||||
property var activator: MouseArea {
|
||||
width: frame.decoration.width
|
||||
|
@ -56,18 +51,48 @@ FocusScope {
|
|||
y: frame.decoration.anchors.topMargin
|
||||
propagateComposedEvents: true
|
||||
hoverEnabled: true
|
||||
onPressed: { window.raise(); mouse.accepted = false; }
|
||||
// Debugging visualization
|
||||
// Rectangle { anchors.fill:parent; color: "#7f00ff00" }
|
||||
acceptedButtons: Qt.AllButtons
|
||||
onPressed: {
|
||||
//console.log("Pressed on activator area");
|
||||
window.raise();
|
||||
mouse.accepted = false;
|
||||
}
|
||||
// Debugging
|
||||
// onEntered: console.log("activator entered")
|
||||
// onExited: console.log("activator exited")
|
||||
// onContainsMouseChanged: console.log("Activator contains mouse " + containsMouse)
|
||||
// onPositionChanged: console.log("Activator mouse position " + mouse.x + " x " + mouse.y)
|
||||
// Rectangle { anchors.fill:parent; color: "#7f00ff00" }
|
||||
}
|
||||
|
||||
signal windowDestroyed();
|
||||
|
||||
// Default to a standard frame. Can be overriden to provide custom
|
||||
// frame styles, like a full desktop frame to simulate a modal window
|
||||
property var frame;
|
||||
|
||||
Component {
|
||||
id: defaultFrameBuilder;
|
||||
DefaultFrame { anchors.fill: parent }
|
||||
}
|
||||
|
||||
Component {
|
||||
id: modalFrameBuilder;
|
||||
ModalFrame { anchors.fill: parent }
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
if (!frame) {
|
||||
if (modality === Qt.NonModal) {
|
||||
frame = defaultFrameBuilder.createObject(window);
|
||||
} else {
|
||||
frame = modalFrameBuilder.createObject(window);
|
||||
}
|
||||
}
|
||||
raise();
|
||||
}
|
||||
|
||||
children: [ frame, content, activator ]
|
||||
signal windowDestroyed();
|
||||
|
||||
Component.onCompleted: {
|
||||
fadeTargetProperty = visible ? 1.0 : 0.0
|
||||
raise();
|
||||
}
|
||||
|
||||
Component.onDestruction: {
|
||||
content.destroy();
|
||||
|
@ -76,17 +101,15 @@ FocusScope {
|
|||
}
|
||||
onParentChanged: raise();
|
||||
|
||||
Connections {
|
||||
target: frame
|
||||
onRaise: window.raise();
|
||||
onClose: window.close();
|
||||
onPin: window.pin();
|
||||
onDeltaSize: {
|
||||
var newSize = Qt.vector2d(content.width + dx, content.height + dy);
|
||||
newSize = clampVector(newSize, minSize, maxSize);
|
||||
window.width = newSize.x
|
||||
window.height = newSize.y
|
||||
onVisibleChanged: {
|
||||
if (!visible && destroyOnInvisible) {
|
||||
destroy();
|
||||
return;
|
||||
}
|
||||
if (visible) {
|
||||
raise();
|
||||
}
|
||||
enabled = visible
|
||||
}
|
||||
|
||||
function raise() {
|
||||
|
@ -114,67 +137,6 @@ FocusScope {
|
|||
visible = false;
|
||||
}
|
||||
|
||||
//
|
||||
// Enable window visibility transitions
|
||||
//
|
||||
|
||||
// The target property to animate, usually scale or opacity
|
||||
property alias fadeTargetProperty: window.opacity
|
||||
// always start the property at 0 to enable fade in on creation
|
||||
opacity: 0
|
||||
|
||||
// Some dialogs should be destroyed when they become
|
||||
// invisible, so handle that
|
||||
onVisibleChanged: {
|
||||
// If someone directly set the visibility to false
|
||||
// toggle it back on and use the targetVisible flag to transition
|
||||
// via fading.
|
||||
if ((!visible && fadeTargetProperty != 0.0) || (visible && fadeTargetProperty == 0.0)) {
|
||||
var target = visible;
|
||||
visible = !visible;
|
||||
fadeTargetProperty = target ? 1.0 : 0.0;
|
||||
return;
|
||||
}
|
||||
if (!visible && destroyOnInvisible) {
|
||||
console.log("Destroying " + window);
|
||||
destroy();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// The offscreen UI will enable an object, rather than manipulating it's
|
||||
// visibility, so that we can do animations in both directions. Because
|
||||
// visibility is a boolean flags, it cannot be animated. So when
|
||||
// targetVisible is changed, we modify a property that can be animated,
|
||||
// like scale or opacity, and then when the target animation value is reached,
|
||||
// we can modify the visibility
|
||||
|
||||
// The actual animator
|
||||
Behavior on fadeTargetProperty {
|
||||
NumberAnimation {
|
||||
duration: hifi.effects.fadeInDuration
|
||||
easing.type: Easing.OutCubic
|
||||
}
|
||||
}
|
||||
|
||||
// Once we're transparent, disable the dialog's visibility
|
||||
onFadeTargetPropertyChanged: {
|
||||
visible = (fadeTargetProperty != 0.0);
|
||||
}
|
||||
|
||||
|
||||
Keys.onPressed: {
|
||||
switch(event.key) {
|
||||
case Qt.Key_W:
|
||||
if (event.modifiers === Qt.ControlModifier) {
|
||||
event.accepted = true
|
||||
visible = false
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function clamp(value, min, max) {
|
||||
return Math.min(Math.max(value, min), max);
|
||||
}
|
||||
|
@ -185,4 +147,14 @@ FocusScope {
|
|||
clamp(value.y, min.y, max.y))
|
||||
}
|
||||
|
||||
Keys.onPressed: {
|
||||
switch(event.key) {
|
||||
case Qt.Key_W:
|
||||
if (window.closable && (event.modifiers === Qt.ControlModifier)) {
|
||||
visible = false
|
||||
event.accepted = true
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -80,7 +80,6 @@
|
|||
#include <controllers/StateController.h>
|
||||
#include <LogHandler.h>
|
||||
#include <MainWindow.h>
|
||||
#include <MessageDialog.h>
|
||||
#include <MessagesClient.h>
|
||||
#include <ModelEntityItem.h>
|
||||
#include <NetworkAccessManager.h>
|
||||
|
@ -149,7 +148,6 @@
|
|||
#endif
|
||||
#include "Stars.h"
|
||||
#include "ui/AddressBarDialog.h"
|
||||
#include "ui/RecorderDialog.h"
|
||||
#include "ui/AvatarInputs.h"
|
||||
#include "ui/AssetUploadDialogFactory.h"
|
||||
#include "ui/DataWebDialog.h"
|
||||
|
@ -1176,10 +1174,8 @@ void Application::initializeGL() {
|
|||
|
||||
void Application::initializeUi() {
|
||||
AddressBarDialog::registerType();
|
||||
RecorderDialog::registerType();
|
||||
ErrorDialog::registerType();
|
||||
LoginDialog::registerType();
|
||||
MessageDialog::registerType();
|
||||
VrMenu::registerType();
|
||||
Tooltip::registerType();
|
||||
UpdateDialog::registerType();
|
||||
|
@ -1843,14 +1839,6 @@ void Application::keyPressEvent(QKeyEvent* event) {
|
|||
}
|
||||
break;
|
||||
|
||||
case Qt::Key_X:
|
||||
if (isMeta && isShifted) {
|
||||
// auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
||||
// offscreenUi->load("TestControllers.qml");
|
||||
RecorderDialog::toggle();
|
||||
}
|
||||
break;
|
||||
|
||||
case Qt::Key_L:
|
||||
if (isShifted && isMeta) {
|
||||
Menu::getInstance()->triggerOption(MenuOption::Log);
|
||||
|
@ -4544,7 +4532,7 @@ bool Application::displayAvatarAttachmentConfirmationDialog(const QString& name)
|
|||
|
||||
void Application::toggleRunningScriptsWidget() {
|
||||
static const QUrl url("dialogs/RunningScripts.qml");
|
||||
DependencyManager::get<OffscreenUi>()->toggle(url, "RunningScripts");
|
||||
DependencyManager::get<OffscreenUi>()->show(url, "RunningScripts");
|
||||
//if (_runningScriptsWidget->isVisible()) {
|
||||
// if (_runningScriptsWidget->hasFocus()) {
|
||||
// _runningScriptsWidget->hide();
|
||||
|
|
|
@ -168,9 +168,9 @@ QScriptValue WindowScriptingInterface::showAlert(const QString& message) {
|
|||
/// \return QScriptValue `true` if 'Yes' was clicked, `false` otherwise
|
||||
QScriptValue WindowScriptingInterface::showConfirm(const QString& message) {
|
||||
bool confirm = false;
|
||||
OffscreenUi::question("", message, [&](QMessageBox::StandardButton response){
|
||||
confirm = (response == QMessageBox::Yes);
|
||||
});
|
||||
if (QMessageBox::Yes == OffscreenUi::question("", message)) {
|
||||
confirm = true;
|
||||
}
|
||||
return QScriptValue(confirm);
|
||||
}
|
||||
|
||||
|
|
|
@ -61,10 +61,10 @@ void AddressBarDialog::loadForward() {
|
|||
}
|
||||
|
||||
void AddressBarDialog::displayAddressOfflineMessage() {
|
||||
OffscreenUi::error("That user or place is currently offline");
|
||||
OffscreenUi::critical("", "That user or place is currently offline");
|
||||
}
|
||||
|
||||
void AddressBarDialog::displayAddressNotFoundMessage() {
|
||||
OffscreenUi::error("There is no address information for that user or place");
|
||||
OffscreenUi::critical("", "There is no address information for that user or place");
|
||||
}
|
||||
|
||||
|
|
|
@ -147,10 +147,6 @@ void DialogsManager::lodTools() {
|
|||
_lodToolsDialog->raise();
|
||||
}
|
||||
|
||||
void DialogsManager::toggleToolWindow() {
|
||||
DependencyManager::get<OffscreenUi>()->toggleToolWindow();
|
||||
}
|
||||
|
||||
void DialogsManager::hmdTools(bool showTools) {
|
||||
if (showTools) {
|
||||
if (!_hmdToolsDialog) {
|
||||
|
|
|
@ -66,7 +66,6 @@ signals:
|
|||
void addressBarToggled();
|
||||
|
||||
private slots:
|
||||
void toggleToolWindow();
|
||||
void hmdToolsClosed();
|
||||
|
||||
private:
|
||||
|
|
|
@ -1,29 +0,0 @@
|
|||
//
|
||||
// MarketplaceDialog.cpp
|
||||
//
|
||||
// Created by Bradley Austin Davis on 2015/04/14
|
||||
// Copyright 2015 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
|
||||
//
|
||||
|
||||
#include "Application.h"
|
||||
#include "MarketplaceDialog.h"
|
||||
#include "DependencyManager.h"
|
||||
|
||||
HIFI_QML_DEF(MarketplaceDialog)
|
||||
|
||||
|
||||
MarketplaceDialog::MarketplaceDialog(QQuickItem* parent) : OffscreenQmlDialog(parent) {
|
||||
}
|
||||
|
||||
bool MarketplaceDialog::navigationRequested(const QString& url) {
|
||||
qDebug() << url;
|
||||
if (qApp->canAcceptURL(url)) {
|
||||
if (qApp->acceptURL(url)) {
|
||||
return false; // we handled it, so QWebPage doesn't need to handle it
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
//
|
||||
// MarketplaceDialog.h
|
||||
//
|
||||
// Created by Bradley Austin Davis on 2015/04/14
|
||||
// Copyright 2015 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
|
||||
//
|
||||
|
||||
#pragma once
|
||||
#ifndef hifi_MarketplaceDialog_h
|
||||
#define hifi_MarketplaceDialog_h
|
||||
|
||||
#include <OffscreenQmlDialog.h>
|
||||
|
||||
class MarketplaceDialog : public OffscreenQmlDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
HIFI_QML_DECL
|
||||
|
||||
public:
|
||||
MarketplaceDialog(QQuickItem* parent = nullptr);
|
||||
|
||||
Q_INVOKABLE bool navigationRequested(const QString& url);
|
||||
|
||||
};
|
||||
|
||||
#endif
|
|
@ -1,22 +0,0 @@
|
|||
//
|
||||
// Created by Bradley Austin Davis on 2015/11/14
|
||||
// Copyright 2015 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
|
||||
//
|
||||
|
||||
#include "RecorderDialog.h"
|
||||
|
||||
#include <QMessageBox>
|
||||
|
||||
#include "DependencyManager.h"
|
||||
|
||||
HIFI_QML_DEF(RecorderDialog)
|
||||
|
||||
RecorderDialog::RecorderDialog(QQuickItem* parent) : OffscreenQmlDialog(parent) {
|
||||
}
|
||||
|
||||
void RecorderDialog::hide() {
|
||||
((QQuickItem*)parent())->setEnabled(false);
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
//
|
||||
// Created by Bradley Austin Davis on 2015/11/14
|
||||
// Copyright 2015 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
|
||||
//
|
||||
|
||||
#pragma once
|
||||
#ifndef hifi_RecorderDialog_h
|
||||
#define hifi_RecorderDialog_h
|
||||
|
||||
#include <OffscreenQmlDialog.h>
|
||||
|
||||
class RecorderDialog : public OffscreenQmlDialog {
|
||||
Q_OBJECT
|
||||
HIFI_QML_DECL
|
||||
|
||||
public:
|
||||
RecorderDialog(QQuickItem* parent = nullptr);
|
||||
|
||||
signals:
|
||||
|
||||
protected:
|
||||
void hide();
|
||||
};
|
||||
|
||||
#endif
|
|
@ -1,119 +0,0 @@
|
|||
//
|
||||
// MessageDialog.cpp
|
||||
//
|
||||
// Created by Bradley Austin Davis on 2015/04/14
|
||||
// Copyright 2015 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
|
||||
//
|
||||
#include "MessageDialog.h"
|
||||
|
||||
HIFI_QML_DEF(MessageDialog)
|
||||
|
||||
MessageDialog::MessageDialog(QQuickItem* parent) : OffscreenQmlDialog(parent) {
|
||||
_buttons = StandardButtons(Ok | Cancel);
|
||||
}
|
||||
|
||||
MessageDialog::~MessageDialog() {
|
||||
}
|
||||
|
||||
QString MessageDialog::text() const {
|
||||
return _text;
|
||||
}
|
||||
|
||||
QString MessageDialog::informativeText() const {
|
||||
return _informativeText;
|
||||
}
|
||||
|
||||
QString MessageDialog::detailedText() const {
|
||||
return _detailedText;
|
||||
}
|
||||
|
||||
MessageDialog::Icon MessageDialog::icon() const {
|
||||
return _icon;
|
||||
}
|
||||
|
||||
void MessageDialog::setVisible(bool v) {
|
||||
OffscreenQmlDialog::setVisible(v);
|
||||
}
|
||||
|
||||
void MessageDialog::setText(const QString& arg) {
|
||||
if (arg != _text) {
|
||||
_text = arg;
|
||||
emit textChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void MessageDialog::setInformativeText(const QString& arg) {
|
||||
if (arg != _informativeText) {
|
||||
_informativeText = arg;
|
||||
emit informativeTextChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void MessageDialog::setDetailedText(const QString& arg) {
|
||||
if (arg != _detailedText) {
|
||||
_detailedText = arg;
|
||||
emit detailedTextChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void MessageDialog::setIcon(MessageDialog::Icon icon) {
|
||||
if (icon != _icon) {
|
||||
_icon = icon;
|
||||
emit iconChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void MessageDialog::setStandardButtons(StandardButtons buttons) {
|
||||
if (buttons != _buttons) {
|
||||
_buttons = buttons;
|
||||
emit standardButtonsChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void MessageDialog::click(StandardButton button) {
|
||||
// FIXME try to do it more like the standard dialog
|
||||
click(StandardButton(button), ButtonRole::NoRole);
|
||||
}
|
||||
|
||||
MessageDialog::StandardButtons MessageDialog::standardButtons() const {
|
||||
return _buttons;
|
||||
}
|
||||
|
||||
MessageDialog::StandardButton MessageDialog::clickedButton() const {
|
||||
return _clickedButton;
|
||||
}
|
||||
|
||||
void MessageDialog::click(StandardButton button, ButtonRole) {
|
||||
_clickedButton = button;
|
||||
if (_resultCallback) {
|
||||
_resultCallback(QMessageBox::StandardButton(_clickedButton));
|
||||
}
|
||||
hide();
|
||||
}
|
||||
|
||||
void MessageDialog::accept() {
|
||||
// enter key is treated like OK
|
||||
if (_clickedButton == NoButton)
|
||||
_clickedButton = Ok;
|
||||
if (_resultCallback) {
|
||||
_resultCallback(QMessageBox::StandardButton(_clickedButton));
|
||||
}
|
||||
OffscreenQmlDialog::accept();
|
||||
}
|
||||
|
||||
void MessageDialog::reject() {
|
||||
// escape key is treated like cancel
|
||||
if (_clickedButton == NoButton)
|
||||
_clickedButton = Cancel;
|
||||
if (_resultCallback) {
|
||||
_resultCallback(QMessageBox::StandardButton(_clickedButton));
|
||||
}
|
||||
OffscreenQmlDialog::reject();
|
||||
}
|
||||
|
||||
void MessageDialog::setResultCallback(OffscreenUi::ButtonCallback callback) {
|
||||
_resultCallback = callback;
|
||||
}
|
|
@ -1,100 +0,0 @@
|
|||
//
|
||||
// MessageDialog.h
|
||||
//
|
||||
// Created by Bradley Austin Davis on 2015/04/14
|
||||
// Copyright 2015 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
|
||||
//
|
||||
|
||||
#pragma once
|
||||
#ifndef hifi_MessageDialog_h
|
||||
#define hifi_MessageDialog_h
|
||||
|
||||
#include "OffscreenQmlDialog.h"
|
||||
|
||||
class MessageDialog : public OffscreenQmlDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
HIFI_QML_DECL
|
||||
|
||||
private:
|
||||
Q_ENUMS(Icon)
|
||||
Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged)
|
||||
Q_PROPERTY(QString informativeText READ informativeText WRITE setInformativeText NOTIFY informativeTextChanged)
|
||||
Q_PROPERTY(QString detailedText READ detailedText WRITE setDetailedText NOTIFY detailedTextChanged)
|
||||
Q_PROPERTY(Icon icon READ icon WRITE setIcon NOTIFY iconChanged)
|
||||
Q_PROPERTY(StandardButtons standardButtons READ standardButtons WRITE setStandardButtons NOTIFY standardButtonsChanged)
|
||||
Q_PROPERTY(StandardButton clickedButton READ clickedButton NOTIFY buttonClicked)
|
||||
|
||||
public:
|
||||
enum Icon { NoIcon, Information, Warning, Critical, Question };
|
||||
|
||||
enum ButtonRole {
|
||||
// keep this in sync with QDialogButtonBox::ButtonRole and QPlatformDialogHelper::ButtonRole
|
||||
InvalidRole = -1,
|
||||
AcceptRole,
|
||||
RejectRole,
|
||||
DestructiveRole,
|
||||
ActionRole,
|
||||
HelpRole,
|
||||
YesRole,
|
||||
NoRole,
|
||||
ResetRole,
|
||||
ApplyRole,
|
||||
|
||||
NRoles
|
||||
};
|
||||
|
||||
MessageDialog(QQuickItem* parent = 0);
|
||||
virtual ~MessageDialog();
|
||||
|
||||
QString text() const;
|
||||
QString informativeText() const;
|
||||
QString detailedText() const;
|
||||
Icon icon() const;
|
||||
|
||||
public slots:
|
||||
virtual void setVisible(bool v);
|
||||
void setText(const QString& arg);
|
||||
void setInformativeText(const QString& arg);
|
||||
void setDetailedText(const QString& arg);
|
||||
void setIcon(Icon icon);
|
||||
void setStandardButtons(StandardButtons buttons);
|
||||
void setResultCallback(OffscreenUi::ButtonCallback callback);
|
||||
void click(StandardButton button);
|
||||
StandardButtons standardButtons() const;
|
||||
StandardButton clickedButton() const;
|
||||
|
||||
signals:
|
||||
void textChanged();
|
||||
void informativeTextChanged();
|
||||
void detailedTextChanged();
|
||||
void iconChanged();
|
||||
void standardButtonsChanged();
|
||||
void buttonClicked();
|
||||
void discard();
|
||||
void help();
|
||||
void yes();
|
||||
void no();
|
||||
void apply();
|
||||
void reset();
|
||||
|
||||
protected slots:
|
||||
virtual void click(StandardButton button, ButtonRole);
|
||||
virtual void accept();
|
||||
virtual void reject();
|
||||
|
||||
private:
|
||||
QString _title;
|
||||
QString _text;
|
||||
QString _informativeText;
|
||||
QString _detailedText;
|
||||
Icon _icon{ Information };
|
||||
StandardButtons _buttons;
|
||||
StandardButton _clickedButton{ NoButton };
|
||||
OffscreenUi::ButtonCallback _resultCallback;
|
||||
};
|
||||
|
||||
#endif // hifi_MessageDialog_h
|
|
@ -17,7 +17,7 @@ OffscreenQmlDialog::~OffscreenQmlDialog() {
|
|||
}
|
||||
|
||||
void OffscreenQmlDialog::hide() {
|
||||
static_cast<QQuickItem*>(parent())->setEnabled(false);
|
||||
static_cast<QQuickItem*>(parent())->setVisible(false);
|
||||
}
|
||||
|
||||
QString OffscreenQmlDialog::title() const {
|
||||
|
|
|
@ -16,10 +16,6 @@
|
|||
#include <AbstractUriHandler.h>
|
||||
#include <AccountManager.h>
|
||||
|
||||
|
||||
#include "ErrorDialog.h"
|
||||
#include "MessageDialog.h"
|
||||
|
||||
// Needs to match the constants in resources/qml/Global.js
|
||||
class OffscreenFlags : public QObject {
|
||||
Q_OBJECT
|
||||
|
@ -117,7 +113,7 @@ void OffscreenUi::show(const QUrl& url, const QString& name, std::function<void(
|
|||
item = getRootItem()->findChild<QQuickItem*>(name);
|
||||
}
|
||||
if (item) {
|
||||
item->setEnabled(true);
|
||||
item->setVisible(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -129,109 +125,103 @@ void OffscreenUi::toggle(const QUrl& url, const QString& name, std::function<voi
|
|||
item = getRootItem()->findChild<QQuickItem*>(name);
|
||||
}
|
||||
if (item) {
|
||||
item->setEnabled(!item->isEnabled());
|
||||
item->setVisible(!item->isVisible());
|
||||
}
|
||||
}
|
||||
|
||||
void OffscreenUi::messageBox(const QString& title, const QString& text,
|
||||
ButtonCallback callback,
|
||||
QMessageBox::Icon icon,
|
||||
QMessageBox::StandardButtons buttons) {
|
||||
MessageDialog* pDialog{ nullptr };
|
||||
MessageDialog::show([&](QQmlContext* ctx, QObject* item) {
|
||||
pDialog = item->findChild<MessageDialog*>();
|
||||
pDialog->setIcon((MessageDialog::Icon)icon);
|
||||
pDialog->setTitle(title);
|
||||
pDialog->setText(text);
|
||||
pDialog->setStandardButtons(MessageDialog::StandardButtons(static_cast<int>(buttons)));
|
||||
pDialog->setResultCallback(callback);
|
||||
});
|
||||
pDialog->setEnabled(true);
|
||||
}
|
||||
class MessageBoxListener : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
void OffscreenUi::information(const QString& title, const QString& text,
|
||||
ButtonCallback callback,
|
||||
QMessageBox::StandardButtons buttons) {
|
||||
messageBox(title, text, callback,
|
||||
static_cast<QMessageBox::Icon>(MessageDialog::Information), buttons);
|
||||
}
|
||||
friend class OffscreenUi;
|
||||
|
||||
void OffscreenUi::question(const QString& title, const QString& text,
|
||||
ButtonCallback callback,
|
||||
QMessageBox::StandardButtons buttons) {
|
||||
|
||||
bool waiting = true;
|
||||
ButtonCallback blockingCallback = [&](QMessageBox::StandardButton response){
|
||||
callback(response); // call the actual callback
|
||||
waiting = false;
|
||||
};
|
||||
|
||||
messageBox(title, text, blockingCallback,
|
||||
static_cast<QMessageBox::Icon>(MessageDialog::Question), buttons);
|
||||
|
||||
// block until the call back has been called
|
||||
while (waiting) {
|
||||
QCoreApplication::processEvents();
|
||||
MessageBoxListener(QQuickItem* messageBox) : _messageBox(messageBox) {
|
||||
if (!_messageBox) {
|
||||
_finished = true;
|
||||
return;
|
||||
}
|
||||
connect(_messageBox, SIGNAL(selected(int)), this, SLOT(onSelected(int)));
|
||||
connect(_messageBox, SIGNAL(destroyed()), this, SLOT(onDestroyed()));
|
||||
}
|
||||
|
||||
~MessageBoxListener() {
|
||||
disconnect(_messageBox);
|
||||
}
|
||||
|
||||
QMessageBox::StandardButton waitForResult() {
|
||||
while (!_finished) {
|
||||
QCoreApplication::processEvents();
|
||||
}
|
||||
return _result;
|
||||
}
|
||||
|
||||
private slots:
|
||||
void onSelected(int button) {
|
||||
_result = static_cast<QMessageBox::StandardButton>(button);
|
||||
_finished = true;
|
||||
disconnect(_messageBox);
|
||||
}
|
||||
|
||||
void onDestroyed() {
|
||||
_finished = true;
|
||||
disconnect(_messageBox);
|
||||
}
|
||||
|
||||
private:
|
||||
bool _finished { false };
|
||||
QMessageBox::StandardButton _result { QMessageBox::StandardButton::NoButton };
|
||||
QQuickItem* const _messageBox;
|
||||
};
|
||||
|
||||
QMessageBox::StandardButton OffscreenUi::messageBox(QMessageBox::Icon icon, const QString& title, const QString& text, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton) {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QMessageBox::StandardButton result = QMessageBox::StandardButton::NoButton;
|
||||
QMetaObject::invokeMethod(this, "messageBox", Qt::BlockingQueuedConnection,
|
||||
Q_RETURN_ARG(QMessageBox::StandardButton, result),
|
||||
Q_ARG(QMessageBox::Icon, icon),
|
||||
Q_ARG(QString, title),
|
||||
Q_ARG(QString, text),
|
||||
Q_ARG(QMessageBox::StandardButtons, buttons),
|
||||
Q_ARG(QMessageBox::StandardButton, defaultButton));
|
||||
return result;
|
||||
}
|
||||
|
||||
QVariantMap map;
|
||||
map.insert("title", title);
|
||||
map.insert("text", text);
|
||||
map.insert("icon", icon);
|
||||
map.insert("buttons", buttons.operator int());
|
||||
map.insert("defaultButton", defaultButton);
|
||||
QVariant result;
|
||||
bool invokeResult = QMetaObject::invokeMethod(getDesktop(), "messageBox",
|
||||
Q_RETURN_ARG(QVariant, result),
|
||||
Q_ARG(QVariant, QVariant::fromValue(map)));
|
||||
|
||||
if (!invokeResult) {
|
||||
qWarning() << "Failed to create message box";
|
||||
return QMessageBox::StandardButton::NoButton;
|
||||
}
|
||||
|
||||
auto resultButton = MessageBoxListener(qvariant_cast<QQuickItem*>(result)).waitForResult();
|
||||
qDebug() << "Message box got a result of " << resultButton;
|
||||
return resultButton;
|
||||
}
|
||||
|
||||
QMessageBox::StandardButton OffscreenUi::question(void* ignored, const QString& title, const QString& text,
|
||||
QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton) {
|
||||
|
||||
QMessageBox::StandardButton result = defaultButton;
|
||||
|
||||
OffscreenUi::question(title, text, [&](QMessageBox::StandardButton response){
|
||||
result = response;
|
||||
}, buttons);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
void OffscreenUi::warning(const QString& title, const QString& text,
|
||||
ButtonCallback callback,
|
||||
QMessageBox::StandardButtons buttons) {
|
||||
messageBox(title, text, callback,
|
||||
static_cast<QMessageBox::Icon>(MessageDialog::Warning), buttons);
|
||||
}
|
||||
|
||||
QMessageBox::StandardButton OffscreenUi::warning(void* ignored, const QString& title, const QString& text,
|
||||
QMessageBox::StandardButton OffscreenUi::critical(const QString& title, const QString& text,
|
||||
QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton) {
|
||||
|
||||
bool waiting = true;
|
||||
QMessageBox::StandardButton result = defaultButton;
|
||||
|
||||
OffscreenUi::warning(title, text, [&](QMessageBox::StandardButton response){
|
||||
result = response;
|
||||
waiting = false;
|
||||
}, buttons);
|
||||
|
||||
// block until the call back has been called
|
||||
while (waiting) {
|
||||
QCoreApplication::processEvents();
|
||||
}
|
||||
|
||||
return result;
|
||||
return DependencyManager::get<OffscreenUi>()->messageBox(QMessageBox::Icon::Critical, title, text, buttons, defaultButton);
|
||||
}
|
||||
|
||||
|
||||
void OffscreenUi::critical(const QString& title, const QString& text,
|
||||
ButtonCallback callback,
|
||||
QMessageBox::StandardButtons buttons) {
|
||||
messageBox(title, text, callback,
|
||||
static_cast<QMessageBox::Icon>(MessageDialog::Critical), buttons);
|
||||
QMessageBox::StandardButton OffscreenUi::information(const QString& title, const QString& text,
|
||||
QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton) {
|
||||
return DependencyManager::get<OffscreenUi>()->messageBox(QMessageBox::Icon::Critical, title, text, buttons, defaultButton);
|
||||
}
|
||||
|
||||
void OffscreenUi::error(const QString& text) {
|
||||
ErrorDialog* pDialog{ nullptr };
|
||||
ErrorDialog::show([&](QQmlContext* ctx, QObject* item) {
|
||||
pDialog = item->findChild<ErrorDialog*>();
|
||||
pDialog->setText(text);
|
||||
});
|
||||
pDialog->setEnabled(true);
|
||||
QMessageBox::StandardButton OffscreenUi::question(const QString& title, const QString& text,
|
||||
QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton) {
|
||||
return DependencyManager::get<OffscreenUi>()->messageBox(QMessageBox::Icon::Critical, title, text, buttons, defaultButton);
|
||||
}
|
||||
QMessageBox::StandardButton OffscreenUi::warning(const QString& title, const QString& text,
|
||||
QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton) {
|
||||
return DependencyManager::get<OffscreenUi>()->messageBox(QMessageBox::Icon::Critical, title, text, buttons, defaultButton);
|
||||
}
|
||||
|
||||
OffscreenUi::ButtonCallback OffscreenUi::NO_OP_CALLBACK = [](QMessageBox::StandardButton) {};
|
||||
|
||||
bool OffscreenUi::navigationFocused() {
|
||||
return offscreenFlags->isNavigationFocused();
|
||||
|
@ -245,16 +235,14 @@ void OffscreenUi::createDesktop() {
|
|||
if (_desktop) {
|
||||
qDebug() << "Desktop already created";
|
||||
}
|
||||
getRootContext()->setContextProperty("DebugQML", false);
|
||||
_desktop = dynamic_cast<QQuickItem*>(load("Root.qml"));
|
||||
Q_ASSERT(_desktop);
|
||||
getRootContext()->setContextProperty("Desktop", _desktop);
|
||||
_desktop->setProperty("offscreenWindow", QVariant::fromValue(getWindow()));
|
||||
_toolWindow = _desktop->findChild<QQuickItem*>("ToolWindow");
|
||||
}
|
||||
|
||||
void OffscreenUi::toggleToolWindow() {
|
||||
_toolWindow->setEnabled(!_toolWindow->isEnabled());
|
||||
}
|
||||
|
||||
QQuickItem* OffscreenUi::getDesktop() {
|
||||
return _desktop;
|
||||
}
|
||||
|
|
|
@ -40,45 +40,46 @@ public:
|
|||
Q_INVOKABLE void executeOnUiThread(std::function<void()> function);
|
||||
Q_INVOKABLE QVariant returnFromUiThread(std::function<QVariant()> function);
|
||||
|
||||
// Messagebox replacement functions
|
||||
using ButtonCallback = std::function<void(QMessageBox::StandardButton)>;
|
||||
static ButtonCallback NO_OP_CALLBACK;
|
||||
|
||||
static void messageBox(const QString& title, const QString& text,
|
||||
ButtonCallback f,
|
||||
QMessageBox::Icon icon,
|
||||
QMessageBox::StandardButtons buttons);
|
||||
|
||||
static void information(const QString& title, const QString& text,
|
||||
ButtonCallback callback = NO_OP_CALLBACK,
|
||||
QMessageBox::StandardButtons buttons = QMessageBox::Ok);
|
||||
|
||||
/// Note: will block until user clicks a response to the question
|
||||
static void question(const QString& title, const QString& text,
|
||||
ButtonCallback callback = NO_OP_CALLBACK,
|
||||
QMessageBox::StandardButtons buttons = QMessageBox::StandardButtons(QMessageBox::Yes | QMessageBox::No));
|
||||
|
||||
/// Same design as QMessageBox::critical(), will block, returns result
|
||||
static QMessageBox::StandardButton critical(void* ignored, const QString& title, const QString& text,
|
||||
QMessageBox::StandardButtons buttons = QMessageBox::Ok,
|
||||
QMessageBox::StandardButton defaultButton = QMessageBox::NoButton) {
|
||||
return critical(title, text, buttons, defaultButton);
|
||||
}
|
||||
/// Same design as QMessageBox::information(), will block, returns result
|
||||
static QMessageBox::StandardButton information(void* ignored, const QString& title, const QString& text,
|
||||
QMessageBox::StandardButtons buttons = QMessageBox::Ok,
|
||||
QMessageBox::StandardButton defaultButton = QMessageBox::NoButton) {
|
||||
return information(title, text, buttons, defaultButton);
|
||||
}
|
||||
/// Same design as QMessageBox::question(), will block, returns result
|
||||
static QMessageBox::StandardButton question(void* ignored, const QString& title, const QString& text,
|
||||
QMessageBox::StandardButtons buttons = QMessageBox::StandardButtons(QMessageBox::Yes | QMessageBox::No),
|
||||
QMessageBox::StandardButton defaultButton = QMessageBox::NoButton);
|
||||
|
||||
static void warning(const QString& title, const QString& text,
|
||||
ButtonCallback callback = NO_OP_CALLBACK,
|
||||
QMessageBox::StandardButtons buttons = QMessageBox::Ok);
|
||||
|
||||
static QMessageBox::StandardButton question(void* ignored, const QString& title, const QString& text,
|
||||
QMessageBox::StandardButtons buttons = QMessageBox::Ok,
|
||||
QMessageBox::StandardButton defaultButton = QMessageBox::NoButton) {
|
||||
return question(title, text, buttons, defaultButton);
|
||||
}
|
||||
/// Same design as QMessageBox::warning(), will block, returns result
|
||||
static QMessageBox::StandardButton warning(void* ignored, const QString& title, const QString& text,
|
||||
QMessageBox::StandardButtons buttons = QMessageBox::StandardButtons(QMessageBox::Yes | QMessageBox::No),
|
||||
QMessageBox::StandardButtons buttons = QMessageBox::Ok,
|
||||
QMessageBox::StandardButton defaultButton = QMessageBox::NoButton) {
|
||||
return warning(title, text, buttons, defaultButton);
|
||||
}
|
||||
|
||||
static QMessageBox::StandardButton critical(const QString& title, const QString& text,
|
||||
QMessageBox::StandardButtons buttons = QMessageBox::Ok,
|
||||
QMessageBox::StandardButton defaultButton = QMessageBox::NoButton);
|
||||
static QMessageBox::StandardButton information(const QString& title, const QString& text,
|
||||
QMessageBox::StandardButtons buttons = QMessageBox::Ok,
|
||||
QMessageBox::StandardButton defaultButton = QMessageBox::NoButton);
|
||||
static QMessageBox::StandardButton question(const QString& title, const QString& text,
|
||||
QMessageBox::StandardButtons buttons = QMessageBox::Ok,
|
||||
QMessageBox::StandardButton defaultButton = QMessageBox::NoButton);
|
||||
static QMessageBox::StandardButton warning(const QString& title, const QString& text,
|
||||
QMessageBox::StandardButtons buttons = QMessageBox::Ok,
|
||||
QMessageBox::StandardButton defaultButton = QMessageBox::NoButton);
|
||||
|
||||
static void critical(const QString& title, const QString& text,
|
||||
ButtonCallback callback = NO_OP_CALLBACK,
|
||||
QMessageBox::StandardButtons buttons = QMessageBox::Ok);
|
||||
QMessageBox::StandardButton messageBox(QMessageBox::Icon icon, const QString& title, const QString& text, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton);
|
||||
|
||||
static void error(const QString& text); // Interim dialog in new style
|
||||
|
||||
void toggleToolWindow();
|
||||
private:
|
||||
QQuickItem* _desktop { nullptr };
|
||||
QQuickItem* _toolWindow { nullptr };
|
||||
|
|
|
@ -250,16 +250,13 @@ QQuickItem* QmlWindowClass::asQuickItem() const {
|
|||
}
|
||||
|
||||
void QmlWindowClass::setVisible(bool visible) {
|
||||
// For tool window tabs we special case visiblility as enable / disable of the tab, not the window
|
||||
// The tool window itself has special logic based on whether any tabs are enabled
|
||||
QQuickItem* targetWindow = asQuickItem();
|
||||
if (_toolWindow) {
|
||||
auto targetTab = dynamic_cast<QQuickItem*>(_qmlWindow);
|
||||
DependencyManager::get<OffscreenUi>()->executeOnUiThread([=] {
|
||||
targetTab->setEnabled(visible);
|
||||
//emit visibilityChanged(visible);
|
||||
});
|
||||
// For tool window tabs we special case visibility as a function call on the tab parent
|
||||
// The tool window itself has special logic based on whether any tabs are visible
|
||||
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
||||
QMetaObject::invokeMethod(targetWindow, "showTabForUrl", Qt::QueuedConnection, Q_ARG(QVariant, _source), Q_ARG(QVariant, visible));
|
||||
} else {
|
||||
QQuickItem* targetWindow = asQuickItem();
|
||||
DependencyManager::get<OffscreenUi>()->executeOnUiThread([=] {
|
||||
targetWindow->setVisible(visible);
|
||||
//emit visibilityChanged(visible);
|
||||
|
@ -282,7 +279,6 @@ bool QmlWindowClass::isVisible() const {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
glm::vec2 QmlWindowClass::getPosition() const {
|
||||
QQuickItem* targetWindow = asQuickItem();
|
||||
QVariant result = DependencyManager::get<OffscreenUi>()->returnFromUiThread([&]()->QVariant {
|
||||
|
|
|
@ -1,33 +1 @@
|
|||
|
||||
set(TARGET_NAME "ui-test")
|
||||
|
||||
# This is not a testcase -- just set it up as a regular hifi project
|
||||
setup_hifi_project(Network OpenGL Qml Quick Script WebChannel WebEngine WebSockets)
|
||||
|
||||
set_target_properties(${TARGET_NAME} PROPERTIES FOLDER "Tests/manual-tests/")
|
||||
|
||||
if (WIN32)
|
||||
target_link_libraries(${TARGET_NAME} wsock32.lib opengl32.lib Winmm.lib)
|
||||
# Issue causes build failure unless we add this directory.
|
||||
# See https://bugreports.qt.io/browse/QTBUG-43351
|
||||
add_paths_to_fixup_libs(${Qt5_DIR}/../../../plugins/qtwebengine)
|
||||
endif()
|
||||
|
||||
# link in the shared libraries
|
||||
link_hifi_libraries(shared networking gl gpu ui)
|
||||
|
||||
# copy the resources files beside the executable
|
||||
add_custom_command(TARGET ${TARGET_NAME} POST_BUILD
|
||||
COMMAND "${CMAKE_COMMAND}" -E copy_directory
|
||||
"${PROJECT_SOURCE_DIR}/qml"
|
||||
$<TARGET_FILE_DIR:${TARGET_NAME}>/qml
|
||||
)
|
||||
|
||||
|
||||
target_glew()
|
||||
|
||||
if (WIN32)
|
||||
set(EXTRA_DEPLOY_OPTIONS "--qmldir ${PROJECT_SOURCE_DIR}/../../interface/resources/qml")
|
||||
endif()
|
||||
|
||||
package_libraries_for_deployment()
|
||||
# This folder contains code for testing the QML UI using Qt Creator. It is not intended to be included in the CMake project
|
||||
|
|
734
tests/ui/qml/StubMenu.qml
Normal file
734
tests/ui/qml/StubMenu.qml
Normal file
|
@ -0,0 +1,734 @@
|
|||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.4
|
||||
|
||||
import "../../../interface/resources/qml/hifi"
|
||||
|
||||
Menu {
|
||||
property var menuOption: MenuOption {}
|
||||
Item {
|
||||
Action {
|
||||
id: login;
|
||||
text: menuOption.login
|
||||
}
|
||||
Action {
|
||||
id: update;
|
||||
text: "Update";
|
||||
enabled: false
|
||||
}
|
||||
Action {
|
||||
id: crashReporter;
|
||||
text: "Crash Reporter...";
|
||||
enabled: false
|
||||
}
|
||||
Action {
|
||||
id: help;
|
||||
text: menuOption.help
|
||||
onTriggered: Application.showHelp()
|
||||
}
|
||||
Action {
|
||||
id: aboutApp;
|
||||
text: menuOption.aboutApp
|
||||
}
|
||||
Action {
|
||||
id: quit;
|
||||
text: menuOption.quit
|
||||
}
|
||||
|
||||
ExclusiveGroup { id: renderResolutionGroup }
|
||||
Action {
|
||||
id: renderResolutionOne;
|
||||
exclusiveGroup: renderResolutionGroup;
|
||||
text: menuOption.renderResolutionOne;
|
||||
checkable: true;
|
||||
checked: true
|
||||
}
|
||||
Action {
|
||||
id: renderResolutionTwoThird;
|
||||
exclusiveGroup: renderResolutionGroup;
|
||||
text: menuOption.renderResolutionTwoThird;
|
||||
checkable: true
|
||||
}
|
||||
Action {
|
||||
id: renderResolutionHalf;
|
||||
exclusiveGroup: renderResolutionGroup;
|
||||
text: menuOption.renderResolutionHalf;
|
||||
checkable: true
|
||||
}
|
||||
Action {
|
||||
id: renderResolutionThird;
|
||||
exclusiveGroup: renderResolutionGroup;
|
||||
text: menuOption.renderResolutionThird;
|
||||
checkable: true
|
||||
}
|
||||
Action {
|
||||
id: renderResolutionQuarter;
|
||||
exclusiveGroup: renderResolutionGroup;
|
||||
text: menuOption.renderResolutionQuarter;
|
||||
checkable: true
|
||||
}
|
||||
|
||||
ExclusiveGroup { id: ambientLightGroup }
|
||||
Action {
|
||||
id: renderAmbientLightGlobal;
|
||||
exclusiveGroup: ambientLightGroup;
|
||||
text: menuOption.renderAmbientLightGlobal;
|
||||
checkable: true;
|
||||
checked: true
|
||||
}
|
||||
Action {
|
||||
id: renderAmbientLight0;
|
||||
exclusiveGroup: ambientLightGroup;
|
||||
text: menuOption.renderAmbientLight0;
|
||||
checkable: true;
|
||||
checked: true
|
||||
}
|
||||
Action {
|
||||
id: renderAmbientLight1;
|
||||
exclusiveGroup: ambientLightGroup;
|
||||
text: menuOption.renderAmbientLight1;
|
||||
checkable: true;
|
||||
checked: true
|
||||
}
|
||||
Action {
|
||||
id: renderAmbientLight2;
|
||||
exclusiveGroup: ambientLightGroup;
|
||||
text: menuOption.renderAmbientLight2;
|
||||
checkable: true;
|
||||
checked: true
|
||||
}
|
||||
Action {
|
||||
id: renderAmbientLight3;
|
||||
exclusiveGroup: ambientLightGroup;
|
||||
text: menuOption.renderAmbientLight3;
|
||||
checkable: true;
|
||||
checked: true
|
||||
}
|
||||
Action {
|
||||
id: renderAmbientLight4;
|
||||
exclusiveGroup: ambientLightGroup;
|
||||
text: menuOption.renderAmbientLight4;
|
||||
checkable: true;
|
||||
checked: true
|
||||
}
|
||||
Action {
|
||||
id: renderAmbientLight5;
|
||||
exclusiveGroup: ambientLightGroup;
|
||||
text: menuOption.renderAmbientLight5;
|
||||
checkable: true;
|
||||
checked: true
|
||||
}
|
||||
Action {
|
||||
id: renderAmbientLight6;
|
||||
exclusiveGroup: ambientLightGroup;
|
||||
text: menuOption.renderAmbientLight6;
|
||||
checkable: true;
|
||||
checked: true
|
||||
}
|
||||
Action {
|
||||
id: renderAmbientLight7;
|
||||
exclusiveGroup: ambientLightGroup;
|
||||
text: menuOption.renderAmbientLight7;
|
||||
checkable: true;
|
||||
checked: true
|
||||
}
|
||||
Action {
|
||||
id: renderAmbientLight8;
|
||||
exclusiveGroup: ambientLightGroup;
|
||||
text: menuOption.renderAmbientLight8;
|
||||
checkable: true;
|
||||
checked: true
|
||||
}
|
||||
Action {
|
||||
id: renderAmbientLight9;
|
||||
exclusiveGroup: ambientLightGroup;
|
||||
text: menuOption.renderAmbientLight9;
|
||||
checkable: true;
|
||||
checked: true
|
||||
}
|
||||
Action {
|
||||
id: preferences
|
||||
shortcut: StandardKey.Preferences
|
||||
text: menuOption.preferences
|
||||
onTriggered: dialogsManager.editPreferences()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Menu {
|
||||
title: "File"
|
||||
MenuItem {
|
||||
action: login
|
||||
}
|
||||
MenuItem {
|
||||
action: update
|
||||
}
|
||||
MenuItem {
|
||||
action: help
|
||||
}
|
||||
MenuItem {
|
||||
action: crashReporter
|
||||
}
|
||||
MenuItem {
|
||||
action: aboutApp
|
||||
}
|
||||
MenuItem {
|
||||
action: quit
|
||||
}
|
||||
}
|
||||
|
||||
Menu {
|
||||
title: "Edit"
|
||||
MenuItem {
|
||||
text: "Undo" }
|
||||
MenuItem {
|
||||
text: "Redo" }
|
||||
MenuItem {
|
||||
text: menuOption.runningScripts
|
||||
}
|
||||
MenuItem {
|
||||
text: menuOption.loadScript
|
||||
}
|
||||
MenuItem {
|
||||
text: menuOption.loadScriptURL
|
||||
}
|
||||
MenuItem {
|
||||
text: menuOption.stopAllScripts
|
||||
}
|
||||
MenuItem {
|
||||
text: menuOption.reloadAllScripts
|
||||
}
|
||||
MenuItem {
|
||||
text: menuOption.scriptEditor
|
||||
}
|
||||
MenuItem {
|
||||
text: menuOption.console_
|
||||
}
|
||||
MenuItem {
|
||||
text: menuOption.reloadContent
|
||||
}
|
||||
MenuItem {
|
||||
text: menuOption.packageModel
|
||||
}
|
||||
}
|
||||
|
||||
Menu {
|
||||
title: "Audio"
|
||||
MenuItem {
|
||||
text: menuOption.muteAudio;
|
||||
checkable: true
|
||||
}
|
||||
MenuItem {
|
||||
text: menuOption.audioTools;
|
||||
checkable: true
|
||||
}
|
||||
}
|
||||
Menu {
|
||||
title: "Avatar"
|
||||
// Avatar > Attachments...
|
||||
MenuItem {
|
||||
text: menuOption.attachments
|
||||
}
|
||||
Menu {
|
||||
title: "Size"
|
||||
// Avatar > Size > Increase
|
||||
MenuItem {
|
||||
text: menuOption.increaseAvatarSize
|
||||
}
|
||||
// Avatar > Size > Decrease
|
||||
MenuItem {
|
||||
text: menuOption.decreaseAvatarSize
|
||||
}
|
||||
// Avatar > Size > Reset
|
||||
MenuItem {
|
||||
text: menuOption.resetAvatarSize
|
||||
}
|
||||
}
|
||||
// Avatar > Reset Sensors
|
||||
MenuItem {
|
||||
text: menuOption.resetSensors
|
||||
}
|
||||
}
|
||||
Menu {
|
||||
title: "Display"
|
||||
}
|
||||
Menu {
|
||||
title: "View"
|
||||
ExclusiveGroup {
|
||||
id: cameraModeGroup
|
||||
}
|
||||
|
||||
MenuItem {
|
||||
text: menuOption.firstPerson;
|
||||
checkable: true;
|
||||
exclusiveGroup: cameraModeGroup
|
||||
}
|
||||
MenuItem {
|
||||
text: menuOption.thirdPerson;
|
||||
checkable: true;
|
||||
exclusiveGroup: cameraModeGroup
|
||||
}
|
||||
MenuItem {
|
||||
text: menuOption.fullscreenMirror;
|
||||
checkable: true;
|
||||
exclusiveGroup: cameraModeGroup
|
||||
}
|
||||
MenuItem {
|
||||
text: menuOption.independentMode;
|
||||
checkable: true;
|
||||
exclusiveGroup: cameraModeGroup
|
||||
}
|
||||
MenuItem {
|
||||
text: menuOption.cameraEntityMode;
|
||||
checkable: true;
|
||||
exclusiveGroup: cameraModeGroup
|
||||
}
|
||||
MenuSeparator{}
|
||||
MenuItem {
|
||||
text: menuOption.miniMirror;
|
||||
checkable: true
|
||||
}
|
||||
}
|
||||
Menu {
|
||||
title: "Navigate"
|
||||
MenuItem {
|
||||
text: "Home" }
|
||||
MenuItem {
|
||||
text: menuOption.addressBar
|
||||
}
|
||||
MenuItem {
|
||||
text: "Directory" }
|
||||
MenuItem {
|
||||
text: menuOption.copyAddress
|
||||
}
|
||||
MenuItem {
|
||||
text: menuOption.copyPath
|
||||
}
|
||||
}
|
||||
Menu {
|
||||
title: "Settings"
|
||||
MenuItem {
|
||||
text: "Advanced Menus" }
|
||||
MenuItem {
|
||||
text: "Developer Menus" }
|
||||
MenuItem {
|
||||
text: menuOption.preferences
|
||||
}
|
||||
MenuItem {
|
||||
text: "Avatar..." }
|
||||
MenuItem {
|
||||
text: "Audio..." }
|
||||
MenuItem {
|
||||
text: "LOD..." }
|
||||
MenuItem {
|
||||
text: menuOption.inputMenu
|
||||
}
|
||||
}
|
||||
Menu {
|
||||
title: "Developer"
|
||||
Menu {
|
||||
title: "Render"
|
||||
MenuItem {
|
||||
text: menuOption.atmosphere;
|
||||
checkable: true
|
||||
}
|
||||
MenuItem {
|
||||
text: menuOption.worldAxes;
|
||||
checkable: true
|
||||
}
|
||||
MenuItem {
|
||||
text: menuOption.debugAmbientOcclusion;
|
||||
checkable: true
|
||||
}
|
||||
MenuItem {
|
||||
text: menuOption.antialiasing;
|
||||
checkable: true
|
||||
}
|
||||
MenuItem {
|
||||
text: menuOption.stars;
|
||||
checkable: true
|
||||
}
|
||||
Menu {
|
||||
title: menuOption.renderAmbientLight
|
||||
MenuItem {
|
||||
action: renderAmbientLightGlobal; }
|
||||
MenuItem {
|
||||
action: renderAmbientLight0; }
|
||||
MenuItem {
|
||||
action: renderAmbientLight1; }
|
||||
MenuItem {
|
||||
action: renderAmbientLight2; }
|
||||
MenuItem {
|
||||
action: renderAmbientLight3; }
|
||||
MenuItem {
|
||||
action: renderAmbientLight4; }
|
||||
MenuItem {
|
||||
action: renderAmbientLight5; }
|
||||
MenuItem {
|
||||
action: renderAmbientLight6; }
|
||||
MenuItem {
|
||||
action: renderAmbientLight7; }
|
||||
MenuItem {
|
||||
action: renderAmbientLight8; }
|
||||
MenuItem {
|
||||
action: renderAmbientLight9; }
|
||||
}
|
||||
MenuItem {
|
||||
text: menuOption.throttleFPSIfNotFocus;
|
||||
checkable: true
|
||||
}
|
||||
Menu {
|
||||
title: menuOption.renderResolution
|
||||
MenuItem {
|
||||
action: renderResolutionOne
|
||||
}
|
||||
MenuItem {
|
||||
action: renderResolutionTwoThird
|
||||
}
|
||||
MenuItem {
|
||||
action: renderResolutionHalf
|
||||
}
|
||||
MenuItem {
|
||||
action: renderResolutionThird
|
||||
}
|
||||
MenuItem {
|
||||
action: renderResolutionQuarter
|
||||
}
|
||||
}
|
||||
MenuItem {
|
||||
text: menuOption.lodTools
|
||||
}
|
||||
}
|
||||
Menu {
|
||||
title: "Assets"
|
||||
MenuItem {
|
||||
text: menuOption.uploadAsset
|
||||
}
|
||||
MenuItem {
|
||||
text: menuOption.assetMigration
|
||||
}
|
||||
}
|
||||
Menu {
|
||||
title: "Avatar"
|
||||
Menu {
|
||||
title: "Face Tracking"
|
||||
MenuItem {
|
||||
text: menuOption.noFaceTracking;
|
||||
checkable: true
|
||||
}
|
||||
MenuItem {
|
||||
text: menuOption.faceshift;
|
||||
checkable: true
|
||||
}
|
||||
MenuItem {
|
||||
text: menuOption.useCamera;
|
||||
checkable: true
|
||||
}
|
||||
MenuSeparator{}
|
||||
MenuItem {
|
||||
text: menuOption.binaryEyelidControl;
|
||||
checkable: true
|
||||
}
|
||||
MenuItem {
|
||||
text: menuOption.coupleEyelids;
|
||||
checkable: true
|
||||
}
|
||||
MenuItem {
|
||||
text: menuOption.useAudioForMouth;
|
||||
checkable: true
|
||||
}
|
||||
MenuItem {
|
||||
text: menuOption.velocityFilter;
|
||||
checkable: true
|
||||
}
|
||||
MenuItem {
|
||||
text: menuOption.calibrateCamera
|
||||
}
|
||||
MenuSeparator{}
|
||||
MenuItem {
|
||||
text: menuOption.muteFaceTracking;
|
||||
checkable: true
|
||||
}
|
||||
MenuItem {
|
||||
text: menuOption.autoMuteAudio;
|
||||
checkable: true
|
||||
}
|
||||
}
|
||||
Menu {
|
||||
title: "Eye Tracking"
|
||||
MenuItem {
|
||||
text: menuOption.sMIEyeTracking;
|
||||
checkable: true
|
||||
}
|
||||
Menu {
|
||||
title: "Calibrate"
|
||||
MenuItem {
|
||||
text: menuOption.onePointCalibration
|
||||
}
|
||||
MenuItem {
|
||||
text: menuOption.threePointCalibration
|
||||
}
|
||||
MenuItem {
|
||||
text: menuOption.fivePointCalibration
|
||||
}
|
||||
}
|
||||
MenuItem {
|
||||
text: menuOption.simulateEyeTracking;
|
||||
checkable: true
|
||||
}
|
||||
}
|
||||
MenuItem {
|
||||
text: menuOption.avatarReceiveStats;
|
||||
checkable: true
|
||||
}
|
||||
MenuItem {
|
||||
text: menuOption.renderBoundingCollisionShapes;
|
||||
checkable: true
|
||||
}
|
||||
MenuItem {
|
||||
text: menuOption.renderLookAtVectors;
|
||||
checkable: true
|
||||
}
|
||||
MenuItem {
|
||||
text: menuOption.renderLookAtTargets;
|
||||
checkable: true
|
||||
}
|
||||
MenuItem {
|
||||
text: menuOption.renderFocusIndicator;
|
||||
checkable: true
|
||||
}
|
||||
MenuItem {
|
||||
text: menuOption.showWhosLookingAtMe;
|
||||
checkable: true
|
||||
}
|
||||
MenuItem {
|
||||
text: menuOption.fixGaze;
|
||||
checkable: true
|
||||
}
|
||||
MenuItem {
|
||||
text: menuOption.animDebugDrawDefaultPose;
|
||||
checkable: true
|
||||
}
|
||||
MenuItem {
|
||||
text: menuOption.animDebugDrawAnimPose;
|
||||
checkable: true
|
||||
}
|
||||
MenuItem {
|
||||
text: menuOption.animDebugDrawPosition;
|
||||
checkable: true
|
||||
}
|
||||
MenuItem {
|
||||
text: menuOption.meshVisible;
|
||||
checkable: true
|
||||
}
|
||||
MenuItem {
|
||||
text: menuOption.disableEyelidAdjustment;
|
||||
checkable: true
|
||||
}
|
||||
MenuItem {
|
||||
text: menuOption.turnWithHead;
|
||||
checkable: true
|
||||
}
|
||||
MenuItem {
|
||||
text: menuOption.comfortMode;
|
||||
checkable: true
|
||||
}
|
||||
MenuItem {
|
||||
text: menuOption.keyboardMotorControl;
|
||||
checkable: true
|
||||
}
|
||||
MenuItem {
|
||||
text: menuOption.scriptedMotorControl;
|
||||
checkable: true
|
||||
}
|
||||
MenuItem {
|
||||
text: menuOption.enableCharacterController;
|
||||
checkable: true
|
||||
}
|
||||
}
|
||||
Menu {
|
||||
title: "Hands"
|
||||
MenuItem {
|
||||
text: menuOption.displayHandTargets;
|
||||
checkable: true
|
||||
}
|
||||
MenuItem {
|
||||
text: menuOption.lowVelocityFilter;
|
||||
checkable: true
|
||||
}
|
||||
Menu {
|
||||
title: "Leap Motion"
|
||||
MenuItem {
|
||||
text: menuOption.leapMotionOnHMD;
|
||||
checkable: true
|
||||
}
|
||||
}
|
||||
}
|
||||
Menu {
|
||||
title: "Entities"
|
||||
MenuItem {
|
||||
text: menuOption.octreeStats
|
||||
}
|
||||
MenuItem {
|
||||
text: menuOption.showRealtimeEntityStats;
|
||||
checkable: true
|
||||
}
|
||||
}
|
||||
Menu {
|
||||
title: "Network"
|
||||
MenuItem {
|
||||
text: menuOption.reloadContent
|
||||
}
|
||||
MenuItem {
|
||||
text: menuOption.disableNackPackets;
|
||||
checkable: true
|
||||
}
|
||||
MenuItem {
|
||||
text: menuOption.disableActivityLogger;
|
||||
checkable: true
|
||||
}
|
||||
MenuItem {
|
||||
text: menuOption.cachesSize
|
||||
}
|
||||
MenuItem {
|
||||
text: menuOption.diskCacheEditor
|
||||
}
|
||||
MenuItem {
|
||||
text: menuOption.showDSConnectTable
|
||||
}
|
||||
MenuItem {
|
||||
text: menuOption.bandwidthDetails
|
||||
}
|
||||
}
|
||||
Menu {
|
||||
title: "Timing"
|
||||
Menu {
|
||||
title: "Performance Timer"
|
||||
MenuItem {
|
||||
text: menuOption.displayDebugTimingDetails;
|
||||
checkable: true
|
||||
}
|
||||
MenuItem {
|
||||
text: menuOption.onlyDisplayTopTen;
|
||||
checkable: true
|
||||
}
|
||||
MenuItem {
|
||||
text: menuOption.expandUpdateTiming;
|
||||
checkable: true
|
||||
}
|
||||
MenuItem {
|
||||
text: menuOption.expandMyAvatarTiming;
|
||||
checkable: true
|
||||
}
|
||||
MenuItem {
|
||||
text: menuOption.expandMyAvatarSimulateTiming;
|
||||
checkable: true
|
||||
}
|
||||
MenuItem {
|
||||
text: menuOption.expandOtherAvatarTiming;
|
||||
checkable: true
|
||||
}
|
||||
MenuItem {
|
||||
text: menuOption.expandPaintGLTiming;
|
||||
checkable: true
|
||||
}
|
||||
}
|
||||
MenuItem {
|
||||
text: menuOption.frameTimer;
|
||||
checkable: true
|
||||
}
|
||||
MenuItem {
|
||||
text: menuOption.runTimingTests
|
||||
}
|
||||
MenuItem {
|
||||
text: menuOption.pipelineWarnings;
|
||||
checkable: true
|
||||
}
|
||||
MenuItem {
|
||||
text: menuOption.logExtraTimings;
|
||||
checkable: true
|
||||
}
|
||||
MenuItem {
|
||||
text: menuOption.suppressShortTimings;
|
||||
checkable: true
|
||||
}
|
||||
}
|
||||
Menu {
|
||||
title: "Audio"
|
||||
MenuItem {
|
||||
text: menuOption.audioNoiseReduction;
|
||||
checkable: true
|
||||
}
|
||||
MenuItem {
|
||||
text: menuOption.echoServerAudio;
|
||||
checkable: true
|
||||
}
|
||||
MenuItem {
|
||||
text: menuOption.echoLocalAudio;
|
||||
checkable: true
|
||||
}
|
||||
MenuItem {
|
||||
text: menuOption.muteEnvironment
|
||||
}
|
||||
Menu {
|
||||
title: "Audio"
|
||||
MenuItem {
|
||||
text: menuOption.audioScope;
|
||||
checkable: true
|
||||
}
|
||||
MenuItem {
|
||||
text: menuOption.audioScopePause;
|
||||
checkable: true
|
||||
}
|
||||
Menu {
|
||||
title: "Display Frames"
|
||||
ExclusiveGroup {
|
||||
id: audioScopeFramesGroup
|
||||
}
|
||||
MenuItem {
|
||||
exclusiveGroup: audioScopeFramesGroup;
|
||||
text: menuOption.audioScopeFiveFrames;
|
||||
checkable: true
|
||||
}
|
||||
MenuItem {
|
||||
exclusiveGroup: audioScopeFramesGroup;
|
||||
text: menuOption.audioScopeTwentyFrames;
|
||||
checkable: true
|
||||
}
|
||||
MenuItem {
|
||||
exclusiveGroup: audioScopeFramesGroup;
|
||||
text: menuOption.audioScopeFiftyFrames;
|
||||
checkable: true
|
||||
}
|
||||
}
|
||||
MenuItem {
|
||||
text: menuOption.audioNetworkStats
|
||||
}
|
||||
}
|
||||
}
|
||||
Menu {
|
||||
title: "Physics"
|
||||
MenuItem {
|
||||
text: menuOption.physicsShowOwned;
|
||||
checkable: true
|
||||
}
|
||||
MenuItem {
|
||||
text: menuOption.physicsShowHulls;
|
||||
checkable: true
|
||||
}
|
||||
}
|
||||
MenuItem {
|
||||
text: menuOption.displayCrashOptions;
|
||||
checkable: true
|
||||
}
|
||||
MenuItem {
|
||||
text: menuOption.crashInterface
|
||||
}
|
||||
MenuItem {
|
||||
text: menuOption.log
|
||||
}
|
||||
MenuItem {
|
||||
text: menuOption.stats;
|
||||
checkable: true
|
||||
}
|
||||
}
|
||||
}
|
|
@ -20,7 +20,7 @@ Item {
|
|||
|
||||
Item {
|
||||
objectName: "ScriptDiscoveryService"
|
||||
property var scriptsModelFilter: scriptsModel
|
||||
//property var scriptsModelFilter: scriptsModel
|
||||
signal scriptCountChanged()
|
||||
property var _runningScripts:[
|
||||
{ name: "wireFrameTest.js", url: "foo/wireframetest.js", path: "foo/wireframetest.js", local: true },
|
||||
|
@ -106,7 +106,7 @@ Item {
|
|||
function closeDialog(item) {
|
||||
item = findDialog(item);
|
||||
if (item) {
|
||||
item.enabled = false
|
||||
item.visible = false
|
||||
} else {
|
||||
console.warn("Could not find top level dialog")
|
||||
}
|
|
@ -42,7 +42,6 @@ HifiControls.VrDialog {
|
|||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
enabled = true
|
||||
var xboxRegex = /^GamePad/;
|
||||
var hydraRegex = /^Hydra/;
|
||||
for (var prop in Controller.Hardware) {
|
336
tests/ui/qml/main.qml
Normal file
336
tests/ui/qml/main.qml
Normal file
|
@ -0,0 +1,336 @@
|
|||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.4
|
||||
import QtQuick.Dialogs 1.2 as OriginalDialogs
|
||||
import Qt.labs.settings 1.0
|
||||
|
||||
import "../../../interface/resources/qml"
|
||||
import "../../../interface/resources/qml/windows"
|
||||
import "../../../interface/resources/qml/dialogs"
|
||||
|
||||
ApplicationWindow {
|
||||
id: appWindow
|
||||
visible: true
|
||||
width: 1280
|
||||
height: 720
|
||||
title: qsTr("Scratch App")
|
||||
|
||||
Component { id: listModelBuilder; ListModel{} }
|
||||
|
||||
function menuItemsToModel(menu) {
|
||||
var items = menu.items
|
||||
var newListModel = listModelBuilder.createObject(desktop);
|
||||
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;
|
||||
}
|
||||
|
||||
Root {
|
||||
id: desktop
|
||||
anchors.fill: parent
|
||||
|
||||
StubMenu { id: stubMenu }
|
||||
|
||||
Row {
|
||||
id: testButtons
|
||||
anchors { margins: 8; left: parent.left; top: parent.top }
|
||||
spacing: 8
|
||||
property int count: 0
|
||||
|
||||
property var tabs: [];
|
||||
property var urls: [];
|
||||
Button {
|
||||
text: "restore all"
|
||||
onClicked: {
|
||||
for (var i = 0; i < desktop.windows.length; ++i) {
|
||||
desktop.windows[i].visible = true
|
||||
}
|
||||
}
|
||||
}
|
||||
Button {
|
||||
text: "toggle blue visible"
|
||||
onClicked: {
|
||||
blue.visible = !blue.visible
|
||||
}
|
||||
}
|
||||
Button {
|
||||
text: "toggle blue enabled"
|
||||
onClicked: {
|
||||
blue.enabled = !blue.enabled
|
||||
}
|
||||
}
|
||||
// Button {
|
||||
// text: "add web tab"
|
||||
// onClicked: {
|
||||
// testButtons.urls.push("http://slashdot.org?" + testButtons.count++);
|
||||
// testButtons.tabs.push(desktop.toolWindow.addWebTab({ title: "test", source: testButtons.urls[testButtons.urls.length - 1], width: 500, height: 720 }))
|
||||
// }
|
||||
// }
|
||||
// Button {
|
||||
// text: "toggle tab visible"
|
||||
// onClicked: {
|
||||
// var lastUrl = testButtons.urls[testButtons.urls.length - 1];
|
||||
// var tab = desktop.toolWindow.findTabForUrl(lastUrl);
|
||||
// desktop.toolWindow.showTabForUrl(lastUrl, !tab.enabled)
|
||||
// }
|
||||
// }
|
||||
// Button {
|
||||
// text: "Remove last tab"
|
||||
// onClicked: {
|
||||
// testButtons.tabs.pop();
|
||||
// desktop.toolWindow.removeTabForUrl(testButtons.urls.pop());
|
||||
// }
|
||||
// }
|
||||
Button {
|
||||
text: "Show Long Error"
|
||||
onClicked: {
|
||||
desktop.messageBox({
|
||||
informativeText: "Diagnostic cycle will be complete in 30 seconds Diagnostic cycle will be complete in 30 seconds Diagnostic cycle will be complete in 30 seconds Diagnostic cycle will be complete in 30 seconds Diagnostic cycle will be complete in 30 seconds Diagnostic cycle will be complete in 30 seconds Diagnostic cycle will be complete in 30 seconds Diagnostic cycle will be complete in 30 seconds ",
|
||||
text: "Baloney",
|
||||
icon: OriginalDialogs.StandardIcon.Warning,
|
||||
detailedText: "sakjd;laskj dksa;dl jka;lsd j;lkjas ;dlkaj s;dlakjd ;alkjda; slkjda; lkjda;lksjd ;alksjd; alksjd ;alksjd; alksjd; alksdjas;ldkjas;lkdja ;kj ;lkasjd; lkj as;dlka jsd;lka jsd;laksjd a"
|
||||
});
|
||||
}
|
||||
}
|
||||
Button {
|
||||
text: "Show Error"
|
||||
onClicked: {
|
||||
desktop.messageBox({
|
||||
text: "Diagnostic cycle will be complete in 30 seconds",
|
||||
icon: OriginalDialogs.StandardIcon.Critical,
|
||||
});
|
||||
}
|
||||
}
|
||||
Button {
|
||||
text: "Open File"
|
||||
property var builder: Component {
|
||||
FileDialog { }
|
||||
}
|
||||
|
||||
ListModel {
|
||||
id: jsFilters
|
||||
ListElement { text: "Javascript Files (*.js)"; filter: "*.js" }
|
||||
ListElement { text: "All Files (*.*)"; filter: "*.*" }
|
||||
}
|
||||
onClicked: {
|
||||
var fileDialogProperties = {
|
||||
filterModel: jsFilters
|
||||
}
|
||||
var fileDialog = builder.createObject(desktop, fileDialogProperties);
|
||||
fileDialog.canceled.connect(function(){
|
||||
console.log("Cancelled")
|
||||
})
|
||||
fileDialog.selectedFile.connect(function(file){
|
||||
console.log("Selected " + file)
|
||||
})
|
||||
}
|
||||
}
|
||||
Button {
|
||||
text: "Focus Test"
|
||||
onClicked: {
|
||||
var item = desktop;
|
||||
while (item) {
|
||||
console.log(item);
|
||||
item = item.parent;
|
||||
}
|
||||
item = appWindow
|
||||
while (item) {
|
||||
console.log(item);
|
||||
item = item.parent;
|
||||
}
|
||||
console.log(appWindow.activeFocusItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Window {
|
||||
id: blue
|
||||
closable: true
|
||||
visible: true
|
||||
resizable: true
|
||||
destroyOnInvisible: false
|
||||
|
||||
width: 100; height: 100
|
||||
x: 1280 / 2; y: 720 / 2
|
||||
Settings {
|
||||
category: "TestWindow.Blue"
|
||||
property alias x: blue.x
|
||||
property alias y: blue.y
|
||||
property alias width: blue.width
|
||||
property alias height: blue.height
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
visible: true
|
||||
color: "blue"
|
||||
Component.onDestruction: console.log("Blue destroyed")
|
||||
}
|
||||
}
|
||||
|
||||
Window {
|
||||
id: green
|
||||
alwaysOnTop: true
|
||||
closable: true
|
||||
visible: true
|
||||
resizable: false
|
||||
x: 1280 / 2; y: 720 / 2
|
||||
Settings {
|
||||
category: "TestWindow.Green"
|
||||
property alias x: green.x
|
||||
property alias y: green.y
|
||||
property alias width: green.width
|
||||
property alias height: green.height
|
||||
}
|
||||
width: 100; height: 100
|
||||
Rectangle { anchors.fill: parent; color: "green" }
|
||||
}
|
||||
|
||||
Window {
|
||||
id: yellow
|
||||
closable: true
|
||||
visible: true
|
||||
resizable: true
|
||||
width: 100; height: 100
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
visible: true
|
||||
color: "yellow"
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
acceptedButtons: Qt.RightButton
|
||||
|
||||
Component {
|
||||
id: menuBuilder
|
||||
VrMenuView { }
|
||||
}
|
||||
|
||||
onClicked: {
|
||||
console.log("zzz")
|
||||
var menuItems = menuItemsToModel(stubMenu);
|
||||
var newMenu = menuBuilder.createObject(desktop, { source: stubMenu, items: menuItems });
|
||||
newMenu.x = mouseX
|
||||
newMenu.y = mouseY
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Arcane.Test {
|
||||
anchors.centerIn: parent
|
||||
height: 600; width: 600
|
||||
}
|
||||
|
||||
|
||||
Item {
|
||||
id: desktop
|
||||
anchors.fill: parent
|
||||
objectName: Desktop._OFFSCREEN_ROOT_OBJECT_NAME
|
||||
property bool uiVisible: true
|
||||
property variant toolbars: { "_root" : null }
|
||||
focus: true
|
||||
|
||||
|
||||
|
||||
Rectangle {
|
||||
id: root
|
||||
Vr.Constants { id: vr }
|
||||
implicitWidth: 384; implicitHeight: 640
|
||||
anchors.centerIn: parent
|
||||
color: vr.windows.colors.background
|
||||
border.color: vr.controls.colors.background
|
||||
border.width: vr.styles.borderWidth
|
||||
radius: vr.styles.borderRadius
|
||||
RunningScripts { }
|
||||
}
|
||||
|
||||
FileDialog {
|
||||
id: fileDialog
|
||||
width: 800; height: 600
|
||||
anchors.centerIn: parent
|
||||
onSelectedFile: console.log("Chose file " + file)
|
||||
}
|
||||
Timer {
|
||||
id: timer
|
||||
running: false
|
||||
interval: 100
|
||||
onTriggered: wireFrameContainer.enabled = true
|
||||
}
|
||||
|
||||
Item {
|
||||
id: wireFrameContainer
|
||||
objectName: Desktop._OFFSCREEN_DIALOG_OBJECT_NAME
|
||||
anchors.fill: parent
|
||||
onEnabledChanged: if (!enabled) timer.running = true
|
||||
|
||||
NewUi.Main {
|
||||
id: wireFrame
|
||||
anchors.fill: parent
|
||||
|
||||
property var offscreenFlags: Item {
|
||||
property bool navigationFocused: false
|
||||
}
|
||||
|
||||
property var urlHandler: Item {
|
||||
function fixupUrl(url) {
|
||||
var urlString = url.toString();
|
||||
if (urlString.indexOf("https://metaverse.highfidelity.com/") !== -1 &&
|
||||
urlString.indexOf("access_token") === -1) {
|
||||
console.log("metaverse URL, fixing")
|
||||
return urlString + "?access_token=875885020b1d5f1ea694ce971c8601fa33ffd77f61851be01ed1e3fde8cabbe9"
|
||||
}
|
||||
return url
|
||||
}
|
||||
|
||||
function canHandleUrl(url) {
|
||||
var urlString = url.toString();
|
||||
if (urlString.indexOf("hifi://") === 0) {
|
||||
console.log("Can handle hifi addresses: " + urlString)
|
||||
return true;
|
||||
}
|
||||
|
||||
if (urlString.indexOf(".svo.json?") !== -1) {
|
||||
console.log("Can handle svo json addresses: " + urlString)
|
||||
return true;
|
||||
}
|
||||
|
||||
if (urlString.indexOf(".js?") !== -1) {
|
||||
console.log("Can handle javascript addresses: " + urlString)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
function handleUrl(url) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
property var addressManager: Item {
|
||||
function navigate(url) {
|
||||
console.log("Navigate to: " + url);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Keys.onMenuPressed: desktop.uiVisible = !desktop.uiVisible
|
||||
Keys.onEscapePressed: desktop.uiVisible = !desktop.uiVisible
|
||||
}
|
||||
*/
|
||||
}
|
84
tests/ui/qmlscratch.pro
Normal file
84
tests/ui/qmlscratch.pro
Normal file
|
@ -0,0 +1,84 @@
|
|||
TEMPLATE = app
|
||||
|
||||
QT += gui qml quick xml webengine widgets
|
||||
|
||||
CONFIG += c++11
|
||||
|
||||
SOURCES += src/main.cpp
|
||||
|
||||
# Additional import path used to resolve QML modules in Qt Creator's code model
|
||||
QML_IMPORT_PATH =
|
||||
|
||||
DISTFILES += \
|
||||
qml/UI.js \
|
||||
qml/main.qml \
|
||||
qml/Palettes.qml \
|
||||
qml/StubMenu.qml \
|
||||
qml/Stubs.qml \
|
||||
qml/TestControllers.qml \
|
||||
qml/TestDialog.qml \
|
||||
qml/TestMenu.qml \
|
||||
qml/TestRoot.qml \
|
||||
qml/controlDemo/ButtonPage.qml \
|
||||
qml/controlDemo/InputPage.qml \
|
||||
qml/controlDemo/main.qml \
|
||||
qml/controlDemo/ProgressPage.qml \
|
||||
../../interface/resources/qml/controller/hydra/HydraButtons.qml \
|
||||
../../interface/resources/qml/controller/hydra/HydraStick.qml \
|
||||
../../interface/resources/qml/controller/xbox/DPad.qml \
|
||||
../../interface/resources/qml/controller/xbox/LeftAnalogStick.qml \
|
||||
../../interface/resources/qml/controller/xbox/RightAnalogStick.qml \
|
||||
../../interface/resources/qml/controller/xbox/XboxButtons.qml \
|
||||
../../interface/resources/qml/controller/AnalogButton.qml \
|
||||
../../interface/resources/qml/controller/AnalogStick.qml \
|
||||
../../interface/resources/qml/controller/Hydra.qml \
|
||||
../../interface/resources/qml/controller/Standard.qml \
|
||||
../../interface/resources/qml/controller/ToggleButton.qml \
|
||||
../../interface/resources/qml/controller/Xbox.qml \
|
||||
../../interface/resources/qml/controls/Button.qml \
|
||||
../../interface/resources/qml/controls/ButtonAwesome.qml \
|
||||
../../interface/resources/qml/controls/CheckBox.qml \
|
||||
../../interface/resources/qml/controls/FontAwesome.qml \
|
||||
../../interface/resources/qml/controls/Player.qml \
|
||||
../../interface/resources/qml/controls/Slider.qml \
|
||||
../../interface/resources/qml/controls/Spacer.qml \
|
||||
../../interface/resources/qml/controls/SpinBox.qml \
|
||||
../../interface/resources/qml/controls/Text.qml \
|
||||
../../interface/resources/qml/controls/TextAndSlider.qml \
|
||||
../../interface/resources/qml/controls/TextAndSpinBox.qml \
|
||||
../../interface/resources/qml/controls/TextArea.qml \
|
||||
../../interface/resources/qml/controls/TextEdit.qml \
|
||||
../../interface/resources/qml/controls/TextHeader.qml \
|
||||
../../interface/resources/qml/controls/TextInput.qml \
|
||||
../../interface/resources/qml/controls/TextInputAndButton.qml \
|
||||
../../interface/resources/qml/controls/WebView.qml \
|
||||
../../interface/resources/qml/dialogs/FileDialog.qml \
|
||||
../../interface/resources/qml/dialogs/MessageDialog.qml \
|
||||
../../interface/resources/qml/dialogs/RunningScripts.qml \
|
||||
../../interface/resources/qml/hifi/MenuOption.qml \
|
||||
../../interface/resources/qml/styles/Border.qml \
|
||||
../../interface/resources/qml/styles/HifiConstants.qml \
|
||||
../../interface/resources/qml/windows/DefaultFrame.qml \
|
||||
../../interface/resources/qml/windows/Fadable.qml \
|
||||
../../interface/resources/qml/windows/Frame.qml \
|
||||
../../interface/resources/qml/windows/ModalFrame.qml \
|
||||
../../interface/resources/qml/windows/Window.qml \
|
||||
../../interface/resources/qml/AddressBarDialog.qml \
|
||||
../../interface/resources/qml/AvatarInputs.qml \
|
||||
../../interface/resources/qml/Browser.qml \
|
||||
../../interface/resources/qml/InfoView.qml \
|
||||
../../interface/resources/qml/LoginDialog.qml \
|
||||
../../interface/resources/qml/QmlWebWindow.qml \
|
||||
../../interface/resources/qml/QmlWindow.qml \
|
||||
../../interface/resources/qml/Root.qml \
|
||||
../../interface/resources/qml/ScrollingGraph.qml \
|
||||
../../interface/resources/qml/Stats.qml \
|
||||
../../interface/resources/qml/TextOverlayElement.qml \
|
||||
../../interface/resources/qml/Tooltip.qml \
|
||||
../../interface/resources/qml/ToolWindow.qml \
|
||||
../../interface/resources/qml/UpdateDialog.qml \
|
||||
../../interface/resources/qml/VrMenu.qml \
|
||||
../../interface/resources/qml/VrMenuItem.qml \
|
||||
../../interface/resources/qml/VrMenuView.qml \
|
||||
../../interface/resources/qml/WebEntity.qml
|
||||
|
|
@ -1,645 +1,65 @@
|
|||
//
|
||||
// Created by Bradley Austin Davis on 2015-04-22
|
||||
// Copyright 2013-2015 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
|
||||
//
|
||||
#include <QApplication>
|
||||
#include <QQmlApplicationEngine>
|
||||
#include <QtWebEngine>
|
||||
#include <QFileSystemModel>
|
||||
|
||||
#include <gl/Config.h>
|
||||
#include <gl/OglplusHelpers.h>
|
||||
#include <gl/GLHelpers.h>
|
||||
#include <memory>
|
||||
|
||||
#include <QtCore/QFile>
|
||||
#include <QtCore/QDir>
|
||||
#include <QtCore/QTime>
|
||||
#include <QtCore/QTimer>
|
||||
#include <QtCore/QElapsedTimer>
|
||||
#include <QtCore/QLoggingCategory>
|
||||
#include <QtCore/QThread>
|
||||
#include <QtCore/QUuid>
|
||||
|
||||
#include <QtGui/QWindow>
|
||||
#include <QtGui/QImage>
|
||||
#include <QtGui/QGuiApplication>
|
||||
#include <QtGui/QResizeEvent>
|
||||
#include <QtGui/QScreen>
|
||||
|
||||
#include <gl/QOpenGLContextWrapper.h>
|
||||
|
||||
#include <QtScript/QScriptEngine>
|
||||
|
||||
#include <QtQml/QQmlContext>
|
||||
#include <QtQml/QQmlApplicationEngine>
|
||||
|
||||
#include <GLMHelpers.h>
|
||||
#include <gl/OffscreenGLCanvas.h>
|
||||
#include <OffscreenUi.h>
|
||||
#include <PathUtils.h>
|
||||
#include <PathUtils.h>
|
||||
#include <MessageDialog.h>
|
||||
#include <VrMenu.h>
|
||||
#include <InfoView.h>
|
||||
#include <QmlWebWindowClass.h>
|
||||
#include <RegisteredMetaTypes.h>
|
||||
|
||||
const QString& getResourcesDir() {
|
||||
static QString dir;
|
||||
if (dir.isEmpty()) {
|
||||
QDir path(__FILE__);
|
||||
path.cdUp();
|
||||
dir = path.cleanPath(path.absoluteFilePath("../../../interface/resources/")) + "/";
|
||||
qDebug() << "Resources Path: " << dir;
|
||||
}
|
||||
return dir;
|
||||
QString getRelativeDir(const QString& relativePath = ".") {
|
||||
QDir path(__FILE__); path.cdUp();
|
||||
auto result = path.absoluteFilePath(relativePath);
|
||||
result = path.cleanPath(result) + "/";
|
||||
return result;
|
||||
}
|
||||
|
||||
const QString& getExamplesDir() {
|
||||
static QString dir;
|
||||
if (dir.isEmpty()) {
|
||||
QDir path(__FILE__);
|
||||
path.cdUp();
|
||||
dir = path.cleanPath(path.absoluteFilePath("../../../examples/")) + "/";
|
||||
qDebug() << "Resources Path: " << dir;
|
||||
}
|
||||
return dir;
|
||||
QString getTestQmlDir() {
|
||||
return getRelativeDir("../qml");
|
||||
}
|
||||
|
||||
const QString& getInterfaceQmlDir() {
|
||||
static QString dir;
|
||||
if (dir.isEmpty()) {
|
||||
dir = getResourcesDir() + "qml/";
|
||||
qDebug() << "Qml Path: " << dir;
|
||||
}
|
||||
return dir;
|
||||
}
|
||||
|
||||
const QString& getTestQmlDir() {
|
||||
static QString dir;
|
||||
if (dir.isEmpty()) {
|
||||
QDir path(__FILE__);
|
||||
path.cdUp();
|
||||
dir = path.cleanPath(path.absoluteFilePath("../")) + "/";
|
||||
qDebug() << "Qml Test Path: " << dir;
|
||||
}
|
||||
return dir;
|
||||
QString getInterfaceQmlDir() {
|
||||
return getRelativeDir("/");
|
||||
}
|
||||
|
||||
|
||||
class RateCounter {
|
||||
std::vector<float> times;
|
||||
QElapsedTimer timer;
|
||||
public:
|
||||
RateCounter() {
|
||||
timer.start();
|
||||
void setChild(QQmlApplicationEngine& engine, const char* name) {
|
||||
for (auto obj : engine.rootObjects()) {
|
||||
auto child = obj->findChild<QObject*>(QString(name));
|
||||
if (child) {
|
||||
engine.rootContext()->setContextProperty(name, child);
|
||||
return;
|
||||
}
|
||||
|
||||
void reset() {
|
||||
times.clear();
|
||||
}
|
||||
|
||||
size_t count() const {
|
||||
return times.size() - 1;
|
||||
}
|
||||
|
||||
float elapsed() const {
|
||||
if (times.size() < 1) {
|
||||
return 0.0f;
|
||||
}
|
||||
float elapsed = *times.rbegin() - *times.begin();
|
||||
return elapsed;
|
||||
}
|
||||
|
||||
void increment() {
|
||||
times.push_back(timer.elapsed() / 1000.0f);
|
||||
}
|
||||
|
||||
float rate() const {
|
||||
if (elapsed() == 0.0f) {
|
||||
return 0.0f;
|
||||
}
|
||||
return (float) count() / elapsed();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
extern QOpenGLContext* qt_gl_global_share_context();
|
||||
|
||||
|
||||
static bool hadUncaughtExceptions(QScriptEngine& engine, const QString& fileName) {
|
||||
if (engine.hasUncaughtException()) {
|
||||
const auto backtrace = engine.uncaughtExceptionBacktrace();
|
||||
const auto exception = engine.uncaughtException().toString();
|
||||
const auto line = QString::number(engine.uncaughtExceptionLineNumber());
|
||||
engine.clearExceptions();
|
||||
|
||||
auto message = QString("[UncaughtException] %1 in %2:%3").arg(exception, fileName, line);
|
||||
if (!backtrace.empty()) {
|
||||
static const auto lineSeparator = "\n ";
|
||||
message += QString("\n[Backtrace]%1%2").arg(lineSeparator, backtrace.join(lineSeparator));
|
||||
}
|
||||
qWarning() << qPrintable(message);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
qWarning() << "Could not find object named " << name;
|
||||
}
|
||||
|
||||
const unsigned int SCRIPT_DATA_CALLBACK_USECS = floor(((1.0f / 60.0f) * 1000 * 1000) + 0.5f);
|
||||
|
||||
static QScriptValue debugPrint(QScriptContext* context, QScriptEngine* engine) {
|
||||
QString message = "";
|
||||
for (int i = 0; i < context->argumentCount(); i++) {
|
||||
if (i > 0) {
|
||||
message += " ";
|
||||
}
|
||||
message += context->argument(i).toString();
|
||||
}
|
||||
qDebug().noquote() << "script:print()<<" << message; // noquote() so that \n is treated as newline
|
||||
|
||||
message = message.replace("\\", "\\\\")
|
||||
.replace("\n", "\\n")
|
||||
.replace("\r", "\\r")
|
||||
.replace("'", "\\'");
|
||||
engine->evaluate("Script.print('" + message + "')");
|
||||
|
||||
return QScriptValue();
|
||||
void addImportPath(QQmlApplicationEngine& engine, const QString& relativePath) {
|
||||
QString resolvedPath = getRelativeDir("../qml");
|
||||
QUrl resolvedUrl = QUrl::fromLocalFile(resolvedPath);
|
||||
resolvedPath = resolvedUrl.toString();
|
||||
engine.addImportPath(resolvedPath);
|
||||
}
|
||||
|
||||
class ScriptEngine : public QScriptEngine {
|
||||
Q_OBJECT
|
||||
int main(int argc, char *argv[]) {
|
||||
QApplication app(argc, argv);
|
||||
app.setOrganizationName("Some Company");
|
||||
app.setOrganizationDomain("somecompany.com");
|
||||
app.setApplicationName("Amazing Application");
|
||||
QDir::setCurrent(getRelativeDir(".."));
|
||||
|
||||
public:
|
||||
void loadFile(const QString& scriptPath) {
|
||||
if (_isRunning) {
|
||||
return;
|
||||
}
|
||||
qDebug() << "Loading script from " << scriptPath;
|
||||
_fileNameString = scriptPath;
|
||||
QtWebEngine::initialize();
|
||||
|
||||
QFile file(scriptPath);
|
||||
if (file.exists()) {
|
||||
file.open(QIODevice::ReadOnly);
|
||||
_scriptContents = file.readAll();
|
||||
} else {
|
||||
qFatal("Missing file ");
|
||||
}
|
||||
runInThread();
|
||||
}
|
||||
QQmlApplicationEngine engine;
|
||||
addImportPath(engine, "../qml");
|
||||
addImportPath(engine, "../../../interface/resources/qml");
|
||||
engine.load(QUrl(QStringLiteral("qml/Stubs.qml")));
|
||||
|
||||
Q_INVOKABLE void stop() {
|
||||
if (!_isFinished) {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QMetaObject::invokeMethod(this, "stop");
|
||||
return;
|
||||
}
|
||||
_isFinished = true;
|
||||
if (_wantSignals) {
|
||||
emit runningStateChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
setChild(engine, "rootMenu");
|
||||
setChild(engine, "Account");
|
||||
setChild(engine, "Desktop");
|
||||
setChild(engine, "ScriptDiscoveryService");
|
||||
setChild(engine, "MenuHelper");
|
||||
setChild(engine, "urlHandler");
|
||||
engine.rootContext()->setContextProperty("DebugQML", true);
|
||||
|
||||
Q_INVOKABLE void print(const QString& message) {
|
||||
if (_wantSignals) {
|
||||
emit printedMessage(message);
|
||||
}
|
||||
}
|
||||
|
||||
Q_INVOKABLE QObject* setupTimerWithInterval(const QScriptValue& function, int intervalMS, bool isSingleShot) {
|
||||
// create the timer, add it to the map, and start it
|
||||
QTimer* newTimer = new QTimer(this);
|
||||
newTimer->setSingleShot(isSingleShot);
|
||||
|
||||
connect(newTimer, &QTimer::timeout, this, &ScriptEngine::timerFired);
|
||||
|
||||
// make sure the timer stops when the script does
|
||||
connect(this, &ScriptEngine::scriptEnding, newTimer, &QTimer::stop);
|
||||
|
||||
_timerFunctionMap.insert(newTimer, function);
|
||||
|
||||
newTimer->start(intervalMS);
|
||||
return newTimer;
|
||||
}
|
||||
|
||||
Q_INVOKABLE QObject* setInterval(const QScriptValue& function, int intervalMS) {
|
||||
return setupTimerWithInterval(function, intervalMS, false);
|
||||
}
|
||||
|
||||
Q_INVOKABLE QObject* setTimeout(const QScriptValue& function, int timeoutMS) {
|
||||
return setupTimerWithInterval(function, timeoutMS, true);
|
||||
}
|
||||
private:
|
||||
|
||||
void runInThread() {
|
||||
QThread* workerThread = new QThread();
|
||||
connect(workerThread, &QThread::finished, workerThread, &QThread::deleteLater);
|
||||
connect(workerThread, &QThread::started, this, &ScriptEngine::run);
|
||||
connect(workerThread, &QThread::finished, this, &ScriptEngine::deleteLater);
|
||||
connect(this, &ScriptEngine::doneRunning, workerThread, &QThread::quit);
|
||||
moveToThread(workerThread);
|
||||
workerThread->start();
|
||||
}
|
||||
|
||||
void init() {
|
||||
_isInitialized = true;
|
||||
registerMetaTypes(this);
|
||||
registerGlobalObject("Script", this);
|
||||
qScriptRegisterSequenceMetaType<QVector<QUuid>>(this);
|
||||
qScriptRegisterSequenceMetaType<QVector<QString>>(this);
|
||||
globalObject().setProperty("OverlayWebWindow", newFunction(QmlWebWindowClass::constructor));
|
||||
QScriptValue printConstructorValue = newFunction(debugPrint);
|
||||
globalObject().setProperty("print", printConstructorValue);
|
||||
}
|
||||
|
||||
void timerFired() {
|
||||
QTimer* callingTimer = reinterpret_cast<QTimer*>(sender());
|
||||
QScriptValue timerFunction = _timerFunctionMap.value(callingTimer);
|
||||
|
||||
if (!callingTimer->isActive()) {
|
||||
// this timer is done, we can kill it
|
||||
_timerFunctionMap.remove(callingTimer);
|
||||
delete callingTimer;
|
||||
}
|
||||
|
||||
// call the associated JS function, if it exists
|
||||
if (timerFunction.isValid()) {
|
||||
timerFunction.call();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void run() {
|
||||
if (!_isInitialized) {
|
||||
init();
|
||||
}
|
||||
|
||||
_isRunning = true;
|
||||
if (_wantSignals) {
|
||||
emit runningStateChanged();
|
||||
}
|
||||
|
||||
QScriptValue result = evaluate(_scriptContents, _fileNameString);
|
||||
QElapsedTimer startTime;
|
||||
startTime.start();
|
||||
|
||||
int thisFrame = 0;
|
||||
|
||||
qint64 lastUpdate = usecTimestampNow();
|
||||
|
||||
while (!_isFinished) {
|
||||
int usecToSleep = (thisFrame++ * SCRIPT_DATA_CALLBACK_USECS) - startTime.nsecsElapsed() / 1000; // nsec to usec
|
||||
if (usecToSleep > 0) {
|
||||
usleep(usecToSleep);
|
||||
}
|
||||
|
||||
if (_isFinished) {
|
||||
break;
|
||||
}
|
||||
|
||||
QCoreApplication::processEvents();
|
||||
if (_isFinished) {
|
||||
break;
|
||||
}
|
||||
|
||||
qint64 now = usecTimestampNow();
|
||||
float deltaTime = (float)(now - lastUpdate) / (float)USECS_PER_SECOND;
|
||||
if (!_isFinished) {
|
||||
if (_wantSignals) {
|
||||
emit update(deltaTime);
|
||||
}
|
||||
}
|
||||
lastUpdate = now;
|
||||
|
||||
// Debug and clear exceptions
|
||||
hadUncaughtExceptions(*this, _fileNameString);
|
||||
}
|
||||
|
||||
if (_wantSignals) {
|
||||
emit scriptEnding();
|
||||
}
|
||||
|
||||
if (_wantSignals) {
|
||||
emit finished(_fileNameString, this);
|
||||
}
|
||||
|
||||
_isRunning = false;
|
||||
|
||||
if (_wantSignals) {
|
||||
emit runningStateChanged();
|
||||
emit doneRunning();
|
||||
}
|
||||
}
|
||||
|
||||
void registerGlobalObject(const QString& name, QObject* object) {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QMetaObject::invokeMethod(this, "registerGlobalObject",
|
||||
Q_ARG(const QString&, name),
|
||||
Q_ARG(QObject*, object));
|
||||
return;
|
||||
}
|
||||
if (!globalObject().property(name).isValid()) {
|
||||
if (object) {
|
||||
QScriptValue value = newQObject(object);
|
||||
globalObject().setProperty(name, value);
|
||||
} else {
|
||||
globalObject().setProperty(name, QScriptValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void registerFunction(const QString& name, QScriptEngine::FunctionSignature functionSignature, int numArguments) {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QMetaObject::invokeMethod(this, "registerFunction",
|
||||
Q_ARG(const QString&, name),
|
||||
Q_ARG(QScriptEngine::FunctionSignature, functionSignature),
|
||||
Q_ARG(int, numArguments));
|
||||
return;
|
||||
}
|
||||
QScriptValue scriptFun = newFunction(functionSignature, numArguments);
|
||||
globalObject().setProperty(name, scriptFun);
|
||||
}
|
||||
|
||||
void registerFunction(const QString& parent, const QString& name, QScriptEngine::FunctionSignature functionSignature, int numArguments) {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QMetaObject::invokeMethod(this, "registerFunction",
|
||||
Q_ARG(const QString&, name),
|
||||
Q_ARG(QScriptEngine::FunctionSignature, functionSignature),
|
||||
Q_ARG(int, numArguments));
|
||||
return;
|
||||
}
|
||||
|
||||
QScriptValue object = globalObject().property(parent);
|
||||
if (object.isValid()) {
|
||||
QScriptValue scriptFun = newFunction(functionSignature, numArguments);
|
||||
object.setProperty(name, scriptFun);
|
||||
}
|
||||
}
|
||||
|
||||
signals:
|
||||
void scriptLoaded(const QString& scriptFilename);
|
||||
void errorLoadingScript(const QString& scriptFilename);
|
||||
void update(float deltaTime);
|
||||
void scriptEnding();
|
||||
void finished(const QString& fileNameString, ScriptEngine* engine);
|
||||
void cleanupMenuItem(const QString& menuItemString);
|
||||
void printedMessage(const QString& message);
|
||||
void errorMessage(const QString& message);
|
||||
void runningStateChanged();
|
||||
void evaluationFinished(QScriptValue result, bool isException);
|
||||
void loadScript(const QString& scriptName, bool isUserLoaded);
|
||||
void reloadScript(const QString& scriptName, bool isUserLoaded);
|
||||
void doneRunning();
|
||||
|
||||
|
||||
private:
|
||||
QString _scriptContents;
|
||||
QString _fileNameString;
|
||||
QString _parentURL;
|
||||
bool _isInitialized { false };
|
||||
std::atomic<bool> _isFinished { false };
|
||||
std::atomic<bool> _isRunning { false };
|
||||
bool _wantSignals { true };
|
||||
QHash<QTimer*, QScriptValue> _timerFunctionMap;
|
||||
};
|
||||
|
||||
|
||||
|
||||
ScriptEngine* loadScript(const QString& scriptFilename) {
|
||||
ScriptEngine* scriptEngine = new ScriptEngine();
|
||||
scriptEngine->loadFile(scriptFilename);
|
||||
return scriptEngine;
|
||||
//engine.load(QUrl(QStringLiteral("qrc:/qml/gallery/main.qml")));
|
||||
engine.load(QUrl(QStringLiteral("qml/main.qml")));
|
||||
return app.exec();
|
||||
}
|
||||
|
||||
OffscreenGLCanvas* _chromiumShareContext { nullptr };
|
||||
Q_GUI_EXPORT void qt_gl_set_global_share_context(QOpenGLContext *context);
|
||||
|
||||
|
||||
// Create a simple OpenGL window that renders text in various ways
|
||||
class QTestWindow : public QWindow {
|
||||
Q_OBJECT
|
||||
|
||||
QOpenGLContextWrapper* _context{ nullptr };
|
||||
QSize _size;
|
||||
bool _altPressed{ false };
|
||||
RateCounter fps;
|
||||
QTimer _timer;
|
||||
int testQmlTexture{ 0 };
|
||||
ProgramPtr _program;
|
||||
ShapeWrapperPtr _plane;
|
||||
QScriptEngine* _scriptEngine { nullptr };
|
||||
|
||||
public:
|
||||
QObject* rootMenu;
|
||||
|
||||
QTestWindow() {
|
||||
_scriptEngine = new ScriptEngine();
|
||||
_timer.setInterval(1);
|
||||
QObject::connect(&_timer, &QTimer::timeout, this, &QTestWindow::draw);
|
||||
|
||||
_chromiumShareContext = new OffscreenGLCanvas();
|
||||
_chromiumShareContext->create();
|
||||
_chromiumShareContext->makeCurrent();
|
||||
qt_gl_set_global_share_context(_chromiumShareContext->getContext());
|
||||
|
||||
{
|
||||
setSurfaceType(QSurface::OpenGLSurface);
|
||||
QSurfaceFormat format = getDefaultOpenGLSurfaceFormat();
|
||||
setFormat(format);
|
||||
_context = new QOpenGLContextWrapper();
|
||||
_context->setFormat(format);
|
||||
_context->setShareContext(_chromiumShareContext->getContext());
|
||||
}
|
||||
|
||||
|
||||
if (!_context->create()) {
|
||||
qFatal("Could not create OpenGL context");
|
||||
}
|
||||
|
||||
show();
|
||||
|
||||
makeCurrent();
|
||||
|
||||
glewExperimental = true;
|
||||
glewInit();
|
||||
glGetError();
|
||||
|
||||
using namespace oglplus;
|
||||
Context::Enable(Capability::Blend);
|
||||
Context::BlendFunc(BlendFunction::SrcAlpha, BlendFunction::OneMinusSrcAlpha);
|
||||
Context::Disable(Capability::DepthTest);
|
||||
Context::Disable(Capability::CullFace);
|
||||
Context::ClearColor(0.2f, 0.2f, 0.2f, 1);
|
||||
|
||||
MessageDialog::registerType();
|
||||
InfoView::registerType();
|
||||
|
||||
auto offscreenUi = DependencyManager::set<OffscreenUi>();
|
||||
{
|
||||
offscreenUi->create(_context->getContext());
|
||||
offscreenUi->setProxyWindow(this);
|
||||
|
||||
connect(offscreenUi.data(), &OffscreenUi::textureUpdated, this, [this, offscreenUi](int textureId) {
|
||||
testQmlTexture = textureId;
|
||||
});
|
||||
|
||||
makeCurrent();
|
||||
}
|
||||
|
||||
|
||||
auto primaryScreen = QGuiApplication::primaryScreen();
|
||||
auto targetScreen = primaryScreen;
|
||||
auto screens = QGuiApplication::screens();
|
||||
if (screens.size() > 1) {
|
||||
for (auto screen : screens) {
|
||||
if (screen != targetScreen) {
|
||||
targetScreen = screen;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
auto rect = targetScreen->availableGeometry();
|
||||
rect.setWidth(rect.width() * 0.8f);
|
||||
rect.setHeight(rect.height() * 0.8f);
|
||||
rect.moveTo(QPoint(20, 20));
|
||||
setGeometry(rect);
|
||||
|
||||
#ifdef QML_CONTROL_GALLERY
|
||||
offscreenUi->setBaseUrl(QUrl::fromLocalFile(getTestQmlDir()));
|
||||
offscreenUi->load(QUrl("main.qml"));
|
||||
#else
|
||||
offscreenUi->setBaseUrl(QUrl::fromLocalFile(getInterfaceQmlDir()));
|
||||
offscreenUi->load(QUrl("TestRoot.qml"));
|
||||
#endif
|
||||
installEventFilter(offscreenUi.data());
|
||||
offscreenUi->resume();
|
||||
_timer.start();
|
||||
}
|
||||
|
||||
virtual ~QTestWindow() {
|
||||
DependencyManager::destroy<OffscreenUi>();
|
||||
}
|
||||
|
||||
private:
|
||||
void draw() {
|
||||
if (!isVisible()) {
|
||||
return;
|
||||
}
|
||||
|
||||
makeCurrent();
|
||||
auto error = glGetError();
|
||||
if (error != GL_NO_ERROR) {
|
||||
qDebug() << "GL error in entering draw " << error;
|
||||
}
|
||||
|
||||
using namespace oglplus;
|
||||
Context::Clear().ColorBuffer().DepthBuffer();
|
||||
ivec2 size(_size.width(), _size.height());
|
||||
size *= devicePixelRatio();
|
||||
size = glm::max(size, ivec2(100, 100));
|
||||
Context::Viewport(size.x, size.y);
|
||||
if (!_program) {
|
||||
_program = loadDefaultShader();
|
||||
_plane = loadPlane(_program);
|
||||
}
|
||||
|
||||
if (testQmlTexture > 0) {
|
||||
glBindTexture(GL_TEXTURE_2D, testQmlTexture);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
}
|
||||
|
||||
_program->Bind();
|
||||
_plane->Use();
|
||||
_plane->Draw();
|
||||
_context->swapBuffers(this);
|
||||
|
||||
fps.increment();
|
||||
if (fps.elapsed() >= 10.0f) {
|
||||
qDebug() << "FPS: " << fps.rate();
|
||||
fps.reset();
|
||||
}
|
||||
}
|
||||
|
||||
void makeCurrent() {
|
||||
_context->makeCurrent(this);
|
||||
}
|
||||
|
||||
void resizeWindow(const QSize & size) {
|
||||
_size = size;
|
||||
DependencyManager::get<OffscreenUi>()->resize(_size);
|
||||
}
|
||||
|
||||
|
||||
protected:
|
||||
void resizeEvent(QResizeEvent* ev) override {
|
||||
resizeWindow(ev->size());
|
||||
}
|
||||
|
||||
|
||||
void keyPressEvent(QKeyEvent* event) override {
|
||||
_altPressed = Qt::Key_Alt == event->key();
|
||||
switch (event->key()) {
|
||||
case Qt::Key_B:
|
||||
if (event->modifiers() & Qt::CTRL) {
|
||||
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
||||
offscreenUi->load("Browser.qml");
|
||||
}
|
||||
break;
|
||||
|
||||
case Qt::Key_J:
|
||||
if (event->modifiers() & Qt::CTRL) {
|
||||
loadScript(getExamplesDir() + "tests/qmlWebTest.js");
|
||||
}
|
||||
break;
|
||||
|
||||
case Qt::Key_K:
|
||||
if (event->modifiers() & Qt::CTRL) {
|
||||
OffscreenUi::question("Message title", "Message contents", [](QMessageBox::Button b){
|
||||
qDebug() << b;
|
||||
});
|
||||
}
|
||||
break;
|
||||
}
|
||||
QWindow::keyPressEvent(event);
|
||||
}
|
||||
|
||||
void moveEvent(QMoveEvent* event) override {
|
||||
static qreal oldPixelRatio = 0.0;
|
||||
if (devicePixelRatio() != oldPixelRatio) {
|
||||
oldPixelRatio = devicePixelRatio();
|
||||
resizeWindow(size());
|
||||
}
|
||||
QWindow::moveEvent(event);
|
||||
}
|
||||
};
|
||||
|
||||
const char * LOG_FILTER_RULES = R"V0G0N(
|
||||
hifi.offscreen.focus.debug=false
|
||||
qt.quick.mouse.debug=false
|
||||
)V0G0N";
|
||||
|
||||
void messageHandler(QtMsgType type, const QMessageLogContext& context, const QString& message) {
|
||||
QString logMessage = message;
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
if (!logMessage.isEmpty()) {
|
||||
OutputDebugStringA(logMessage.toLocal8Bit().constData());
|
||||
OutputDebugStringA("\n");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
QGuiApplication app(argc, argv);
|
||||
qInstallMessageHandler(messageHandler);
|
||||
QLoggingCategory::setFilterRules(LOG_FILTER_RULES);
|
||||
QTestWindow window;
|
||||
app.exec();
|
||||
return 0;
|
||||
}
|
||||
|
||||
#include "main.moc"
|
||||
|
|
643
tests/ui/src/oldmain.cpp
Normal file
643
tests/ui/src/oldmain.cpp
Normal file
|
@ -0,0 +1,643 @@
|
|||
//
|
||||
// Created by Bradley Austin Davis on 2015-04-22
|
||||
// Copyright 2013-2015 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
|
||||
//
|
||||
|
||||
#include <gl/Config.h>
|
||||
#include <gl/OglplusHelpers.h>
|
||||
#include <gl/GLHelpers.h>
|
||||
#include <memory>
|
||||
|
||||
#include <QtCore/QFile>
|
||||
#include <QtCore/QDir>
|
||||
#include <QtCore/QTime>
|
||||
#include <QtCore/QTimer>
|
||||
#include <QtCore/QElapsedTimer>
|
||||
#include <QtCore/QLoggingCategory>
|
||||
#include <QtCore/QThread>
|
||||
#include <QtCore/QUuid>
|
||||
|
||||
#include <QtGui/QWindow>
|
||||
#include <QtGui/QImage>
|
||||
#include <QtGui/QGuiApplication>
|
||||
#include <QtGui/QResizeEvent>
|
||||
#include <QtGui/QScreen>
|
||||
|
||||
#include <gl/QOpenGLContextWrapper.h>
|
||||
|
||||
#include <QtScript/QScriptEngine>
|
||||
|
||||
#include <QtQml/QQmlContext>
|
||||
#include <QtQml/QQmlApplicationEngine>
|
||||
|
||||
#include <GLMHelpers.h>
|
||||
#include <gl/OffscreenGLCanvas.h>
|
||||
#include <OffscreenUi.h>
|
||||
#include <PathUtils.h>
|
||||
#include <PathUtils.h>
|
||||
#include <VrMenu.h>
|
||||
#include <InfoView.h>
|
||||
#include <QmlWebWindowClass.h>
|
||||
#include <RegisteredMetaTypes.h>
|
||||
|
||||
const QString& getResourcesDir() {
|
||||
static QString dir;
|
||||
if (dir.isEmpty()) {
|
||||
QDir path(__FILE__);
|
||||
path.cdUp();
|
||||
dir = path.cleanPath(path.absoluteFilePath("../../../interface/resources/")) + "/";
|
||||
qDebug() << "Resources Path: " << dir;
|
||||
}
|
||||
return dir;
|
||||
}
|
||||
|
||||
const QString& getExamplesDir() {
|
||||
static QString dir;
|
||||
if (dir.isEmpty()) {
|
||||
QDir path(__FILE__);
|
||||
path.cdUp();
|
||||
dir = path.cleanPath(path.absoluteFilePath("../../../examples/")) + "/";
|
||||
qDebug() << "Resources Path: " << dir;
|
||||
}
|
||||
return dir;
|
||||
}
|
||||
|
||||
const QString& getInterfaceQmlDir() {
|
||||
static QString dir;
|
||||
if (dir.isEmpty()) {
|
||||
dir = getResourcesDir() + "qml/";
|
||||
qDebug() << "Qml Path: " << dir;
|
||||
}
|
||||
return dir;
|
||||
}
|
||||
|
||||
const QString& getTestQmlDir() {
|
||||
static QString dir;
|
||||
if (dir.isEmpty()) {
|
||||
QDir path(__FILE__);
|
||||
path.cdUp();
|
||||
dir = path.cleanPath(path.absoluteFilePath("../")) + "/";
|
||||
qDebug() << "Qml Test Path: " << dir;
|
||||
}
|
||||
return dir;
|
||||
}
|
||||
|
||||
|
||||
class RateCounter {
|
||||
std::vector<float> times;
|
||||
QElapsedTimer timer;
|
||||
public:
|
||||
RateCounter() {
|
||||
timer.start();
|
||||
}
|
||||
|
||||
void reset() {
|
||||
times.clear();
|
||||
}
|
||||
|
||||
size_t count() const {
|
||||
return times.size() - 1;
|
||||
}
|
||||
|
||||
float elapsed() const {
|
||||
if (times.size() < 1) {
|
||||
return 0.0f;
|
||||
}
|
||||
float elapsed = *times.rbegin() - *times.begin();
|
||||
return elapsed;
|
||||
}
|
||||
|
||||
void increment() {
|
||||
times.push_back(timer.elapsed() / 1000.0f);
|
||||
}
|
||||
|
||||
float rate() const {
|
||||
if (elapsed() == 0.0f) {
|
||||
return 0.0f;
|
||||
}
|
||||
return (float) count() / elapsed();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
extern QOpenGLContext* qt_gl_global_share_context();
|
||||
|
||||
|
||||
static bool hadUncaughtExceptions(QScriptEngine& engine, const QString& fileName) {
|
||||
if (engine.hasUncaughtException()) {
|
||||
const auto backtrace = engine.uncaughtExceptionBacktrace();
|
||||
const auto exception = engine.uncaughtException().toString();
|
||||
const auto line = QString::number(engine.uncaughtExceptionLineNumber());
|
||||
engine.clearExceptions();
|
||||
|
||||
auto message = QString("[UncaughtException] %1 in %2:%3").arg(exception, fileName, line);
|
||||
if (!backtrace.empty()) {
|
||||
static const auto lineSeparator = "\n ";
|
||||
message += QString("\n[Backtrace]%1%2").arg(lineSeparator, backtrace.join(lineSeparator));
|
||||
}
|
||||
qWarning() << qPrintable(message);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const unsigned int SCRIPT_DATA_CALLBACK_USECS = floor(((1.0f / 60.0f) * 1000 * 1000) + 0.5f);
|
||||
|
||||
static QScriptValue debugPrint(QScriptContext* context, QScriptEngine* engine) {
|
||||
QString message = "";
|
||||
for (int i = 0; i < context->argumentCount(); i++) {
|
||||
if (i > 0) {
|
||||
message += " ";
|
||||
}
|
||||
message += context->argument(i).toString();
|
||||
}
|
||||
qDebug().noquote() << "script:print()<<" << message; // noquote() so that \n is treated as newline
|
||||
|
||||
message = message.replace("\\", "\\\\")
|
||||
.replace("\n", "\\n")
|
||||
.replace("\r", "\\r")
|
||||
.replace("'", "\\'");
|
||||
engine->evaluate("Script.print('" + message + "')");
|
||||
|
||||
return QScriptValue();
|
||||
}
|
||||
|
||||
class ScriptEngine : public QScriptEngine {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
void loadFile(const QString& scriptPath) {
|
||||
if (_isRunning) {
|
||||
return;
|
||||
}
|
||||
qDebug() << "Loading script from " << scriptPath;
|
||||
_fileNameString = scriptPath;
|
||||
|
||||
QFile file(scriptPath);
|
||||
if (file.exists()) {
|
||||
file.open(QIODevice::ReadOnly);
|
||||
_scriptContents = file.readAll();
|
||||
} else {
|
||||
qFatal("Missing file ");
|
||||
}
|
||||
runInThread();
|
||||
}
|
||||
|
||||
Q_INVOKABLE void stop() {
|
||||
if (!_isFinished) {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QMetaObject::invokeMethod(this, "stop");
|
||||
return;
|
||||
}
|
||||
_isFinished = true;
|
||||
if (_wantSignals) {
|
||||
emit runningStateChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Q_INVOKABLE void print(const QString& message) {
|
||||
if (_wantSignals) {
|
||||
emit printedMessage(message);
|
||||
}
|
||||
}
|
||||
|
||||
Q_INVOKABLE QObject* setupTimerWithInterval(const QScriptValue& function, int intervalMS, bool isSingleShot) {
|
||||
// create the timer, add it to the map, and start it
|
||||
QTimer* newTimer = new QTimer(this);
|
||||
newTimer->setSingleShot(isSingleShot);
|
||||
|
||||
connect(newTimer, &QTimer::timeout, this, &ScriptEngine::timerFired);
|
||||
|
||||
// make sure the timer stops when the script does
|
||||
connect(this, &ScriptEngine::scriptEnding, newTimer, &QTimer::stop);
|
||||
|
||||
_timerFunctionMap.insert(newTimer, function);
|
||||
|
||||
newTimer->start(intervalMS);
|
||||
return newTimer;
|
||||
}
|
||||
|
||||
Q_INVOKABLE QObject* setInterval(const QScriptValue& function, int intervalMS) {
|
||||
return setupTimerWithInterval(function, intervalMS, false);
|
||||
}
|
||||
|
||||
Q_INVOKABLE QObject* setTimeout(const QScriptValue& function, int timeoutMS) {
|
||||
return setupTimerWithInterval(function, timeoutMS, true);
|
||||
}
|
||||
private:
|
||||
|
||||
void runInThread() {
|
||||
QThread* workerThread = new QThread();
|
||||
connect(workerThread, &QThread::finished, workerThread, &QThread::deleteLater);
|
||||
connect(workerThread, &QThread::started, this, &ScriptEngine::run);
|
||||
connect(workerThread, &QThread::finished, this, &ScriptEngine::deleteLater);
|
||||
connect(this, &ScriptEngine::doneRunning, workerThread, &QThread::quit);
|
||||
moveToThread(workerThread);
|
||||
workerThread->start();
|
||||
}
|
||||
|
||||
void init() {
|
||||
_isInitialized = true;
|
||||
registerMetaTypes(this);
|
||||
registerGlobalObject("Script", this);
|
||||
qScriptRegisterSequenceMetaType<QVector<QUuid>>(this);
|
||||
qScriptRegisterSequenceMetaType<QVector<QString>>(this);
|
||||
globalObject().setProperty("OverlayWebWindow", newFunction(QmlWebWindowClass::constructor));
|
||||
QScriptValue printConstructorValue = newFunction(debugPrint);
|
||||
globalObject().setProperty("print", printConstructorValue);
|
||||
}
|
||||
|
||||
void timerFired() {
|
||||
QTimer* callingTimer = reinterpret_cast<QTimer*>(sender());
|
||||
QScriptValue timerFunction = _timerFunctionMap.value(callingTimer);
|
||||
|
||||
if (!callingTimer->isActive()) {
|
||||
// this timer is done, we can kill it
|
||||
_timerFunctionMap.remove(callingTimer);
|
||||
delete callingTimer;
|
||||
}
|
||||
|
||||
// call the associated JS function, if it exists
|
||||
if (timerFunction.isValid()) {
|
||||
timerFunction.call();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void run() {
|
||||
if (!_isInitialized) {
|
||||
init();
|
||||
}
|
||||
|
||||
_isRunning = true;
|
||||
if (_wantSignals) {
|
||||
emit runningStateChanged();
|
||||
}
|
||||
|
||||
QScriptValue result = evaluate(_scriptContents, _fileNameString);
|
||||
QElapsedTimer startTime;
|
||||
startTime.start();
|
||||
|
||||
int thisFrame = 0;
|
||||
|
||||
qint64 lastUpdate = usecTimestampNow();
|
||||
|
||||
while (!_isFinished) {
|
||||
int usecToSleep = (thisFrame++ * SCRIPT_DATA_CALLBACK_USECS) - startTime.nsecsElapsed() / 1000; // nsec to usec
|
||||
if (usecToSleep > 0) {
|
||||
usleep(usecToSleep);
|
||||
}
|
||||
|
||||
if (_isFinished) {
|
||||
break;
|
||||
}
|
||||
|
||||
QCoreApplication::processEvents();
|
||||
if (_isFinished) {
|
||||
break;
|
||||
}
|
||||
|
||||
qint64 now = usecTimestampNow();
|
||||
float deltaTime = (float)(now - lastUpdate) / (float)USECS_PER_SECOND;
|
||||
if (!_isFinished) {
|
||||
if (_wantSignals) {
|
||||
emit update(deltaTime);
|
||||
}
|
||||
}
|
||||
lastUpdate = now;
|
||||
|
||||
// Debug and clear exceptions
|
||||
hadUncaughtExceptions(*this, _fileNameString);
|
||||
}
|
||||
|
||||
if (_wantSignals) {
|
||||
emit scriptEnding();
|
||||
}
|
||||
|
||||
if (_wantSignals) {
|
||||
emit finished(_fileNameString, this);
|
||||
}
|
||||
|
||||
_isRunning = false;
|
||||
|
||||
if (_wantSignals) {
|
||||
emit runningStateChanged();
|
||||
emit doneRunning();
|
||||
}
|
||||
}
|
||||
|
||||
void registerGlobalObject(const QString& name, QObject* object) {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QMetaObject::invokeMethod(this, "registerGlobalObject",
|
||||
Q_ARG(const QString&, name),
|
||||
Q_ARG(QObject*, object));
|
||||
return;
|
||||
}
|
||||
if (!globalObject().property(name).isValid()) {
|
||||
if (object) {
|
||||
QScriptValue value = newQObject(object);
|
||||
globalObject().setProperty(name, value);
|
||||
} else {
|
||||
globalObject().setProperty(name, QScriptValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void registerFunction(const QString& name, QScriptEngine::FunctionSignature functionSignature, int numArguments) {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QMetaObject::invokeMethod(this, "registerFunction",
|
||||
Q_ARG(const QString&, name),
|
||||
Q_ARG(QScriptEngine::FunctionSignature, functionSignature),
|
||||
Q_ARG(int, numArguments));
|
||||
return;
|
||||
}
|
||||
QScriptValue scriptFun = newFunction(functionSignature, numArguments);
|
||||
globalObject().setProperty(name, scriptFun);
|
||||
}
|
||||
|
||||
void registerFunction(const QString& parent, const QString& name, QScriptEngine::FunctionSignature functionSignature, int numArguments) {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QMetaObject::invokeMethod(this, "registerFunction",
|
||||
Q_ARG(const QString&, name),
|
||||
Q_ARG(QScriptEngine::FunctionSignature, functionSignature),
|
||||
Q_ARG(int, numArguments));
|
||||
return;
|
||||
}
|
||||
|
||||
QScriptValue object = globalObject().property(parent);
|
||||
if (object.isValid()) {
|
||||
QScriptValue scriptFun = newFunction(functionSignature, numArguments);
|
||||
object.setProperty(name, scriptFun);
|
||||
}
|
||||
}
|
||||
|
||||
signals:
|
||||
void scriptLoaded(const QString& scriptFilename);
|
||||
void errorLoadingScript(const QString& scriptFilename);
|
||||
void update(float deltaTime);
|
||||
void scriptEnding();
|
||||
void finished(const QString& fileNameString, ScriptEngine* engine);
|
||||
void cleanupMenuItem(const QString& menuItemString);
|
||||
void printedMessage(const QString& message);
|
||||
void errorMessage(const QString& message);
|
||||
void runningStateChanged();
|
||||
void evaluationFinished(QScriptValue result, bool isException);
|
||||
void loadScript(const QString& scriptName, bool isUserLoaded);
|
||||
void reloadScript(const QString& scriptName, bool isUserLoaded);
|
||||
void doneRunning();
|
||||
|
||||
|
||||
private:
|
||||
QString _scriptContents;
|
||||
QString _fileNameString;
|
||||
QString _parentURL;
|
||||
bool _isInitialized { false };
|
||||
std::atomic<bool> _isFinished { false };
|
||||
std::atomic<bool> _isRunning { false };
|
||||
bool _wantSignals { true };
|
||||
QHash<QTimer*, QScriptValue> _timerFunctionMap;
|
||||
};
|
||||
|
||||
|
||||
|
||||
ScriptEngine* loadScript(const QString& scriptFilename) {
|
||||
ScriptEngine* scriptEngine = new ScriptEngine();
|
||||
scriptEngine->loadFile(scriptFilename);
|
||||
return scriptEngine;
|
||||
}
|
||||
|
||||
OffscreenGLCanvas* _chromiumShareContext { nullptr };
|
||||
Q_GUI_EXPORT void qt_gl_set_global_share_context(QOpenGLContext *context);
|
||||
|
||||
|
||||
// Create a simple OpenGL window that renders text in various ways
|
||||
class QTestWindow : public QWindow {
|
||||
Q_OBJECT
|
||||
|
||||
QOpenGLContextWrapper* _context{ nullptr };
|
||||
QSize _size;
|
||||
bool _altPressed{ false };
|
||||
RateCounter fps;
|
||||
QTimer _timer;
|
||||
int testQmlTexture{ 0 };
|
||||
ProgramPtr _program;
|
||||
ShapeWrapperPtr _plane;
|
||||
QScriptEngine* _scriptEngine { nullptr };
|
||||
|
||||
public:
|
||||
QObject* rootMenu;
|
||||
|
||||
QTestWindow() {
|
||||
_scriptEngine = new ScriptEngine();
|
||||
_timer.setInterval(1);
|
||||
QObject::connect(&_timer, &QTimer::timeout, this, &QTestWindow::draw);
|
||||
|
||||
_chromiumShareContext = new OffscreenGLCanvas();
|
||||
_chromiumShareContext->create();
|
||||
_chromiumShareContext->makeCurrent();
|
||||
qt_gl_set_global_share_context(_chromiumShareContext->getContext());
|
||||
|
||||
{
|
||||
setSurfaceType(QSurface::OpenGLSurface);
|
||||
QSurfaceFormat format = getDefaultOpenGLSurfaceFormat();
|
||||
setFormat(format);
|
||||
_context = new QOpenGLContextWrapper();
|
||||
_context->setFormat(format);
|
||||
_context->setShareContext(_chromiumShareContext->getContext());
|
||||
}
|
||||
|
||||
|
||||
if (!_context->create()) {
|
||||
qFatal("Could not create OpenGL context");
|
||||
}
|
||||
|
||||
show();
|
||||
|
||||
makeCurrent();
|
||||
|
||||
glewExperimental = true;
|
||||
glewInit();
|
||||
glGetError();
|
||||
|
||||
using namespace oglplus;
|
||||
Context::Enable(Capability::Blend);
|
||||
Context::BlendFunc(BlendFunction::SrcAlpha, BlendFunction::OneMinusSrcAlpha);
|
||||
Context::Disable(Capability::DepthTest);
|
||||
Context::Disable(Capability::CullFace);
|
||||
Context::ClearColor(0.2f, 0.2f, 0.2f, 1);
|
||||
|
||||
InfoView::registerType();
|
||||
|
||||
auto offscreenUi = DependencyManager::set<OffscreenUi>();
|
||||
{
|
||||
offscreenUi->create(_context->getContext());
|
||||
offscreenUi->setProxyWindow(this);
|
||||
|
||||
connect(offscreenUi.data(), &OffscreenUi::textureUpdated, this, [this, offscreenUi](int textureId) {
|
||||
testQmlTexture = textureId;
|
||||
});
|
||||
|
||||
makeCurrent();
|
||||
}
|
||||
|
||||
|
||||
auto primaryScreen = QGuiApplication::primaryScreen();
|
||||
auto targetScreen = primaryScreen;
|
||||
auto screens = QGuiApplication::screens();
|
||||
if (screens.size() > 1) {
|
||||
for (auto screen : screens) {
|
||||
if (screen != targetScreen) {
|
||||
targetScreen = screen;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
auto rect = targetScreen->availableGeometry();
|
||||
rect.setWidth(rect.width() * 0.8f);
|
||||
rect.setHeight(rect.height() * 0.8f);
|
||||
rect.moveTo(QPoint(20, 20));
|
||||
setGeometry(rect);
|
||||
|
||||
#ifdef QML_CONTROL_GALLERY
|
||||
offscreenUi->setBaseUrl(QUrl::fromLocalFile(getTestQmlDir()));
|
||||
offscreenUi->load(QUrl("main.qml"));
|
||||
#else
|
||||
offscreenUi->setBaseUrl(QUrl::fromLocalFile(getInterfaceQmlDir()));
|
||||
offscreenUi->load(QUrl("TestRoot.qml"));
|
||||
#endif
|
||||
installEventFilter(offscreenUi.data());
|
||||
offscreenUi->resume();
|
||||
_timer.start();
|
||||
}
|
||||
|
||||
virtual ~QTestWindow() {
|
||||
DependencyManager::destroy<OffscreenUi>();
|
||||
}
|
||||
|
||||
private:
|
||||
void draw() {
|
||||
if (!isVisible()) {
|
||||
return;
|
||||
}
|
||||
|
||||
makeCurrent();
|
||||
auto error = glGetError();
|
||||
if (error != GL_NO_ERROR) {
|
||||
qDebug() << "GL error in entering draw " << error;
|
||||
}
|
||||
|
||||
using namespace oglplus;
|
||||
Context::Clear().ColorBuffer().DepthBuffer();
|
||||
ivec2 size(_size.width(), _size.height());
|
||||
size *= devicePixelRatio();
|
||||
size = glm::max(size, ivec2(100, 100));
|
||||
Context::Viewport(size.x, size.y);
|
||||
if (!_program) {
|
||||
_program = loadDefaultShader();
|
||||
_plane = loadPlane(_program);
|
||||
}
|
||||
|
||||
if (testQmlTexture > 0) {
|
||||
glBindTexture(GL_TEXTURE_2D, testQmlTexture);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
}
|
||||
|
||||
_program->Bind();
|
||||
_plane->Use();
|
||||
_plane->Draw();
|
||||
_context->swapBuffers(this);
|
||||
|
||||
fps.increment();
|
||||
if (fps.elapsed() >= 10.0f) {
|
||||
qDebug() << "FPS: " << fps.rate();
|
||||
fps.reset();
|
||||
}
|
||||
}
|
||||
|
||||
void makeCurrent() {
|
||||
_context->makeCurrent(this);
|
||||
}
|
||||
|
||||
void resizeWindow(const QSize & size) {
|
||||
_size = size;
|
||||
DependencyManager::get<OffscreenUi>()->resize(_size);
|
||||
}
|
||||
|
||||
|
||||
protected:
|
||||
void resizeEvent(QResizeEvent* ev) override {
|
||||
resizeWindow(ev->size());
|
||||
}
|
||||
|
||||
|
||||
void keyPressEvent(QKeyEvent* event) override {
|
||||
_altPressed = Qt::Key_Alt == event->key();
|
||||
switch (event->key()) {
|
||||
case Qt::Key_B:
|
||||
if (event->modifiers() & Qt::CTRL) {
|
||||
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
||||
offscreenUi->load("Browser.qml");
|
||||
}
|
||||
break;
|
||||
|
||||
case Qt::Key_J:
|
||||
if (event->modifiers() & Qt::CTRL) {
|
||||
loadScript(getExamplesDir() + "tests/qmlWebTest.js");
|
||||
}
|
||||
break;
|
||||
|
||||
case Qt::Key_K:
|
||||
if (event->modifiers() & Qt::CTRL) {
|
||||
OffscreenUi::question("Message title", "Message contents", [](QMessageBox::Button b){
|
||||
qDebug() << b;
|
||||
});
|
||||
}
|
||||
break;
|
||||
}
|
||||
QWindow::keyPressEvent(event);
|
||||
}
|
||||
|
||||
void moveEvent(QMoveEvent* event) override {
|
||||
static qreal oldPixelRatio = 0.0;
|
||||
if (devicePixelRatio() != oldPixelRatio) {
|
||||
oldPixelRatio = devicePixelRatio();
|
||||
resizeWindow(size());
|
||||
}
|
||||
QWindow::moveEvent(event);
|
||||
}
|
||||
};
|
||||
|
||||
const char * LOG_FILTER_RULES = R"V0G0N(
|
||||
hifi.offscreen.focus.debug=false
|
||||
qt.quick.mouse.debug=false
|
||||
)V0G0N";
|
||||
|
||||
void messageHandler(QtMsgType type, const QMessageLogContext& context, const QString& message) {
|
||||
QString logMessage = message;
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
if (!logMessage.isEmpty()) {
|
||||
OutputDebugStringA(logMessage.toLocal8Bit().constData());
|
||||
OutputDebugStringA("\n");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
QGuiApplication app(argc, argv);
|
||||
qInstallMessageHandler(messageHandler);
|
||||
QLoggingCategory::setFilterRules(LOG_FILTER_RULES);
|
||||
QTestWindow window;
|
||||
app.exec();
|
||||
return 0;
|
||||
}
|
||||
|
||||
#include "main.moc"
|
Loading…
Reference in a new issue