Merge pull request from thoys/feat/create/native-windows

Create App: Native windows
This commit is contained in:
John Conklin II 2018-07-09 14:25:13 -07:00 committed by GitHub
commit 25406fa464
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 936 additions and 222 deletions

View file

@ -120,12 +120,8 @@ Windows.Window {
Component.onCompleted: {
// Fix for parent loss on OSX:
parent.heightChanged.connect(function() {
updateContentParent();
});
parent.widthChanged.connect(function() {
updateContentParent();
});
parent.heightChanged.connect(updateContentParent);
parent.widthChanged.connect(updateContentParent);
x = interactiveWindowPosition.x;
y = interactiveWindowPosition.y;
@ -194,6 +190,11 @@ Windows.Window {
initialized = true;
}
Component.onDestruction: {
parent.heightChanged.disconnect(updateContentParent);
parent.widthChanged.disconnect(updateContentParent);
}
// Handle message traffic from the script that launched us to the loaded QML
function fromScript(message) {
if (root.dynamicContent && root.dynamicContent.fromScript) {

View file

@ -0,0 +1,15 @@
import QtQuick 2.7
import QtQuick.Controls 2.2
import QtWebChannel 1.0
import "../../controls"
import "../toolbars"
import QtGraphicalEffects 1.0
import "../../controls-uit" as HifiControls
import "../../styles-uit"
WebView {
id: entityListToolWebView
url: Paths.defaultScripts + "/system/html/entityList.html"
enabled: true
}

View file

@ -9,7 +9,6 @@ import "../../styles-uit"
TabBar {
id: editTabView
// anchors.fill: parent
width: parent.width
contentWidth: parent.width
padding: 0
@ -34,7 +33,7 @@ TabBar {
width: parent.width
clip: true
contentHeight: createEntitiesFlow.height + importButton.height + assetServerButton.height +
contentHeight: createEntitiesFlow.height + importButton.height + assetServerButton.height +
header.anchors.topMargin + createEntitiesFlow.anchors.topMargin +
assetServerButton.anchors.topMargin + importButton.anchors.topMargin +
header.paintedHeight
@ -77,8 +76,9 @@ TabBar {
text: "MODEL"
onClicked: {
editRoot.sendToScript({
method: "newEntityButtonClicked", params: { buttonName: "newModelButton" }
});
method: "newEntityButtonClicked",
params: { buttonName: "newModelButton" }
});
editTabView.currentIndex = 2
}
}
@ -88,8 +88,9 @@ TabBar {
text: "CUBE"
onClicked: {
editRoot.sendToScript({
method: "newEntityButtonClicked", params: { buttonName: "newCubeButton" }
});
method: "newEntityButtonClicked",
params: { buttonName: "newCubeButton" }
});
editTabView.currentIndex = 2
}
}
@ -99,8 +100,9 @@ TabBar {
text: "SPHERE"
onClicked: {
editRoot.sendToScript({
method: "newEntityButtonClicked", params: { buttonName: "newSphereButton" }
});
method: "newEntityButtonClicked",
params: { buttonName: "newSphereButton" }
});
editTabView.currentIndex = 2
}
}
@ -110,8 +112,9 @@ TabBar {
text: "LIGHT"
onClicked: {
editRoot.sendToScript({
method: "newEntityButtonClicked", params: { buttonName: "newLightButton" }
});
method: "newEntityButtonClicked",
params: { buttonName: "newLightButton" }
});
editTabView.currentIndex = 2
}
}
@ -121,8 +124,9 @@ TabBar {
text: "TEXT"
onClicked: {
editRoot.sendToScript({
method: "newEntityButtonClicked", params: { buttonName: "newTextButton" }
});
method: "newEntityButtonClicked",
params: { buttonName: "newTextButton" }
});
editTabView.currentIndex = 2
}
}
@ -132,8 +136,9 @@ TabBar {
text: "IMAGE"
onClicked: {
editRoot.sendToScript({
method: "newEntityButtonClicked", params: { buttonName: "newImageButton" }
});
method: "newEntityButtonClicked",
params: { buttonName: "newImageButton" }
});
editTabView.currentIndex = 2
}
}
@ -143,8 +148,9 @@ TabBar {
text: "WEB"
onClicked: {
editRoot.sendToScript({
method: "newEntityButtonClicked", params: { buttonName: "newWebButton" }
});
method: "newEntityButtonClicked",
params: { buttonName: "newWebButton" }
});
editTabView.currentIndex = 2
}
}
@ -154,8 +160,9 @@ TabBar {
text: "ZONE"
onClicked: {
editRoot.sendToScript({
method: "newEntityButtonClicked", params: { buttonName: "newZoneButton" }
});
method: "newEntityButtonClicked",
params: { buttonName: "newZoneButton" }
});
editTabView.currentIndex = 2
}
}
@ -165,8 +172,9 @@ TabBar {
text: "PARTICLE"
onClicked: {
editRoot.sendToScript({
method: "newEntityButtonClicked", params: { buttonName: "newParticleButton" }
});
method: "newEntityButtonClicked",
params: { buttonName: "newParticleButton" }
});
editTabView.currentIndex = 4
}
}
@ -176,8 +184,9 @@ TabBar {
text: "MATERIAL"
onClicked: {
editRoot.sendToScript({
method: "newEntityButtonClicked", params: { buttonName: "newMaterialButton" }
});
method: "newEntityButtonClicked",
params: { buttonName: "newMaterialButton" }
});
editTabView.currentIndex = 2
}
}
@ -196,8 +205,9 @@ TabBar {
anchors.topMargin: 35
onClicked: {
editRoot.sendToScript({
method: "newEntityButtonClicked", params: { buttonName: "openAssetBrowserButton" }
});
method: "newEntityButtonClicked",
params: { buttonName: "openAssetBrowserButton" }
});
}
}
@ -214,8 +224,9 @@ TabBar {
anchors.topMargin: 20
onClicked: {
editRoot.sendToScript({
method: "newEntityButtonClicked", params: { buttonName: "importEntitiesButton" }
});
method: "newEntityButtonClicked",
params: { buttonName: "importEntitiesButton" }
});
}
}
}

View file

@ -0,0 +1,58 @@
import QtQuick 2.7
import QtQuick.Controls 2.3
// FIXME pretty non-DRY code, should figure out a way to optionally hide one tab from the tab view, keep in sync with Edit.qml
StackView {
id: editRoot
objectName: "stack"
signal sendToScript(var message);
topPadding: 40
leftPadding: 0
rightPadding: 0
bottomPadding: 0
anchors.fill: parent
property var itemProperties: {"y": editRoot.topPadding,
"width": editRoot.availableWidth,
"height": editRoot.availableHeight }
Component.onCompleted: {
tab.currentIndex = 0
}
background: Rectangle {
color: "#404040" //default background color
EditToolsTabView {
id: tab
anchors.fill: parent
currentIndex: -1
onCurrentIndexChanged: {
editRoot.replace(null, tab.itemAt(currentIndex).visualItem,
itemProperties,
StackView.Immediate)
}
}
}
function pushSource(path) {
editRoot.push(Qt.resolvedUrl("../../" + path), itemProperties,
StackView.Immediate);
editRoot.currentItem.sendToScript.connect(editRoot.sendToScript);
}
function popSource() {
editRoot.pop(StackView.Immediate);
}
// Passes script messages to the item on the top of the stack
function fromScript(message) {
var currentItem = editRoot.currentItem;
if (currentItem && currentItem.fromScript) {
currentItem.fromScript(message);
} else if (tab.fromScript) {
tab.fromScript(message);
}
}
}

View file

@ -0,0 +1,328 @@
import QtQuick 2.7
import QtQuick.Controls 2.2
import QtWebChannel 1.0
import "../../controls"
import "../toolbars"
import QtGraphicalEffects 1.0
import "../../controls-uit" as HifiControls
import "../../styles-uit"
TabBar {
id: editTabView
width: parent.width
contentWidth: parent.width
padding: 0
spacing: 0
readonly property QtObject tabIndex: QtObject {
readonly property int create: 0
readonly property int properties: 1
readonly property int grid: 2
readonly property int particle: 3
}
readonly property HifiConstants hifi: HifiConstants {}
EditTabButton {
title: "CREATE"
active: true
enabled: true
property string originalUrl: ""
property Component visualItem: Component {
Rectangle {
color: "#404040"
id: container
Flickable {
height: parent.height
width: parent.width
clip: true
contentHeight: createEntitiesFlow.height + importButton.height + assetServerButton.height +
header.anchors.topMargin + createEntitiesFlow.anchors.topMargin +
assetServerButton.anchors.topMargin + importButton.anchors.topMargin +
header.paintedHeight
contentWidth: width
ScrollBar.vertical : ScrollBar {
visible: parent.contentHeight > parent.height
width: 20
background: Rectangle {
color: hifi.colors.tableScrollBackgroundDark
}
}
Text {
id: header
color: "#ffffff"
text: "Choose an Entity Type to Create:"
font.pixelSize: 14
font.bold: true
anchors.top: parent.top
anchors.topMargin: 28
anchors.left: parent.left
anchors.leftMargin: 28
}
Flow {
id: createEntitiesFlow
spacing: 35
anchors.right: parent.right
anchors.rightMargin: 55
anchors.left: parent.left
anchors.leftMargin: 55
anchors.top: parent.top
anchors.topMargin: 70
NewEntityButton {
icon: "icons/create-icons/94-model-01.svg"
text: "MODEL"
onClicked: {
editRoot.sendToScript({
method: "newEntityButtonClicked",
params: { buttonName: "newModelButton" }
});
editTabView.currentIndex = tabIndex.properties
}
}
NewEntityButton {
icon: "icons/create-icons/21-cube-01.svg"
text: "CUBE"
onClicked: {
editRoot.sendToScript({
method: "newEntityButtonClicked",
params: { buttonName: "newCubeButton" }
});
editTabView.currentIndex = tabIndex.properties
}
}
NewEntityButton {
icon: "icons/create-icons/22-sphere-01.svg"
text: "SPHERE"
onClicked: {
editRoot.sendToScript({
method: "newEntityButtonClicked",
params: { buttonName: "newSphereButton" }
});
editTabView.currentIndex = tabIndex.properties
}
}
NewEntityButton {
icon: "icons/create-icons/24-light-01.svg"
text: "LIGHT"
onClicked: {
editRoot.sendToScript({
method: "newEntityButtonClicked",
params: { buttonName: "newLightButton" }
});
editTabView.currentIndex = tabIndex.properties
}
}
NewEntityButton {
icon: "icons/create-icons/20-text-01.svg"
text: "TEXT"
onClicked: {
editRoot.sendToScript({
method: "newEntityButtonClicked",
params: { buttonName: "newTextButton" }
});
editTabView.currentIndex = tabIndex.properties
}
}
NewEntityButton {
icon: "icons/create-icons/image.svg"
text: "IMAGE"
onClicked: {
editRoot.sendToScript({
method: "newEntityButtonClicked",
params: { buttonName: "newImageButton" }
});
editTabView.currentIndex = tabIndex.properties
}
}
NewEntityButton {
icon: "icons/create-icons/25-web-1-01.svg"
text: "WEB"
onClicked: {
editRoot.sendToScript({
method: "newEntityButtonClicked",
params: { buttonName: "newWebButton" }
});
editTabView.currentIndex = tabIndex.properties
}
}
NewEntityButton {
icon: "icons/create-icons/23-zone-01.svg"
text: "ZONE"
onClicked: {
editRoot.sendToScript({
method: "newEntityButtonClicked",
params: { buttonName: "newZoneButton" }
});
editTabView.currentIndex = tabIndex.properties
}
}
NewEntityButton {
icon: "icons/create-icons/90-particles-01.svg"
text: "PARTICLE"
onClicked: {
editRoot.sendToScript({
method: "newEntityButtonClicked",
params: { buttonName: "newParticleButton" }
});
editTabView.currentIndex = tabIndex.particle
}
}
NewEntityButton {
icon: "icons/create-icons/126-material-01.svg"
text: "MATERIAL"
onClicked: {
editRoot.sendToScript({
method: "newEntityButtonClicked",
params: { buttonName: "newMaterialButton" }
});
editTabView.currentIndex = tabIndex.properties
}
}
}
HifiControls.Button {
id: assetServerButton
text: "Open This Domain's Asset Server"
color: hifi.buttons.black
colorScheme: hifi.colorSchemes.dark
anchors.right: parent.right
anchors.rightMargin: 55
anchors.left: parent.left
anchors.leftMargin: 55
anchors.top: createEntitiesFlow.bottom
anchors.topMargin: 35
onClicked: {
editRoot.sendToScript({
method: "newEntityButtonClicked",
params: { buttonName: "openAssetBrowserButton" }
});
}
}
HifiControls.Button {
id: importButton
text: "Import Entities (.json)"
color: hifi.buttons.black
colorScheme: hifi.colorSchemes.dark
anchors.right: parent.right
anchors.rightMargin: 55
anchors.left: parent.left
anchors.leftMargin: 55
anchors.top: assetServerButton.bottom
anchors.topMargin: 20
onClicked: {
editRoot.sendToScript({
method: "newEntityButtonClicked",
params: { buttonName: "importEntitiesButton" }
});
}
}
}
} // Flickable
}
}
EditTabButton {
title: "PROPERTIES"
active: true
enabled: true
property string originalUrl: ""
property Component visualItem: Component {
WebView {
id: entityPropertiesWebView
url: Paths.defaultScripts + "/system/html/entityProperties.html"
enabled: true
}
}
}
EditTabButton {
title: "GRID"
active: true
enabled: true
property string originalUrl: ""
property Component visualItem: Component {
WebView {
id: gridControlsWebView
url: Paths.defaultScripts + "/system/html/gridControls.html"
enabled: true
}
}
}
EditTabButton {
title: "P"
active: true
enabled: true
property string originalUrl: ""
property Component visualItem: Component {
WebView {
id: particleExplorerWebView
url: Paths.defaultScripts + "/system/particle_explorer/particleExplorer.html"
enabled: true
}
}
}
function fromScript(message) {
switch (message.method) {
case 'selectTab':
selectTab(message.params.id);
break;
default:
console.warn('Unrecognized message:', JSON.stringify(message));
}
}
// Changes the current tab based on tab index or title as input
function selectTab(id) {
if (typeof id === 'number') {
if (id >= tabIndex.create && id <= tabIndex.particle) {
editTabView.currentIndex = id;
} else {
console.warn('Attempt to switch to invalid tab:', id);
}
} else if (typeof id === 'string'){
switch (id.toLowerCase()) {
case 'create':
editTabView.currentIndex = tabIndex.create;
break;
case 'properties':
editTabView.currentIndex = tabIndex.properties;
break;
case 'grid':
editTabView.currentIndex = tabIndex.grid;
break;
case 'particle':
editTabView.currentIndex = tabIndex.particle;
break;
default:
console.warn('Attempt to switch to invalid tab:', id);
}
} else {
console.warn('Attempt to switch tabs with invalid input:', JSON.stringify(id));
}
}
}

View file

@ -0,0 +1,5 @@
WebView {
id: entityListToolWebView
url: Paths.defaultScripts + "/system/html/entityList.html"
enabled: true
}

View file

@ -29,12 +29,16 @@ Rectangle {
property bool keyboardRasied: false
function errorMessageBox(message) {
return desktop.messageBox({
icon: hifi.icons.warning,
defaultButton: OriginalDialogs.StandardButton.Ok,
title: "Error",
text: message
});
try {
return desktop.messageBox({
icon: hifi.icons.warning,
defaultButton: OriginalDialogs.StandardButton.Ok,
title: "Error",
text: message
});
} catch(e) {
Window.alert(message);
}
}
Item {

View file

@ -0,0 +1,20 @@
import QtQuick 2.7
import QtQuick.Controls 2.2
StackView {
id: stackView
anchors.fill: parent
anchors.leftMargin: 10
anchors.rightMargin: 10
anchors.topMargin: 40
signal sendToScript(var message);
NewMaterialDialog {
id: dialog
anchors.fill: parent
Component.onCompleted:{
dialog.sendToScript.connect(stackView.sendToScript);
}
}
}

View file

@ -29,12 +29,16 @@ Rectangle {
property bool keyboardRasied: false
function errorMessageBox(message) {
return desktop.messageBox({
icon: hifi.icons.warning,
defaultButton: OriginalDialogs.StandardButton.Ok,
title: "Error",
text: message
});
try {
return desktop.messageBox({
icon: hifi.icons.warning,
defaultButton: OriginalDialogs.StandardButton.Ok,
title: "Error",
text: message
});
} catch(e) {
Window.alert(message);
}
}
Item {

View file

@ -0,0 +1,20 @@
import QtQuick 2.7
import QtQuick.Controls 2.2
StackView {
id: stackView
anchors.fill: parent
anchors.leftMargin: 10
anchors.rightMargin: 10
anchors.topMargin: 40
signal sendToScript(var message);
NewModelDialog {
id: dialog
anchors.fill: parent
Component.onCompleted:{
dialog.sendToScript.connect(stackView.sendToScript);
}
}
}

View file

@ -10,17 +10,15 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
/* global Script, SelectionDisplay, LightOverlayManager, CameraManager, Grid, GridTool, EntityListTool, Vec3, SelectionManager, Overlays, OverlayWebWindow, UserActivityLogger,
Settings, Entities, Tablet, Toolbars, Messages, Menu, Camera, progressDialog, tooltip, MyAvatar, Quat, Controller, Clipboard, HMD, UndoStack, ParticleExplorerTool */
/* global Script, SelectionDisplay, LightOverlayManager, CameraManager, Grid, GridTool, EntityListTool, Vec3, SelectionManager,
Overlays, OverlayWebWindow, UserActivityLogger, Settings, Entities, Tablet, Toolbars, Messages, Menu, Camera,
progressDialog, tooltip, MyAvatar, Quat, Controller, Clipboard, HMD, UndoStack, ParticleExplorerTool, OverlaySystemWindow */
(function() { // BEGIN LOCAL_SCOPE
"use strict";
var HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/";
var EDIT_TOGGLE_BUTTON = "com.highfidelity.interface.system.editButton";
var SYSTEM_TOOLBAR = "com.highfidelity.interface.toolbar.system";
var EDIT_TOOLBAR = "com.highfidelity.interface.toolbar.edit";
Script.include([
"libraries/stringHelpers.js",
@ -36,13 +34,43 @@ Script.include([
"libraries/entityIconOverlayManager.js"
]);
var CreateWindow = Script.require('./modules/createWindow.js');
var TITLE_OFFSET = 60;
var CREATE_TOOLS_WIDTH = 490;
var MAX_DEFAULT_ENTITY_LIST_HEIGHT = 942;
var createToolsWindow = new CreateWindow(
Script.resourcesPath() + "qml/hifi/tablet/EditTools.qml",
'Create Tools',
'com.highfidelity.create.createToolsWindow',
function () {
var windowHeight = Window.innerHeight - TITLE_OFFSET;
if (windowHeight > MAX_DEFAULT_ENTITY_LIST_HEIGHT) {
windowHeight = MAX_DEFAULT_ENTITY_LIST_HEIGHT;
}
return {
size: {
x: CREATE_TOOLS_WIDTH,
y: windowHeight
},
position: {
x: Window.x + Window.innerWidth - CREATE_TOOLS_WIDTH,
y: Window.y + TITLE_OFFSET
}
}
},
false
);
var selectionDisplay = SelectionDisplay;
var selectionManager = SelectionManager;
var PARTICLE_SYSTEM_URL = Script.resolvePath("assets/images/icon-particles.svg");
var POINT_LIGHT_URL = Script.resolvePath("assets/images/icon-point-light.svg");
var SPOT_LIGHT_URL = Script.resolvePath("assets/images/icon-spot-light.svg");
entityIconOverlayManager = new EntityIconOverlayManager(['Light', 'ParticleEffect'], function(entityID) {
var entityIconOverlayManager = new EntityIconOverlayManager(['Light', 'ParticleEffect'], function(entityID) {
var properties = Entities.getEntityProperties(entityID, ['type', 'isSpotlight']);
if (properties.type === 'Light') {
return {
@ -59,7 +87,8 @@ var cameraManager = new CameraManager();
var grid = new Grid();
var gridTool = new GridTool({
horizontalGrid: grid
horizontalGrid: grid,
createToolsWindow: createToolsWindow
});
gridTool.setVisible(false);
@ -207,7 +236,7 @@ function hideMarketplace() {
// }
function adjustPositionPerBoundingBox(position, direction, registration, dimensions, orientation) {
// Adjust the position such that the bounding box (registration, dimenions, and orientation) lies behind the original
// Adjust the position such that the bounding box (registration, dimensions and orientation) lies behind the original
// position in the given direction.
var CORNERS = [
{ x: 0, y: 0, z: 0 },
@ -232,7 +261,6 @@ function adjustPositionPerBoundingBox(position, direction, registration, dimensi
return position;
}
var TOOLS_PATH = Script.resolvePath("assets/images/tools/");
var GRABBABLE_ENTITIES_MENU_CATEGORY = "Edit";
// Handles any edit mode updates required when domains have switched
@ -260,6 +288,7 @@ var toolBar = (function () {
toolBar,
activeButton = null,
systemToolbar = null,
dialogWindow = null,
tablet = null;
function createNewEntity(properties) {
@ -356,6 +385,13 @@ var toolBar = (function () {
return entityID;
}
function closeExistingDialogWindow() {
if (dialogWindow) {
dialogWindow.close();
dialogWindow = null;
}
}
function cleanup() {
that.setActive(false);
if (tablet) {
@ -438,7 +474,7 @@ var toolBar = (function () {
if (materialURL.startsWith("materialData")) {
materialData = JSON.stringify({
"materials": {}
})
});
}
var DEFAULT_LAYERED_MATERIAL_PRIORITY = 1;
@ -458,15 +494,23 @@ var toolBar = (function () {
var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
tablet.popFromStack();
switch (message.method) {
case "newModelDialogAdd":
handleNewModelDialogResult(message.params);
break;
case "newEntityButtonClicked":
buttonHandlers[message.params.buttonName]();
break;
case "newMaterialDialogAdd":
handleNewMaterialDialogResult(message.params);
break;
case "newModelDialogAdd":
handleNewModelDialogResult(message.params);
closeExistingDialogWindow();
break;
case "newModelDialogCancel":
closeExistingDialogWindow();
break;
case "newEntityButtonClicked":
buttonHandlers[message.params.buttonName]();
break;
case "newMaterialDialogAdd":
handleNewMaterialDialogResult(message.params);
closeExistingDialogWindow();
break;
case "newMaterialDialogCancel":
closeExistingDialogWindow();
break;
}
}
@ -501,6 +545,13 @@ var toolBar = (function () {
checkEditPermissionsAndUpdate();
});
HMD.displayModeChanged.connect(function() {
if (isActive) {
tablet.gotoHomeScreen();
}
that.setActive(false);
});
Entities.canAdjustLocksChanged.connect(function (canAdjustLocks) {
if (isActive && !canAdjustLocks) {
that.setActive(false);
@ -527,11 +578,13 @@ var toolBar = (function () {
});
createButton = activeButton;
tablet.screenChanged.connect(function (type, url) {
if (isActive && (type !== "QML" || url !== "hifi/tablet/Edit.qml")) {
that.setActive(false)
var isGoingToHomescreenOnDesktop = (!HMD.active && (url === 'hifi/tablet/TabletHome.qml' || url === ''));
if (isActive && (type !== "QML" || url !== "hifi/tablet/Edit.qml") && !isGoingToHomescreenOnDesktop) {
that.setActive(false);
}
});
tablet.fromQml.connect(fromQml);
createToolsWindow.fromQml.addListener(fromQml);
createButton.clicked.connect(function() {
if ( ! (Entities.canRez() || Entities.canRezTmp() || Entities.canRezCertified() || Entities.canRezTmpCertified()) ) {
@ -550,12 +603,29 @@ var toolBar = (function () {
addButton("openAssetBrowserButton", function() {
Window.showAssetServer();
});
function createNewEntityDialogButtonCallback(entityType) {
return function() {
if (HMD.active) {
// tablet version of new-model dialog
var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
tablet.pushOntoStack("hifi/tablet/New" + entityType + "Dialog.qml");
} else {
closeExistingDialogWindow();
var qmlPath = Script.resourcesPath() + "qml/hifi/tablet/New" + entityType + "Window.qml";
var DIALOG_WINDOW_SIZE = { x: 500, y: 300 };
dialogWindow = Desktop.createWindow(qmlPath, {
title: "New " + entityType + " Entity",
flags: Desktop.ALWAYS_ON_TOP | Desktop.CLOSE_BUTTON_HIDES,
presentationMode: Desktop.PresentationMode.NATIVE,
size: DIALOG_WINDOW_SIZE,
visible: true
});
dialogWindow.fromQml.connect(fromQml);
}
};
};
addButton("newModelButton", function () {
// tablet version of new-model dialog
var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
tablet.pushOntoStack("hifi/tablet/NewModelDialog.qml");
});
addButton("newModelButton", createNewEntityDialogButtonCallback("Model"));
addButton("newCubeButton", function () {
createNewEntity({
@ -716,11 +786,7 @@ var toolBar = (function () {
});
});
addButton("newMaterialButton", function () {
// tablet version of new material dialog
var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
tablet.pushOntoStack("hifi/tablet/NewMaterialDialog.qml");
});
addButton("newMaterialButton", createNewEntityDialogButtonCallback("Material"));
that.setActive(false);
}
@ -743,6 +809,8 @@ var toolBar = (function () {
Controller.captureEntityClickEvents();
} else {
Controller.releaseEntityClickEvents();
closeExistingDialogWindow();
}
if (active === isActive) {
return;
@ -769,7 +837,12 @@ var toolBar = (function () {
selectionDisplay.triggerMapping.disable();
tablet.landscape = false;
} else {
tablet.loadQMLSource("hifi/tablet/Edit.qml", true);
if (HMD.active) {
tablet.loadQMLSource("hifi/tablet/Edit.qml", true);
} else {
// make other apps inactive while in desktop mode
tablet.gotoHomeScreen();
}
UserActivityLogger.enabledEdit();
entityListTool.setVisible(true);
gridTool.setVisible(true);
@ -790,17 +863,6 @@ var toolBar = (function () {
return that;
})();
function isLocked(properties) {
// special case to lock the ground plane model in hq.
if (location.hostname === "hq.highfidelity.io" &&
properties.modelURL === HIFI_PUBLIC_BUCKET + "ozan/Terrain_Reduce_forAlpha.fbx") {
return true;
}
return false;
}
var selectedEntityID;
var orientation;
var intersection;
@ -1047,68 +1109,62 @@ function mouseClickEvent(event) {
return;
}
properties = Entities.getEntityProperties(foundEntity);
if (isLocked(properties)) {
if (wantDebug) {
print("Model locked " + properties.id);
var halfDiagonal = Vec3.length(properties.dimensions) / 2.0;
if (wantDebug) {
print("Checking properties: " + properties.id + " " + " - Half Diagonal:" + halfDiagonal);
}
// P P - Model
// /| A - Palm
// / | d B - unit vector toward tip
// / | X - base of the perpendicular line
// A---X----->B d - distance fom axis
// x x - distance from A
//
// |X-A| = (P-A).B
// X === A + ((P-A).B)B
// d = |P-X|
var A = pickRay.origin;
var B = Vec3.normalize(pickRay.direction);
var P = properties.position;
var x = Vec3.dot(Vec3.subtract(P, A), B);
var angularSize = 2 * Math.atan(halfDiagonal / Vec3.distance(Camera.getPosition(), properties.position)) *
180 / Math.PI;
var sizeOK = (allowLargeModels || angularSize < MAX_ANGULAR_SIZE) &&
(allowSmallModels || angularSize > MIN_ANGULAR_SIZE);
if (0 < x && sizeOK) {
selectedEntityID = foundEntity;
orientation = MyAvatar.orientation;
intersection = rayPlaneIntersection(pickRay, P, Quat.getForward(orientation));
if (event.isShifted) {
particleExplorerTool.destroyWebView();
}
if (properties.type !== "ParticleEffect") {
particleExplorerTool.destroyWebView();
}
if (!event.isShifted) {
selectionManager.setSelections([foundEntity]);
} else {
selectionManager.addEntity(foundEntity, true);
}
} else {
var halfDiagonal = Vec3.length(properties.dimensions) / 2.0;
if (wantDebug) {
print("Checking properties: " + properties.id + " " + " - Half Diagonal:" + halfDiagonal);
print("Model selected: " + foundEntity);
}
// P P - Model
// /| A - Palm
// / | d B - unit vector toward tip
// / | X - base of the perpendicular line
// A---X----->B d - distance fom axis
// x x - distance from A
//
// |X-A| = (P-A).B
// X === A + ((P-A).B)B
// d = |P-X|
selectionDisplay.select(selectedEntityID, event);
var A = pickRay.origin;
var B = Vec3.normalize(pickRay.direction);
var P = properties.position;
var x = Vec3.dot(Vec3.subtract(P, A), B);
var angularSize = 2 * Math.atan(halfDiagonal / Vec3.distance(Camera.getPosition(), properties.position)) *
180 / Math.PI;
var sizeOK = (allowLargeModels || angularSize < MAX_ANGULAR_SIZE) &&
(allowSmallModels || angularSize > MIN_ANGULAR_SIZE);
if (0 < x && sizeOK) {
selectedEntityID = foundEntity;
orientation = MyAvatar.orientation;
intersection = rayPlaneIntersection(pickRay, P, Quat.getForward(orientation));
if (event.isShifted) {
particleExplorerTool.destroyWebView();
}
if (properties.type !== "ParticleEffect") {
particleExplorerTool.destroyWebView();
}
if (!event.isShifted) {
selectionManager.setSelections([foundEntity]);
} else {
selectionManager.addEntity(foundEntity, true);
}
if (wantDebug) {
print("Model selected: " + foundEntity);
}
selectionDisplay.select(selectedEntityID, event);
if (Menu.isOptionChecked(MENU_AUTO_FOCUS_ON_SELECT)) {
cameraManager.enable();
cameraManager.focus(selectionManager.worldPosition,
selectionManager.worldDimensions,
Menu.isOptionChecked(MENU_EASE_ON_FOCUS));
}
if (Menu.isOptionChecked(MENU_AUTO_FOCUS_ON_SELECT)) {
cameraManager.enable();
cameraManager.focus(selectionManager.worldPosition,
selectionManager.worldDimensions,
Menu.isOptionChecked(MENU_EASE_ON_FOCUS));
}
}
} else if (event.isRightButton) {
@ -1368,11 +1424,7 @@ function selectAllEtitiesInCurrentSelectionBox(keepIfTouching) {
var localPosition = Vec3.multiplyQbyV(Quat.inverse(selectionManager.localRotation),
Vec3.subtract(position,
selectionManager.localPosition));
return insideBox({
x: 0,
y: 0,
z: 0
}, selectionManager.localDimensions, localPosition);
return insideBox(Vec3.ZERO, selectionManager.localDimensions, localPosition);
};
}
for (var i = 0; i < entities.length; ++i) {
@ -1476,7 +1528,7 @@ function parentSelectedEntities() {
return;
}
var parentCheck = false;
var lastEntityId = selectedEntities[selectedEntities.length-1];
var lastEntityId = selectedEntities[selectedEntities.length - 1];
selectedEntities.forEach(function (id, index) {
if (lastEntityId !== id) {
var parentId = Entities.getEntityProperties(id, ["parentID"]).parentID;
@ -1489,7 +1541,7 @@ function parentSelectedEntities() {
if (parentCheck) {
Window.notify("Entities parented");
}else {
} else {
Window.notify("Entities are already parented to last");
}
} else {
@ -1902,8 +1954,6 @@ function pushCommandForSelections(createdEntityData, deletedEntityData) {
UndoStack.pushCommand(applyEntityProperties, undoData, applyEntityProperties, redoData);
}
var ENTITY_PROPERTIES_URL = Script.resolvePath('html/entityProperties.html');
var ServerScriptStatusMonitor = function(entityID, statusCallback) {
var self = this;
@ -1947,13 +1997,14 @@ var PropertiesTool = function (opts) {
var currentSelectedEntityID = null;
var statusMonitor = null;
webView.setVisible(visible);
that.setVisible = function (newVisible) {
visible = newVisible;
webView.setVisible(visible);
webView.setVisible(HMD.active && visible);
createToolsWindow.setVisible(!HMD.active && visible);
};
that.setVisible(false);
function updateScriptStatus(info) {
info.type = "server_script_status";
webView.emitScriptEvent(JSON.stringify(info));
@ -1982,7 +2033,7 @@ var PropertiesTool = function (opts) {
statusMonitor = null;
}
currentSelectedEntityID = null;
} else if (currentSelectedEntityID != selectionManager.selections[0]) {
} else if (currentSelectedEntityID !== selectionManager.selections[0]) {
if (statusMonitor !== null) {
statusMonitor.stop();
}
@ -2008,11 +2059,14 @@ var PropertiesTool = function (opts) {
selections.push(entity);
}
data.selections = selections;
webView.emitScriptEvent(JSON.stringify(data));
createToolsWindow.emitScriptEvent(JSON.stringify(data));
}
selectionManager.addEventListener(updateSelections);
webView.webEventReceived.connect(function (data) {
var onWebEventReceived = function(data) {
try {
data = JSON.parse(data);
}
@ -2034,16 +2088,8 @@ var PropertiesTool = function (opts) {
} else if (data.properties) {
if (data.properties.dynamic === false) {
// this object is leaving dynamic, so we zero its velocities
data.properties.velocity = {
x: 0,
y: 0,
z: 0
};
data.properties.angularVelocity = {
x: 0,
y: 0,
z: 0
};
data.properties.velocity = Vec3.ZERO;
data.properties.angularVelocity = Vec3.ZERO;
}
if (data.properties.rotation !== undefined) {
var rotation = data.properties.rotation;
@ -2171,7 +2217,11 @@ var PropertiesTool = function (opts) {
} else if (data.type === "propertiesPageReady") {
updateSelections(true);
}
});
};
createToolsWindow.webEventReceived.addListener(this, onWebEventReceived);
webView.webEventReceived.connect(onWebEventReceived);
return that;
};
@ -2186,6 +2236,8 @@ var PopupMenu = function () {
var overlays = [];
var overlayInfo = {};
var visible = false;
var upColor = {
red: 0,
green: 0,
@ -2303,8 +2355,6 @@ var PopupMenu = function () {
}
};
var visible = false;
self.setVisible = function (newVisible) {
if (newVisible !== visible) {
visible = newVisible;
@ -2358,7 +2408,7 @@ propertyMenu.onSelectMenuItem = function (name) {
var showMenuItem = propertyMenu.addMenuItem("Show in Marketplace");
var propertiesTool = new PropertiesTool();
var particleExplorerTool = new ParticleExplorerTool();
var particleExplorerTool = new ParticleExplorerTool(createToolsWindow);
var selectedParticleEntityID = null;
function selectParticleEntity(entityID) {
@ -2375,11 +2425,16 @@ function selectParticleEntity(entityID) {
particleExplorerTool.setActiveParticleEntity(entityID);
// Switch to particle explorer
var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
tablet.sendToQml({method: 'selectTab', params: {id: 'particle'}});
var selectTabMethod = { method: 'selectTab', params: { id: 'particle' } };
if (HMD.active) {
var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
tablet.sendToQml(selectTabMethod);
} else {
createToolsWindow.sendToQml(selectTabMethod);
}
}
entityListTool.webView.webEventReceived.connect(function (data) {
entityListTool.webView.webEventReceived.connect(function(data) {
try {
data = JSON.parse(data);
} catch(e) {

View file

@ -11,27 +11,64 @@
/* global EntityListTool, Tablet, selectionManager, Entities, Camera, MyAvatar, Vec3, Menu, Messages,
cameraManager, MENU_EASE_ON_FOCUS, deleteSelectedEntities, toggleSelectedEntitiesLocked, toggleSelectedEntitiesVisible */
EntityListTool = function(opts) {
EntityListTool = function() {
var that = {};
var CreateWindow = Script.require('../modules/createWindow.js');
var TITLE_OFFSET = 60;
var ENTITY_LIST_WIDTH = 495;
var MAX_DEFAULT_CREATE_TOOLS_HEIGHT = 778;
var entityListWindow = new CreateWindow(
Script.resourcesPath() + "qml/hifi/tablet/EditEntityList.qml",
'Entity List',
'com.highfidelity.create.entityListWindow',
function () {
var windowHeight = Window.innerHeight - TITLE_OFFSET;
if (windowHeight > MAX_DEFAULT_CREATE_TOOLS_HEIGHT) {
windowHeight = MAX_DEFAULT_CREATE_TOOLS_HEIGHT;
}
return {
size: {
x: ENTITY_LIST_WIDTH,
y: windowHeight
},
position: {
x: Window.x,
y: Window.y + TITLE_OFFSET
}
};
},
false
);
var webView = null;
webView = Tablet.getTablet("com.highfidelity.interface.tablet.system");
webView.setVisible = function(value) {};
webView.setVisible = function(value){ };
var filterInView = false;
var searchRadius = 100;
var visible = false;
webView.setVisible(visible);
that.webView = webView;
that.setVisible = function(newVisible) {
visible = newVisible;
webView.setVisible(visible);
webView.setVisible(HMD.active && visible);
entityListWindow.setVisible(!HMD.active && visible);
};
that.setVisible(false);
function emitJSONScriptEvent(data) {
var dataString = JSON.stringify(data);
webView.emitScriptEvent(dataString);
if (entityListWindow.window) {
entityListWindow.window.emitScriptEvent(dataString);
}
}
that.toggleVisible = function() {
that.setVisible(!visible);
};
@ -43,18 +80,16 @@ EntityListTool = function(opts) {
selectedIDs.push(selectionManager.selections[i]);
}
var data = {
emitJSONScriptEvent({
type: 'selectionUpdate',
selectedIDs: selectedIDs,
};
webView.emitScriptEvent(JSON.stringify(data));
selectedIDs: selectedIDs
});
});
that.clearEntityList = function () {
var data = {
that.clearEntityList = function() {
emitJSONScriptEvent({
type: 'clearEntityList'
};
webView.emitScriptEvent(JSON.stringify(data));
});
};
that.removeEntities = function (deletedIDs, selectedIDs) {
@ -87,9 +122,9 @@ EntityListTool = function(opts) {
if (!filterInView || Vec3.distance(properties.position, cameraPosition) <= searchRadius) {
var url = "";
if (properties.type == "Model") {
if (properties.type === "Model") {
url = properties.modelURL;
} else if (properties.type == "Material") {
} else if (properties.type === "Material") {
url = properties.materialURL;
}
entities.push({
@ -107,7 +142,7 @@ EntityListTool = function(opts) {
valueIfDefined(properties.renderInfo.texturesSize) : ""),
hasTransparent: (properties.renderInfo !== undefined ?
valueIfDefined(properties.renderInfo.hasTransparent) : ""),
isBaked: properties.type == "Model" ? url.toLowerCase().endsWith(".baked.fbx") : false,
isBaked: properties.type === "Model" ? url.toLowerCase().endsWith(".baked.fbx") : false,
drawCalls: (properties.renderInfo !== undefined ?
valueIfDefined(properties.renderInfo.drawCalls) : ""),
hasScript: properties.script !== ""
@ -120,12 +155,11 @@ EntityListTool = function(opts) {
selectedIDs.push(selectionManager.selections[j]);
}
var data = {
emitJSONScriptEvent({
type: "update",
entities: entities,
selectedIDs: selectedIDs,
};
webView.emitScriptEvent(JSON.stringify(data));
});
};
function onFileSaveChanged(filename) {
@ -138,15 +172,15 @@ EntityListTool = function(opts) {
}
}
webView.webEventReceived.connect(function(data) {
var onWebEventReceived = function(data) {
try {
data = JSON.parse(data);
} catch(e) {
print("entityList.js: Error parsing JSON: " + e.name + " data " + data)
print("entityList.js: Error parsing JSON: " + e.name + " data " + data);
return;
}
if (data.type == "selectionUpdate") {
if (data.type === "selectionUpdate") {
var ids = data.entityIds;
var entityIDs = [];
for (var i = 0; i < ids.length; i++) {
@ -159,20 +193,20 @@ EntityListTool = function(opts) {
selectionManager.worldDimensions,
Menu.isOptionChecked(MENU_EASE_ON_FOCUS));
}
} else if (data.type == "refresh") {
} else if (data.type === "refresh") {
that.sendUpdate();
} else if (data.type == "teleport") {
} else if (data.type === "teleport") {
if (selectionManager.hasSelection()) {
MyAvatar.position = selectionManager.worldPosition;
}
} else if (data.type == "export") {
} else if (data.type === "export") {
if (!selectionManager.hasSelection()) {
Window.notifyEditError("No entities have been selected.");
} else {
Window.saveFileChanged.connect(onFileSaveChanged);
Window.saveAsync("Select Where to Save", "", "*.json");
}
} else if (data.type == "pal") {
} else if (data.type === "pal") {
var sessionIds = {}; // Collect the sessionsIds of all selected entitities, w/o duplicates.
selectionManager.selections.forEach(function (id) {
var lastEditedBy = Entities.getEntityProperties(id, 'lastEditedBy').lastEditedBy;
@ -189,24 +223,21 @@ EntityListTool = function(opts) {
// No need to subscribe if we're just sending.
Messages.sendMessage('com.highfidelity.pal', JSON.stringify({method: 'select', params: [dedupped, true, false]}), 'local');
}
} else if (data.type == "delete") {
} else if (data.type === "delete") {
deleteSelectedEntities();
} else if (data.type == "toggleLocked") {
} else if (data.type === "toggleLocked") {
toggleSelectedEntitiesLocked();
} else if (data.type == "toggleVisible") {
} else if (data.type === "toggleVisible") {
toggleSelectedEntitiesVisible();
} else if (data.type === "filterInView") {
filterInView = data.filterInView === true;
} else if (data.type === "radius") {
searchRadius = data.radius;
}
});
};
// webView.visibleChanged.connect(function () {
// if (webView.visible) {
// that.sendUpdate();
// }
// });
webView.webEventReceived.connect(onWebEventReceived);
entityListWindow.webEventReceived.addListener(onWebEventReceived);
return that;
};

View file

@ -240,6 +240,7 @@ GridTool = function(opts) {
var horizontalGrid = opts.horizontalGrid;
var verticalGrid = opts.verticalGrid;
var createToolsWindow = opts.createToolsWindow;
var listeners = [];
var webView = null;
@ -247,13 +248,15 @@ GridTool = function(opts) {
webView.setVisible = function(value) { };
horizontalGrid.addListener(function(data) {
webView.emitScriptEvent(JSON.stringify(data));
var dataString = JSON.stringify(data);
webView.emitScriptEvent(dataString);
createToolsWindow.emitScriptEvent(dataString);
if (selectionDisplay) {
selectionDisplay.updateHandles();
}
});
webView.webEventReceived.connect(function(data) {
var webEventReceived = function(data) {
try {
data = JSON.parse(data);
} catch (e) {
@ -282,14 +285,17 @@ GridTool = function(opts) {
grid.setPosition(newPosition);
}
}
});
};
webView.webEventReceived.connect(webEventReceived);
createToolsWindow.webEventReceived.addListener(webEventReceived);
that.addListener = function(callback) {
listeners.push(callback);
};
that.setVisible = function(visible) {
webView.setVisible(visible);
webView.setVisible(HMD.active && visible);
};
return that;

View file

@ -0,0 +1,151 @@
"use strict";
// createWindow.js
//
// Created by Thijs Wenker on 6/1/18
//
// Copyright 2018 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
var getWindowRect = function(settingsKey, defaultRect) {
var windowRect = Settings.getValue(settingsKey, defaultRect);
return windowRect;
};
var setWindowRect = function(settingsKey, position, size) {
Settings.setValue(settingsKey, {
position: position,
size: size
});
};
var CallableEvent = (function() {
function CallableEvent() {
this.callbacks = [];
}
CallableEvent.prototype = {
callbacks: null,
call: function () {
var callArguments = arguments;
this.callbacks.forEach(function(callbackObject) {
try {
callbackObject.callback.apply(callbackObject.context ? callbackObject.context : this, callArguments);
} catch (e) {
console.error('Call to CallableEvent callback failed!');
}
});
},
addListener: function(contextOrCallback, callback) {
if (callback) {
this.callbacks.push({
context: contextOrCallback,
callback: callback
});
} else {
this.callbacks.push({
callback: contextOrCallback
});
}
},
removeListener: function(callback) {
var foundIndex = -1;
this.callbacks.forEach(function (callbackObject, index) {
if (callbackObject.callback === callback) {
foundIndex = index;
}
});
if (foundIndex !== -1) {
this.callbacks.splice(foundIndex, 1);
}
}
};
return CallableEvent;
})();
module.exports = (function() {
function CreateWindow(qmlPath, title, settingsKey, defaultRect, createOnStartup) {
this.qmlPath = qmlPath;
this.title = title;
this.settingsKey = settingsKey;
this.defaultRect = defaultRect;
this.webEventReceived = new CallableEvent();
this.fromQml = new CallableEvent();
if (createOnStartup) {
this.createWindow();
}
}
CreateWindow.prototype = {
window: null,
createWindow: function() {
var defaultRect = this.defaultRect;
if (typeof this.defaultRect === "function") {
defaultRect = this.defaultRect();
}
var windowRect = getWindowRect(this.settingsKey, defaultRect);
this.window = Desktop.createWindow(this.qmlPath, {
title: this.title,
flags: Desktop.ALWAYS_ON_TOP | Desktop.CLOSE_BUTTON_HIDES,
presentationMode: Desktop.PresentationMode.NATIVE,
size: windowRect.size,
visible: true,
position: windowRect.position
});
var windowRectChanged = function () {
if (this.window.visible) {
setWindowRect(this.settingsKey, this.window.position, this.window.size);
}
};
this.window.sizeChanged.connect(this, windowRectChanged);
this.window.positionChanged.connect(this, windowRectChanged);
this.window.webEventReceived.connect(this, function (data) {
this.webEventReceived.call(data);
});
this.window.fromQml.connect(this, function (data) {
this.fromQml.call(data);
});
Script.scriptEnding.connect(this, function() {
this.window.close();
});
},
setVisible: function(visible) {
if (visible && !this.window) {
this.createWindow();
}
if (this.window) {
if (visible) {
this.window.show();
} else {
this.window.visible = false;
}
}
},
emitScriptEvent: function(data) {
if (this.window) {
this.window.emitScriptEvent(data);
}
},
sendToQml: function(data) {
if (this.window) {
this.window.sendToQml(data);
}
},
webEventReceived: null,
fromQml: null
};
return CreateWindow;
})();

View file

@ -9,13 +9,12 @@
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
/* global window, alert, ParticleExplorerTool, EventBridge, dat, listenForSettingsUpdates, createVec3Folder,
createQuatFolder, writeVec3ToInterface, writeDataToInterface */
/* global ParticleExplorerTool */
var PARTICLE_EXPLORER_HTML_URL = Script.resolvePath('particleExplorer.html');
ParticleExplorerTool = function() {
ParticleExplorerTool = function(createToolsWindow) {
var that = {};
that.activeParticleEntity = 0;
that.updatedActiveParticleProperties = {};
@ -24,8 +23,15 @@ ParticleExplorerTool = function() {
that.webView = Tablet.getTablet("com.highfidelity.interface.tablet.system");
that.webView.setVisible = function(value) {};
that.webView.webEventReceived.connect(that.webEventReceived);
createToolsWindow.webEventReceived.addListener(this, that.webEventReceived);
};
function emitScriptEvent(data) {
var messageData = JSON.stringify(data);
that.webView.emitScriptEvent(messageData);
createToolsWindow.emitScriptEvent(messageData);
}
that.destroyWebView = function() {
if (!that.webView) {
return;
@ -33,17 +39,16 @@ ParticleExplorerTool = function() {
that.activeParticleEntity = 0;
that.updatedActiveParticleProperties = {};
var messageData = {
emitScriptEvent({
messageType: "particle_close"
};
that.webView.emitScriptEvent(JSON.stringify(messageData));
});
};
function sendParticleProperties(properties) {
that.webView.emitScriptEvent(JSON.stringify({
emitScriptEvent({
messageType: "particle_settings",
currentProperties: properties
}));
});
}
function sendActiveParticleProperties() {