diff --git a/interface/src/scripting/DesktopScriptingInterface.h b/interface/src/scripting/DesktopScriptingInterface.h
index 68eb27c7d0..175ce22ad2 100644
--- a/interface/src/scripting/DesktopScriptingInterface.h
+++ b/interface/src/scripting/DesktopScriptingInterface.h
@@ -45,6 +45,7 @@
* {@link InteractiveWindow}: none, top left, top right, bottom right, or bottom left of the Interface window.
* Read-only.
*/
+
class DesktopScriptingInterface : public QObject, public Dependency {
Q_OBJECT
Q_PROPERTY(int width READ getWidth) // Physical width of screen(s) including task bars and system menus
diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h
index bee7d21134..81f4d340a7 100644
--- a/libraries/script-engine/src/ScriptEngine.h
+++ b/libraries/script-engine/src/ScriptEngine.h
@@ -129,6 +129,7 @@ public:
virtual void compileTest() = 0;
virtual QString scriptValueDebugDetails(const ScriptValue &value) = 0;
virtual QString scriptValueDebugListMembers(const ScriptValue &value) = 0;
+ virtual void logBacktrace(const QString &title) = 0;
public:
// helper to detect and log warnings when other code invokes QScriptEngine/BaseScriptEngine in thread-unsafe ways
bool IS_THREADSAFE_INVOCATION(const QString& method);
diff --git a/libraries/script-engine/src/ScriptManager.cpp b/libraries/script-engine/src/ScriptManager.cpp
index 18f41f32c5..b359dc5e3a 100644
--- a/libraries/script-engine/src/ScriptManager.cpp
+++ b/libraries/script-engine/src/ScriptManager.cpp
@@ -2508,3 +2508,7 @@ ScriptValue ScriptManager::evaluate(const QString& program, const QString& fileN
void ScriptManager::requestGarbageCollection() {
_engine->requestCollectGarbage();
}
+
+void ScriptManager::logBacktrace(const QString &title) {
+ _engine->logBacktrace(title);
+}
diff --git a/libraries/script-engine/src/ScriptManager.h b/libraries/script-engine/src/ScriptManager.h
index 3d149c5e8d..3a21882e04 100644
--- a/libraries/script-engine/src/ScriptManager.h
+++ b/libraries/script-engine/src/ScriptManager.h
@@ -564,6 +564,13 @@ public:
*/
Q_INVOKABLE void requestGarbageCollection();
+ /**jsdoc
+ * Prints out current backtrace to the log.
+ * @function Script.logBacktrace
+ * @param {string} title - Title added to the printed out backtrace.
+ */
+ Q_INVOKABLE void logBacktrace(const QString &title);
+
/*@jsdoc
* @function Script.loadEntityScript
* @param {Uuid} entityID - Entity ID.
diff --git a/libraries/script-engine/src/v8/ScriptEngineV8.cpp b/libraries/script-engine/src/v8/ScriptEngineV8.cpp
index 186bba2e5b..de4e8fa264 100644
--- a/libraries/script-engine/src/v8/ScriptEngineV8.cpp
+++ b/libraries/script-engine/src/v8/ScriptEngineV8.cpp
@@ -1714,6 +1714,14 @@ QString ScriptEngineV8::scriptValueDebugDetailsV8(const V8ScriptValue &v8Value)
}
}*/
+void ScriptEngineV8::logBacktrace(const QString &title) {
+ QStringList backtrace = currentContext()->backtrace();
+ qDebug(scriptengine) << title;
+ for (int n = 0; n < backtrace.length(); n++) {
+ qDebug(scriptengine) << backtrace[n];
+ }
+}
+
QStringList ScriptEngineV8::getCurrentScriptURLs() const {
auto isolate = _v8Isolate;
v8::Locker locker(isolate);
diff --git a/libraries/script-engine/src/v8/ScriptEngineV8.h b/libraries/script-engine/src/v8/ScriptEngineV8.h
index 324ebb1292..e6f89d0b7d 100644
--- a/libraries/script-engine/src/v8/ScriptEngineV8.h
+++ b/libraries/script-engine/src/v8/ScriptEngineV8.h
@@ -136,6 +136,7 @@ public: // ScriptEngine implementation
QString scriptValueDebugDetailsV8(const V8ScriptValue &value);
virtual QString scriptValueDebugListMembers(const ScriptValue &value) override;
QString scriptValueDebugListMembersV8(const V8ScriptValue &v8Value);
+ virtual void logBacktrace(const QString &title) override;
// helper to detect and log warnings when other code invokes QScriptEngine/BaseScriptEngine in thread-unsafe ways
inline bool IS_THREADSAFE_INVOCATION(const QString& method) { return ScriptEngine::IS_THREADSAFE_INVOCATION(method); }
diff --git a/libraries/script-engine/src/v8/ScriptEngineV8_cast.cpp b/libraries/script-engine/src/v8/ScriptEngineV8_cast.cpp
index 5b550eef0f..b614a063fe 100644
--- a/libraries/script-engine/src/v8/ScriptEngineV8_cast.cpp
+++ b/libraries/script-engine/src/v8/ScriptEngineV8_cast.cpp
@@ -49,6 +49,7 @@ void ScriptEngineV8::registerCustomType(int type,
}
Q_DECLARE_METATYPE(ScriptValue);
+Q_DECLARE_METATYPE(QVariantMap);
/*static V8ScriptValue ScriptValueToV8ScriptValue(ScriptEngineV8* engine, const ScriptValue& src) {
return ScriptValueV8Wrapper::fullUnwrap(static_cast(engine), src);
diff --git a/libraries/script-engine/src/v8/ScriptObjectV8Proxy.cpp b/libraries/script-engine/src/v8/ScriptObjectV8Proxy.cpp
index 4f9a4dbb43..c4b3a0a030 100644
--- a/libraries/script-engine/src/v8/ScriptObjectV8Proxy.cpp
+++ b/libraries/script-engine/src/v8/ScriptObjectV8Proxy.cpp
@@ -1144,10 +1144,20 @@ int ScriptSignalV8Proxy::qt_metacall(QMetaObject::Call call, int id, void** argu
for (ConnectionList::iterator iter = _connections.begin(); iter != _connections.end(); ++iter) {
Connection& conn = *iter;
{
- //auto functionContext = callback->CreationContext();
- auto functionContext = _v8Context.Get(_engine->getIsolate());
- _engine->pushContext(functionContext);
+ /*if (!conn.callback.get()->IsFunction()) {
+ auto stringV8 = conn.callback.get()->ToDetailString(context).ToLocalChecked();
+ QString error = *v8::String::Utf8Value(_engine->getIsolate(), stringV8);
+ qDebug() << error;
+ Q_ASSERT(false);
+ }
+ v8::Local callback = v8::Local::Cast(conn.callback.get());
+ auto functionContext = callback->CreationContext();
v8::Context::Scope functionContextScope(functionContext);
+ _engine->pushContext(functionContext);*/
+ /*auto functionContext = _v8Context.Get(_engine->getIsolate());
+ _engine->pushContext(functionContext);
+ v8::Context::Scope functionContextScope(functionContext);*/
+ auto functionContext = context;
Q_ASSERT(!conn.callback.get().IsEmpty());
Q_ASSERT(!conn.callback.get()->IsUndefined());
@@ -1178,7 +1188,7 @@ int ScriptSignalV8Proxy::qt_metacall(QMetaObject::Call call, int id, void** argu
<< _engine->formatErrorMessageFromTryCatch(tryCatch)
<< "\nThis provided: " << conn.thisValue.get()->IsObject();
}
- _engine->popContext();
+ //_engine->popContext();
}
}
});
diff --git a/libraries/script-engine/src/v8/ScriptValueV8Wrapper.cpp b/libraries/script-engine/src/v8/ScriptValueV8Wrapper.cpp
index f76798b45b..135b44bbdd 100644
--- a/libraries/script-engine/src/v8/ScriptValueV8Wrapper.cpp
+++ b/libraries/script-engine/src/v8/ScriptValueV8Wrapper.cpp
@@ -91,6 +91,7 @@ ScriptValue ScriptValueV8Wrapper::call(const ScriptValue& thisObject, const Scri
//qDebug() << "V8 This: " << _engine->scriptValueDebugDetailsV8(v8This);
}else{
recv = _engine->getContext()->Global();
+ //recv = v8::Null(isolate);
//qDebug() << "global";
}
//qDebug() << "V8 Call: " << *v8::String::Utf8Value(isolate, v8This.get()->TypeOf(isolate));
diff --git a/scripts/system/create/edit.js b/scripts/system/create/edit.js
index ad40505855..aa8430a2ce 100644
--- a/scripts/system/create/edit.js
+++ b/scripts/system/create/edit.js
@@ -18,3252 +18,3268 @@
progressDialog, tooltip, MyAvatar, Quat, Controller, Clipboard, HMD, UndoStack, OverlaySystemWindow,
keyUpEventFromUIWindow:true */
-//(function() { // BEGIN LOCAL_SCOPE
+(function() { // BEGIN LOCAL_SCOPE
+ //var CreateApp = function() { // BEGIN LOCAL_SCOPE
+ var createApp = {};
-var EDIT_TOGGLE_BUTTON = "com.highfidelity.interface.system.editButton";
+ var EDIT_TOGGLE_BUTTON = "com.highfidelity.interface.system.editButton";
-var CONTROLLER_MAPPING_NAME = "com.highfidelity.editMode";
+ var CONTROLLER_MAPPING_NAME = "com.highfidelity.editMode";
-Script.include([
- "../libraries/stringHelpers.js",
- "../libraries/dataViewHelpers.js",
- "../libraries/progressDialog.js",
- "../libraries/ToolTip.js",
- "../libraries/entityCameraTool.js",
- "../libraries/utils.js",
- "../libraries/entityIconOverlayManager.js",
- "../libraries/gridTool.js",
- "entityList/entityList.js",
- "entitySelectionTool/entitySelectionTool.js",
- "audioFeedback/audioFeedback.js",
- "modules/brokenURLReport.js",
- "editModes/editModes.js",
- "editModes/editVoxels.js"
-]);
+ Script.include([
+ "../libraries/stringHelpers.js",
+ "../libraries/dataViewHelpers.js",
+ "../libraries/progressDialog.js",
+ "../libraries/ToolTip.js",
+ "../libraries/entityCameraTool.js",
+ "../libraries/utils.js",
+ "../libraries/entityIconOverlayManager.js",
+ "../libraries/gridTool.js",
+ "entityList/entityList.js",
+ "entitySelectionTool/entitySelectionTool.js",
+ "audioFeedback/audioFeedback.js",
+ "modules/brokenURLReport.js",
+ "editModes/editModes.js",
+ "editModes/editVoxels.js"
+ ]);
-var CreateWindow = Script.require('./modules/createWindow.js');
+ var CreateWindow = Script.require('./modules/createWindow.js');
-var TITLE_OFFSET = 60;
-var CREATE_TOOLS_WIDTH = 750;
-var MAX_DEFAULT_ENTITY_LIST_HEIGHT = 942;
-var ENTIRE_DOMAIN_SCAN_RADIUS = 27713;
+ var TITLE_OFFSET = 60;
+ var CREATE_TOOLS_WIDTH = 750;
+ var MAX_DEFAULT_ENTITY_LIST_HEIGHT = 942;
+ var ENTIRE_DOMAIN_SCAN_RADIUS = 27713;
-var DEFAULT_IMAGE = Script.getExternalPath(Script.ExternalPaths.Assets, "Bazaar/Assets/Textures/Defaults/Interface/default_image.jpg");
-var DEFAULT_PARTICLE = Script.getExternalPath(Script.ExternalPaths.Assets, "Bazaar/Assets/Textures/Defaults/Interface/default_particle.png");
+ var DEFAULT_IMAGE = Script.getExternalPath(Script.ExternalPaths.Assets, "Bazaar/Assets/Textures/Defaults/Interface/default_image.jpg");
+ var DEFAULT_PARTICLE = Script.getExternalPath(Script.ExternalPaths.Assets, "Bazaar/Assets/Textures/Defaults/Interface/default_particle.png");
-var createToolsWindow = new CreateWindow(
- Script.resolvePath("qml/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
+ var createToolsWindow = new CreateWindow(
+ Script.resolvePath("qml/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;
}
- }
- },
- false
-);
+ return {
+ size: {
+ x: CREATE_TOOLS_WIDTH,
+ y: windowHeight
+ },
+ position: {
+ x: Window.x + Window.innerWidth - CREATE_TOOLS_WIDTH,
+ y: Window.y + TITLE_OFFSET
+ }
+ }
+ },
+ false
+ );
-/**
- * @description Returns true in case we should use the tablet version of the CreateApp
- * @returns boolean
- */
-var shouldUseEditTabletApp = function() {
- return HMD.active || (!HMD.active && !Settings.getValue("desktopTabletBecomesToolbar", true));
-};
+ /**
+ * @description Returns true in case we should use the tablet version of the CreateApp
+ * @returns boolean
+ */
+ var shouldUseEditTabletApp = function() {
+ return HMD.active || (!HMD.active && !Settings.getValue("desktopTabletBecomesToolbar", true));
+ };
-var selectionDisplay = SelectionDisplay;
-var selectionManager = SelectionManager;
+ var selectionDisplay = SelectionDisplay;
+ selectionDisplay.createApp = createApp;
+ 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");
-var ZONE_URL = Script.resolvePath("assets/images/icon-zone.svg");
-var MATERIAL_URL = Script.resolvePath("assets/images/icon-material.svg");
+ 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");
+ var ZONE_URL = Script.resolvePath("assets/images/icon-zone.svg");
+ var MATERIAL_URL = Script.resolvePath("assets/images/icon-material.svg");
-var entityIconOverlayManager = new EntityIconOverlayManager(["Light", "ParticleEffect", "Zone", "Material"], function(entityID) {
- var properties = Entities.getEntityProperties(entityID, ["type", "isSpotlight", "parentID", "name"]);
- if (properties.type === "Light") {
- return {
- imageURL: properties.isSpotlight ? SPOT_LIGHT_URL : POINT_LIGHT_URL
- };
- } else if (properties.type === "Zone") {
- return { imageURL: ZONE_URL };
- } else if (properties.type === "Material") {
- if (properties.parentID !== Uuid.NULL && properties.name !== "MATERIAL_" + entityShapeVisualizerSessionName) {
- return { imageURL: MATERIAL_URL };
+ var entityIconOverlayManager = new EntityIconOverlayManager(["Light", "ParticleEffect", "Zone", "Material"], function(entityID) {
+ var properties = Entities.getEntityProperties(entityID, ["type", "isSpotlight", "parentID", "name"]);
+ if (properties.type === "Light") {
+ return {
+ imageURL: properties.isSpotlight ? SPOT_LIGHT_URL : POINT_LIGHT_URL
+ };
+ } else if (properties.type === "Zone") {
+ return { imageURL: ZONE_URL };
+ } else if (properties.type === "Material") {
+ if (properties.parentID !== Uuid.NULL && properties.name !== "MATERIAL_" + entityShapeVisualizerSessionName) {
+ return { imageURL: MATERIAL_URL };
+ } else {
+ return { imageURL: "" };
+ }
} else {
- return { imageURL: "" };
+ return { imageURL: PARTICLE_SYSTEM_URL };
}
- } else {
- return { imageURL: PARTICLE_SYSTEM_URL };
- }
-});
-
-var hmdMultiSelectMode = false;
-var expectingRotateAsClickedSurface = false;
-var keepSelectedOnNextClick = false;
-
-var copiedPosition;
-var copiedRotation;
-
-var cameraManager = new CameraManager();
-
-var grid = new Grid();
-var gridTool = new GridTool({
- horizontalGrid: grid,
- createToolsWindow: createToolsWindow,
- shouldUseEditTabletApp: shouldUseEditTabletApp
-});
-gridTool.setVisible(false);
-
-var editTools = new EditTools({
- createToolsWindow: createToolsWindow,
-});
-
-var editVoxels = new EditVoxels();
-editVoxels.editTools = editTools;
-
-editTools.addListener(editVoxels.updateEditSettings);
-editTools.addListener(selectionManager.updateEditSettings);
-
-var entityShapeVisualizerSessionName = "SHAPE_VISUALIZER_" + Uuid.generate();
-
-var EntityShapeVisualizer = Script.require('./modules/entityShapeVisualizer.js');
-var entityShapeVisualizer = new EntityShapeVisualizer(["Zone"], entityShapeVisualizerSessionName);
-
-var entityListTool = new EntityListTool(shouldUseEditTabletApp);
-
-selectionManager.addEventListener(function () {
- selectionDisplay.updateHandles();
- entityIconOverlayManager.updatePositions();
- entityShapeVisualizer.setEntities(selectionManager.selections);
-});
-
-var DEGREES_TO_RADIANS = Math.PI / 180.0;
-var RADIANS_TO_DEGREES = 180.0 / Math.PI;
-
-var MIN_ANGULAR_SIZE = 2;
-var MAX_ANGULAR_SIZE = 45;
-var allowLargeModels = true;
-var allowSmallModels = true;
-
-var DEFAULT_DIMENSION = 0.20;
-
-var DEFAULT_DIMENSIONS = {
- x: DEFAULT_DIMENSION,
- y: DEFAULT_DIMENSION,
- z: DEFAULT_DIMENSION
-};
-
-var DEFAULT_LIGHT_DIMENSIONS = Vec3.multiply(20, DEFAULT_DIMENSIONS);
-
-var MENU_IMPORT_FROM_FILE = "Import Entities (.json) From a File";
-var MENU_IMPORT_FROM_URL = "Import Entities (.json) From a URL";
-var MENU_CREATE_SEPARATOR = "Create Application";
-var SUBMENU_ENTITY_EDITOR_PREFERENCES = "Edit > Preferences";
-var MENU_AUTO_FOCUS_ON_SELECT = "Auto Focus on Select";
-var MENU_EASE_ON_FOCUS = "Ease Orientation on Focus";
-var MENU_SHOW_ICONS_IN_CREATE_MODE = "Show Icons in Create Mode";
-var MENU_CREATE_ENTITIES_GRABBABLE = "Create Entities As Grabbable (except Zones, Particles, and Lights)";
-var MENU_ALLOW_SELECTION_LARGE = "Allow Selecting of Large Models";
-var MENU_ALLOW_SELECTION_SMALL = "Allow Selecting of Small Models";
-var MENU_ALLOW_SELECTION_LIGHTS = "Allow Selecting of Lights";
-var MENU_ENTITY_LIST_DEFAULT_RADIUS = "Entity List Default Radius";
-
-var SETTING_AUTO_FOCUS_ON_SELECT = "autoFocusOnSelect";
-var SETTING_EASE_ON_FOCUS = "cameraEaseOnFocus";
-var SETTING_SHOW_LIGHTS_AND_PARTICLES_IN_EDIT_MODE = "showLightsAndParticlesInEditMode";
-var SETTING_SHOW_ZONES_IN_EDIT_MODE = "showZonesInEditMode";
-var SETTING_EDITOR_COLUMNS_SETUP = "editorColumnsSetup";
-var SETTING_ENTITY_LIST_DEFAULT_RADIUS = "entityListDefaultRadius";
-
-var SETTING_EDIT_PREFIX = "Edit/";
-
-
-var CREATE_ENABLED_ICON = "icons/tablet-icons/edit-i.svg";
-var CREATE_DISABLED_ICON = "icons/tablet-icons/edit-disabled.svg";
-
-// marketplace info, etc. not quite ready yet.
-var SHOULD_SHOW_PROPERTY_MENU = false;
-var INSUFFICIENT_PERMISSIONS_ERROR_MSG = "You do not have the necessary permissions to edit on this domain.";
-var INSUFFICIENT_PERMISSIONS_IMPORT_ERROR_MSG = "You do not have the necessary permissions to place items on this domain.";
-
-var isActive = false;
-var createButton = null;
-
-var IMPORTING_SVO_OVERLAY_WIDTH = 144;
-var IMPORTING_SVO_OVERLAY_HEIGHT = 30;
-var IMPORTING_SVO_OVERLAY_MARGIN = 5;
-var IMPORTING_SVO_OVERLAY_LEFT_MARGIN = 34;
-var importingSVOImageOverlay = Overlays.addOverlay("image", {
- imageURL: Script.resolvePath("assets/images/hourglass.svg"),
- width: 20,
- height: 20,
- alpha: 1.0,
- x: Window.innerWidth - IMPORTING_SVO_OVERLAY_WIDTH,
- y: Window.innerHeight - IMPORTING_SVO_OVERLAY_HEIGHT,
- visible: false
-});
-var importingSVOTextOverlay = Overlays.addOverlay("text", {
- font: {
- size: 14
- },
- text: "Importing SVO...",
- leftMargin: IMPORTING_SVO_OVERLAY_LEFT_MARGIN,
- x: Window.innerWidth - IMPORTING_SVO_OVERLAY_WIDTH - IMPORTING_SVO_OVERLAY_MARGIN,
- y: Window.innerHeight - IMPORTING_SVO_OVERLAY_HEIGHT - IMPORTING_SVO_OVERLAY_MARGIN,
- width: IMPORTING_SVO_OVERLAY_WIDTH,
- height: IMPORTING_SVO_OVERLAY_HEIGHT,
- backgroundColor: {
- red: 80,
- green: 80,
- blue: 80
- },
- backgroundAlpha: 0.7,
- visible: false
-});
-
-var MARKETPLACE_URL = Account.metaverseServerURL + "/marketplace";
-var marketplaceWindow = new OverlayWebWindow({
- title: 'Marketplace',
- source: "about:blank",
- width: 900,
- height: 700,
- visible: false
-});
-
-function showMarketplace(marketplaceID) {
- var url = MARKETPLACE_URL;
- if (marketplaceID) {
- url = url + "/items/" + marketplaceID;
- }
- marketplaceWindow.setURL(url);
- marketplaceWindow.setVisible(true);
- marketplaceWindow.raise();
-
- UserActivityLogger.logAction("opened_marketplace");
-}
-
-function hideMarketplace() {
- marketplaceWindow.setVisible(false);
- marketplaceWindow.setURL("about:blank");
-}
-
-// function toggleMarketplace() {
-// if (marketplaceWindow.visible) {
-// hideMarketplace();
-// } else {
-// showMarketplace();
-// }
-// }
-
-function adjustPositionPerBoundingBox(position, direction, registration, dimensions, orientation) {
- // 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 },
- { x: 0, y: 0, z: 1 },
- { x: 0, y: 1, z: 0 },
- { x: 0, y: 1, z: 1 },
- { x: 1, y: 0, z: 0 },
- { x: 1, y: 0, z: 1 },
- { x: 1, y: 1, z: 0 },
- { x: 1, y: 1, z: 1 },
- ];
-
- // Go through all corners and find least (most negative) distance in front of position.
- var distance = 0;
- for (var i = 0, length = CORNERS.length; i < length; i++) {
- var cornerVector =
- Vec3.multiplyQbyV(orientation, Vec3.multiplyVbyV(Vec3.subtract(CORNERS[i], registration), dimensions));
- var cornerDistance = Vec3.dot(cornerVector, direction);
- distance = Math.min(cornerDistance, distance);
- }
- position = Vec3.sum(Vec3.multiply(distance, direction), position);
- return position;
-}
-
-// Handles any edit mode updates required when domains have switched
-function checkEditPermissionsAndUpdate() {
- if ((createButton === null) || (createButton === undefined)) {
- //--EARLY EXIT--( nothing to safely update )
- return;
- }
-
- var hasRezPermissions = (Entities.canRez() || Entities.canRezTmp() || Entities.canRezCertified() || Entities.canRezTmpCertified());
- createButton.editProperties({
- icon: (hasRezPermissions ? CREATE_ENABLED_ICON : CREATE_DISABLED_ICON),
- captionColor: (hasRezPermissions ? "#ffffff" : "#888888"),
});
- if (!hasRezPermissions && isActive) {
- that.setActive(false);
- tablet.gotoHomeScreen();
- }
-}
+ var hmdMultiSelectMode = false;
+ var expectingRotateAsClickedSurface = false;
+ var keepSelectedOnNextClick = false;
-// Copies the properties in `b` into `a`. `a` will be modified.
-function copyProperties(a, b) {
- for (var key in b) {
- a[key] = b[key];
- }
- return a;
-}
+ var copiedPosition;
+ var copiedRotation;
-const DEFAULT_DYNAMIC_PROPERTIES = {
- dynamic: true,
- damping: 0.39347,
- angularDamping: 0.39347,
- gravity: { x: 0, y: -9.8, z: 0 },
-};
+ var cameraManager = new CameraManager();
-const DEFAULT_NON_DYNAMIC_PROPERTIES = {
- dynamic: false,
- damping: 0,
- angularDamping: 0,
- gravity: { x: 0, y: 0, z: 0 },
-};
+ var grid = new Grid();
+ selectionDisplay.grid = grid;
+ var gridTool = new GridTool({
+ horizontalGrid: grid,
+ createToolsWindow: createToolsWindow,
+ shouldUseEditTabletApp: shouldUseEditTabletApp
+ });
+ gridTool.selectionDisplay = selectionDisplay;
+ gridTool.setVisible(false);
-const DEFAULT_ENTITY_PROPERTIES = {
- All: {
- description: "",
- rotation: { x: 0, y: 0, z: 0, w: 1 },
- collidesWith: "static,dynamic,kinematic,otherAvatar,myAvatar",
- collisionSoundURL: "",
- cloneable: false,
- ignoreIK: true,
- canCastShadow: true,
- href: "",
- script: "",
- serverScripts:"",
- velocity: {
- x: 0,
- y: 0,
- z: 0
+ var editTools = new EditTools({
+ createToolsWindow: createToolsWindow,
+ });
+
+ var editVoxels = new EditVoxels();
+ editVoxels.editTools = editTools;
+
+ editTools.addListener(editVoxels.updateEditSettings);
+ editTools.addListener(selectionManager.updateEditSettings);
+
+ var entityShapeVisualizerSessionName = "SHAPE_VISUALIZER_" + Uuid.generate();
+
+ var EntityShapeVisualizer = Script.require('./modules/entityShapeVisualizer.js');
+ var entityShapeVisualizer = new EntityShapeVisualizer(["Zone"], entityShapeVisualizerSessionName);
+
+ var entityListTool = new EntityListTool(shouldUseEditTabletApp);
+ entityListTool.createApp = createApp;
+
+ selectionManager.addEventListener(function () {
+ selectionDisplay.updateHandles();
+ entityIconOverlayManager.updatePositions();
+ entityShapeVisualizer.setEntities(selectionManager.selections);
+ });
+
+ var DEGREES_TO_RADIANS = Math.PI / 180.0;
+ var RADIANS_TO_DEGREES = 180.0 / Math.PI;
+
+ var MIN_ANGULAR_SIZE = 2;
+ var MAX_ANGULAR_SIZE = 45;
+ var allowLargeModels = true;
+ var allowSmallModels = true;
+
+ var DEFAULT_DIMENSION = 0.20;
+
+ var DEFAULT_DIMENSIONS = {
+ x: DEFAULT_DIMENSION,
+ y: DEFAULT_DIMENSION,
+ z: DEFAULT_DIMENSION
+ };
+
+ var DEFAULT_LIGHT_DIMENSIONS = Vec3.multiply(20, DEFAULT_DIMENSIONS);
+
+ var MENU_IMPORT_FROM_FILE = "Import Entities (.json) From a File";
+ var MENU_IMPORT_FROM_URL = "Import Entities (.json) From a URL";
+ var MENU_CREATE_SEPARATOR = "Create Application";
+ var SUBMENU_ENTITY_EDITOR_PREFERENCES = "Edit > Preferences";
+ var MENU_AUTO_FOCUS_ON_SELECT = "Auto Focus on Select";
+ var MENU_EASE_ON_FOCUS = "Ease Orientation on Focus";
+ var MENU_SHOW_ICONS_IN_CREATE_MODE = "Show Icons in Create Mode";
+ var MENU_CREATE_ENTITIES_GRABBABLE = "Create Entities As Grabbable (except Zones, Particles, and Lights)";
+ var MENU_ALLOW_SELECTION_LARGE = "Allow Selecting of Large Models";
+ var MENU_ALLOW_SELECTION_SMALL = "Allow Selecting of Small Models";
+ var MENU_ALLOW_SELECTION_LIGHTS = "Allow Selecting of Lights";
+ var MENU_ENTITY_LIST_DEFAULT_RADIUS = "Entity List Default Radius";
+
+ var SETTING_AUTO_FOCUS_ON_SELECT = "autoFocusOnSelect";
+ var SETTING_EASE_ON_FOCUS = "cameraEaseOnFocus";
+ var SETTING_SHOW_LIGHTS_AND_PARTICLES_IN_EDIT_MODE = "showLightsAndParticlesInEditMode";
+ var SETTING_SHOW_ZONES_IN_EDIT_MODE = "showZonesInEditMode";
+ var SETTING_EDITOR_COLUMNS_SETUP = "editorColumnsSetup";
+ var SETTING_ENTITY_LIST_DEFAULT_RADIUS = "entityListDefaultRadius";
+
+ var SETTING_EDIT_PREFIX = "Edit/";
+
+
+ var CREATE_ENABLED_ICON = "icons/tablet-icons/edit-i.svg";
+ var CREATE_DISABLED_ICON = "icons/tablet-icons/edit-disabled.svg";
+
+ // marketplace info, etc. not quite ready yet.
+ var SHOULD_SHOW_PROPERTY_MENU = false;
+ var INSUFFICIENT_PERMISSIONS_ERROR_MSG = "You do not have the necessary permissions to edit on this domain.";
+ var INSUFFICIENT_PERMISSIONS_IMPORT_ERROR_MSG = "You do not have the necessary permissions to place items on this domain.";
+
+ var isActive = false;
+ var createButton = null;
+
+ var IMPORTING_SVO_OVERLAY_WIDTH = 144;
+ var IMPORTING_SVO_OVERLAY_HEIGHT = 30;
+ var IMPORTING_SVO_OVERLAY_MARGIN = 5;
+ var IMPORTING_SVO_OVERLAY_LEFT_MARGIN = 34;
+ var importingSVOImageOverlay = Overlays.addOverlay("image", {
+ imageURL: Script.resolvePath("assets/images/hourglass.svg"),
+ width: 20,
+ height: 20,
+ alpha: 1.0,
+ x: Window.innerWidth - IMPORTING_SVO_OVERLAY_WIDTH,
+ y: Window.innerHeight - IMPORTING_SVO_OVERLAY_HEIGHT,
+ visible: false
+ });
+ var importingSVOTextOverlay = Overlays.addOverlay("text", {
+ font: {
+ size: 14
},
- angularVelocity: {
- x: 0,
- y: 0,
- z: 0
+ text: "Importing SVO...",
+ leftMargin: IMPORTING_SVO_OVERLAY_LEFT_MARGIN,
+ x: Window.innerWidth - IMPORTING_SVO_OVERLAY_WIDTH - IMPORTING_SVO_OVERLAY_MARGIN,
+ y: Window.innerHeight - IMPORTING_SVO_OVERLAY_HEIGHT - IMPORTING_SVO_OVERLAY_MARGIN,
+ width: IMPORTING_SVO_OVERLAY_WIDTH,
+ height: IMPORTING_SVO_OVERLAY_HEIGHT,
+ backgroundColor: {
+ red: 80,
+ green: 80,
+ blue: 80
},
- restitution: 0.5,
- friction: 0.5,
- density: 1000,
+ backgroundAlpha: 0.7,
+ visible: false
+ });
+
+ var MARKETPLACE_URL = Account.metaverseServerURL + "/marketplace";
+ var marketplaceWindow = new OverlayWebWindow({
+ title: 'Marketplace',
+ source: "about:blank",
+ width: 900,
+ height: 700,
+ visible: false
+ });
+
+ function showMarketplace(marketplaceID) {
+ var url = MARKETPLACE_URL;
+ if (marketplaceID) {
+ url = url + "/items/" + marketplaceID;
+ }
+ marketplaceWindow.setURL(url);
+ marketplaceWindow.setVisible(true);
+ marketplaceWindow.raise();
+
+ UserActivityLogger.logAction("opened_marketplace");
+ }
+
+ function hideMarketplace() {
+ marketplaceWindow.setVisible(false);
+ marketplaceWindow.setURL("about:blank");
+ }
+
+ // function toggleMarketplace() {
+ // if (marketplaceWindow.visible) {
+ // hideMarketplace();
+ // } else {
+ // showMarketplace();
+ // }
+ // }
+
+ function adjustPositionPerBoundingBox(position, direction, registration, dimensions, orientation) {
+ // 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 },
+ { x: 0, y: 0, z: 1 },
+ { x: 0, y: 1, z: 0 },
+ { x: 0, y: 1, z: 1 },
+ { x: 1, y: 0, z: 0 },
+ { x: 1, y: 0, z: 1 },
+ { x: 1, y: 1, z: 0 },
+ { x: 1, y: 1, z: 1 },
+ ];
+
+ // Go through all corners and find least (most negative) distance in front of position.
+ var distance = 0;
+ for (var i = 0, length = CORNERS.length; i < length; i++) {
+ var cornerVector =
+ Vec3.multiplyQbyV(orientation, Vec3.multiplyVbyV(Vec3.subtract(CORNERS[i], registration), dimensions));
+ var cornerDistance = Vec3.dot(cornerVector, direction);
+ distance = Math.min(cornerDistance, distance);
+ }
+ position = Vec3.sum(Vec3.multiply(distance, direction), position);
+ return position;
+ }
+
+ // Handles any edit mode updates required when domains have switched
+ function checkEditPermissionsAndUpdate() {
+ if ((createButton === null) || (createButton === undefined)) {
+ //--EARLY EXIT--( nothing to safely update )
+ return;
+ }
+
+ var hasRezPermissions = (Entities.canRez() || Entities.canRezTmp() || Entities.canRezCertified() || Entities.canRezTmpCertified());
+ createButton.editProperties({
+ icon: (hasRezPermissions ? CREATE_ENABLED_ICON : CREATE_DISABLED_ICON),
+ captionColor: (hasRezPermissions ? "#ffffff" : "#888888"),
+ });
+
+ if (!hasRezPermissions && isActive) {
+ that.setActive(false);
+ tablet.gotoHomeScreen();
+ }
+ }
+
+ // Copies the properties in `b` into `a`. `a` will be modified.
+ function copyProperties(a, b) {
+ for (var key in b) {
+ a[key] = b[key];
+ }
+ return a;
+ }
+
+ const DEFAULT_DYNAMIC_PROPERTIES = {
+ dynamic: true,
+ damping: 0.39347,
+ angularDamping: 0.39347,
+ gravity: { x: 0, y: -9.8, z: 0 },
+ };
+
+ const DEFAULT_NON_DYNAMIC_PROPERTIES = {
dynamic: false,
- },
- Shape: {
- shape: "Box",
- dimensions: { x: 0.2, y: 0.2, z: 0.2 },
- color: { red: 0, green: 180, blue: 239 },
- },
- Text: {
- text: "Text",
- dimensions: {
- x: 0.65,
- y: 0.3,
- z: 0.01
- },
- textColor: { red: 255, green: 255, blue: 255 },
- backgroundColor: { red: 0, green: 0, blue: 0 },
- lineHeight: 0.06,
- faceCamera: false,
- },
- Zone: {
- dimensions: {
- x: 10,
- y: 10,
- z: 10
- },
- flyingAllowed: true,
- ghostingAllowed: true,
- filter: "",
- keyLightMode: "inherit",
- keyLightColor: { red: 255, green: 255, blue: 255 },
- keyLight: {
- intensity: 1.0,
- direction: {
- x: 0.0,
- y: -0.707106769084930, // 45 degrees
- z: 0.7071067690849304
+ damping: 0,
+ angularDamping: 0,
+ gravity: { x: 0, y: 0, z: 0 },
+ };
+
+ const DEFAULT_ENTITY_PROPERTIES = {
+ All: {
+ description: "",
+ rotation: { x: 0, y: 0, z: 0, w: 1 },
+ collidesWith: "static,dynamic,kinematic,otherAvatar,myAvatar",
+ collisionSoundURL: "",
+ cloneable: false,
+ ignoreIK: true,
+ canCastShadow: true,
+ href: "",
+ script: "",
+ serverScripts:"",
+ velocity: {
+ x: 0,
+ y: 0,
+ z: 0
},
- castShadows: true
- },
- ambientLightMode: "inherit",
- ambientLight: {
- ambientIntensity: 0.5,
- ambientURL: ""
- },
- hazeMode: "inherit",
- haze: {
- hazeRange: 1000,
- hazeAltitudeEffect: false,
- hazeBaseRef: 0,
- hazeColor: {
- red: 128,
- green: 154,
- blue: 179
+ angularVelocity: {
+ x: 0,
+ y: 0,
+ z: 0
},
- hazeBackgroundBlend: 0,
- hazeEnableGlare: false,
- hazeGlareColor: {
+ restitution: 0.5,
+ friction: 0.5,
+ density: 1000,
+ dynamic: false,
+ },
+ Shape: {
+ shape: "Box",
+ dimensions: { x: 0.2, y: 0.2, z: 0.2 },
+ color: { red: 0, green: 180, blue: 239 },
+ },
+ Text: {
+ text: "Text",
+ dimensions: {
+ x: 0.65,
+ y: 0.3,
+ z: 0.01
+ },
+ textColor: { red: 255, green: 255, blue: 255 },
+ backgroundColor: { red: 0, green: 0, blue: 0 },
+ lineHeight: 0.06,
+ faceCamera: false,
+ },
+ Zone: {
+ dimensions: {
+ x: 10,
+ y: 10,
+ z: 10
+ },
+ flyingAllowed: true,
+ ghostingAllowed: true,
+ filter: "",
+ keyLightMode: "inherit",
+ keyLightColor: { red: 255, green: 255, blue: 255 },
+ keyLight: {
+ intensity: 1.0,
+ direction: {
+ x: 0.0,
+ y: -0.707106769084930, // 45 degrees
+ z: 0.7071067690849304
+ },
+ castShadows: true
+ },
+ ambientLightMode: "inherit",
+ ambientLight: {
+ ambientIntensity: 0.5,
+ ambientURL: ""
+ },
+ hazeMode: "inherit",
+ haze: {
+ hazeRange: 1000,
+ hazeAltitudeEffect: false,
+ hazeBaseRef: 0,
+ hazeColor: {
+ red: 128,
+ green: 154,
+ blue: 179
+ },
+ hazeBackgroundBlend: 0,
+ hazeEnableGlare: false,
+ hazeGlareColor: {
+ red: 255,
+ green: 229,
+ blue: 179
+ },
+ },
+ shapeType: "box",
+ bloomMode: "inherit",
+ avatarPriority: "inherit",
+ screenshare: "inherit",
+ },
+ Model: {
+ collisionShape: "none",
+ compoundShapeURL: "",
+ animation: {
+ url: "",
+ running: false,
+ allowTranslation: false,
+ loop: true,
+ hold: false,
+ currentFrame: 0,
+ firstFrame: 0,
+ lastFrame: 100000,
+ fps: 30.0,
+ }
+ },
+ Image: {
+ dimensions: {
+ x: 0.5385,
+ y: 0.2819,
+ z: 0.0092
+ },
+ shapeType: "box",
+ collisionless: true,
+ keepAspectRatio: false,
+ imageURL: DEFAULT_IMAGE
+ },
+ Web: {
+ dimensions: {
+ x: 1.6,
+ y: 0.9,
+ z: 0.01
+ },
+ sourceUrl: "https://overte.org/",
+ dpi: 30,
+ },
+ ParticleEffect: {
+ lifespan: 1.5,
+ maxParticles: 10,
+ textures: DEFAULT_PARTICLE,
+ emitRate: 5.5,
+ emitSpeed: 0,
+ speedSpread: 0,
+ emitDimensions: { x: 0, y: 0, z: 0 },
+ emitOrientation: { x: 0, y: 0, z: 0, w: 1 },
+ emitterShouldTrail: true,
+ particleRadius: 0.25,
+ radiusStart: 0,
+ radiusSpread: 0,
+ particleColor: {
red: 255,
- green: 229,
- blue: 179
+ green: 255,
+ blue: 255
},
+ colorSpread: {
+ red: 0,
+ green: 0,
+ blue: 0
+ },
+ alpha: 0,
+ alphaStart: 1,
+ alphaSpread: 0,
+ emitAcceleration: {
+ x: 0,
+ y: 2.5,
+ z: 0
+ },
+ accelerationSpread: {
+ x: 0,
+ y: 0,
+ z: 0
+ },
+ particleSpin: 0,
+ spinSpread: 0,
+ rotateWithEntity: false,
+ polarStart: 0,
+ polarFinish: Math.PI,
+ azimuthStart: -Math.PI,
+ azimuthFinish: Math.PI
},
- shapeType: "box",
- bloomMode: "inherit",
- avatarPriority: "inherit",
- screenshare: "inherit",
- },
- Model: {
- collisionShape: "none",
- compoundShapeURL: "",
- animation: {
- url: "",
- running: false,
- allowTranslation: false,
- loop: true,
- hold: false,
- currentFrame: 0,
- firstFrame: 0,
- lastFrame: 100000,
- fps: 30.0,
- }
- },
- Image: {
- dimensions: {
- x: 0.5385,
- y: 0.2819,
- z: 0.0092
+ Light: {
+ color: { red: 255, green: 255, blue: 255 },
+ intensity: 5.0,
+ dimensions: DEFAULT_LIGHT_DIMENSIONS,
+ falloffRadius: 1.0,
+ isSpotlight: false,
+ exponent: 1.0,
+ cutoff: 75.0,
},
- shapeType: "box",
- collisionless: true,
- keepAspectRatio: false,
- imageURL: DEFAULT_IMAGE
- },
- Web: {
- dimensions: {
- x: 1.6,
- y: 0.9,
- z: 0.01
- },
- sourceUrl: "https://overte.org/",
- dpi: 30,
- },
- ParticleEffect: {
- lifespan: 1.5,
- maxParticles: 10,
- textures: DEFAULT_PARTICLE,
- emitRate: 5.5,
- emitSpeed: 0,
- speedSpread: 0,
- emitDimensions: { x: 0, y: 0, z: 0 },
- emitOrientation: { x: 0, y: 0, z: 0, w: 1 },
- emitterShouldTrail: true,
- particleRadius: 0.25,
- radiusStart: 0,
- radiusSpread: 0,
- particleColor: {
- red: 255,
- green: 255,
- blue: 255
- },
- colorSpread: {
- red: 0,
- green: 0,
- blue: 0
- },
- alpha: 0,
- alphaStart: 1,
- alphaSpread: 0,
- emitAcceleration: {
- x: 0,
- y: 2.5,
- z: 0
- },
- accelerationSpread: {
- x: 0,
- y: 0,
- z: 0
- },
- particleSpin: 0,
- spinSpread: 0,
- rotateWithEntity: false,
- polarStart: 0,
- polarFinish: Math.PI,
- azimuthStart: -Math.PI,
- azimuthFinish: Math.PI
- },
- Light: {
- color: { red: 255, green: 255, blue: 255 },
- intensity: 5.0,
- dimensions: DEFAULT_LIGHT_DIMENSIONS,
- falloffRadius: 1.0,
- isSpotlight: false,
- exponent: 1.0,
- cutoff: 75.0,
- },
-};
+ };
-var toolBar = (function () {
- var EDIT_SETTING = "io.highfidelity.isEditing"; // for communication with other scripts
- var that = {},
- toolBar,
- activeButton = null,
- systemToolbar = null,
- dialogWindow = null,
- tablet = null;
+ var toolBar = (function () {
+ var EDIT_SETTING = "io.highfidelity.isEditing"; // for communication with other scripts
+ var that = {},
+ toolBar,
+ activeButton = null,
+ systemToolbar = null,
+ dialogWindow = null,
+ tablet = null;
- function createNewEntity(requestedProperties) {
- var dimensions = requestedProperties.dimensions ? requestedProperties.dimensions : DEFAULT_DIMENSIONS;
- var position = getPositionToCreateEntity();
- var entityID = null;
+ function createNewEntity(requestedProperties) {
+ var dimensions = requestedProperties.dimensions ? requestedProperties.dimensions : DEFAULT_DIMENSIONS;
+ var position = getPositionToCreateEntity();
+ var entityID = null;
- var properties = {};
+ var properties = {};
- copyProperties(properties, DEFAULT_ENTITY_PROPERTIES.All);
+ copyProperties(properties, DEFAULT_ENTITY_PROPERTIES.All);
- var type = requestedProperties.type;
- if (type === "Box" || type === "Sphere") {
- copyProperties(properties, DEFAULT_ENTITY_PROPERTIES.Shape);
- } else {
- copyProperties(properties, DEFAULT_ENTITY_PROPERTIES[type]);
- }
-
- // We apply the requested properties first so that they take priority over any default properties.
- copyProperties(properties, requestedProperties);
-
- if (properties.dynamic) {
- copyProperties(properties, DEFAULT_DYNAMIC_PROPERTIES);
- } else {
- copyProperties(properties, DEFAULT_NON_DYNAMIC_PROPERTIES);
- }
-
-
- if (position !== null && position !== undefined) {
- var direction;
- if (Camera.mode === "entity" || Camera.mode === "independent") {
- direction = Camera.orientation;
+ var type = requestedProperties.type;
+ if (type === "Box" || type === "Sphere") {
+ copyProperties(properties, DEFAULT_ENTITY_PROPERTIES.Shape);
} else {
- direction = MyAvatar.orientation;
+ copyProperties(properties, DEFAULT_ENTITY_PROPERTIES[type]);
}
- direction = Vec3.multiplyQbyV(direction, Vec3.UNIT_Z);
- var PRE_ADJUST_ENTITY_TYPES = ["Box", "Sphere", "Shape", "Text", "Image", "Web", "Material"];
- if (PRE_ADJUST_ENTITY_TYPES.indexOf(properties.type) !== -1) {
+ // We apply the requested properties first so that they take priority over any default properties.
+ copyProperties(properties, requestedProperties);
- // Adjust position of entity per bounding box prior to creating it.
- var registration = properties.registration;
- if (registration === undefined) {
- var DEFAULT_REGISTRATION = { x: 0.5, y: 0.5, z: 0.5 };
- registration = DEFAULT_REGISTRATION;
- }
+ if (properties.dynamic) {
+ copyProperties(properties, DEFAULT_DYNAMIC_PROPERTIES);
+ } else {
+ copyProperties(properties, DEFAULT_NON_DYNAMIC_PROPERTIES);
+ }
- var orientation = properties.orientation;
- if (orientation === undefined) {
- properties.orientation = MyAvatar.orientation;
- var DEFAULT_ORIENTATION = properties.orientation;
- orientation = DEFAULT_ORIENTATION;
+
+ if (position !== null && position !== undefined) {
+ var direction;
+ if (Camera.mode === "entity" || Camera.mode === "independent") {
+ direction = Camera.orientation;
} else {
- // If the orientation is already defined, we perform the corresponding rotation assuming that
- // our start referential is the avatar referential.
- properties.orientation = Quat.multiply(MyAvatar.orientation, properties.orientation);
- var DEFAULT_ORIENTATION = properties.orientation;
- orientation = DEFAULT_ORIENTATION;
+ direction = MyAvatar.orientation;
+ }
+ direction = Vec3.multiplyQbyV(direction, Vec3.UNIT_Z);
+
+ var PRE_ADJUST_ENTITY_TYPES = ["Box", "Sphere", "Shape", "Text", "Image", "Web", "Material"];
+ if (PRE_ADJUST_ENTITY_TYPES.indexOf(properties.type) !== -1) {
+
+ // Adjust position of entity per bounding box prior to creating it.
+ var registration = properties.registration;
+ if (registration === undefined) {
+ var DEFAULT_REGISTRATION = { x: 0.5, y: 0.5, z: 0.5 };
+ registration = DEFAULT_REGISTRATION;
+ }
+
+ var orientation = properties.orientation;
+ if (orientation === undefined) {
+ properties.orientation = MyAvatar.orientation;
+ var DEFAULT_ORIENTATION = properties.orientation;
+ orientation = DEFAULT_ORIENTATION;
+ } else {
+ // If the orientation is already defined, we perform the corresponding rotation assuming that
+ // our start referential is the avatar referential.
+ properties.orientation = Quat.multiply(MyAvatar.orientation, properties.orientation);
+ var DEFAULT_ORIENTATION = properties.orientation;
+ orientation = DEFAULT_ORIENTATION;
+ }
+
+ position = adjustPositionPerBoundingBox(position, direction, registration, dimensions, orientation);
}
- position = adjustPositionPerBoundingBox(position, direction, registration, dimensions, orientation);
- }
+ position = grid.snapToSurface(grid.snapToGrid(position, false, dimensions), dimensions);
+ properties.position = position;
- position = grid.snapToSurface(grid.snapToGrid(position, false, dimensions), dimensions);
- properties.position = position;
-
- if (!properties.grab) {
- properties.grab = {};
- if (Menu.isOptionChecked(MENU_CREATE_ENTITIES_GRABBABLE) &&
- !(properties.type === "Zone" || properties.type === "Light"
- || properties.type === "ParticleEffect" || properties.type === "Web")) {
- properties.grab.grabbable = true;
- } else {
- properties.grab.grabbable = false;
+ if (!properties.grab) {
+ properties.grab = {};
+ if (Menu.isOptionChecked(MENU_CREATE_ENTITIES_GRABBABLE) &&
+ !(properties.type === "Zone" || properties.type === "Light"
+ || properties.type === "ParticleEffect" || properties.type === "Web")) {
+ properties.grab.grabbable = true;
+ } else {
+ properties.grab.grabbable = false;
+ }
}
- }
- if (type === "Model") {
- properties.visible = false;
- }
+ if (type === "Model") {
+ properties.visible = false;
+ }
- entityID = Entities.addEntity(properties);
+ entityID = Entities.addEntity(properties);
+
+ var dimensionsCheckCallback = function(){
+ // Adjust position of entity per bounding box after it has been created and auto-resized.
+ var initialDimensions = Entities.getEntityProperties(entityID, ["dimensions"]).dimensions;
+ var DIMENSIONS_CHECK_INTERVAL = 200;
+ var MAX_DIMENSIONS_CHECKS = 10;
+ var dimensionsCheckCount = 0;
+ var dimensionsCheckFunction = function () {
+ dimensionsCheckCount++;
+ var properties = Entities.getEntityProperties(entityID, ["dimensions", "registrationPoint", "rotation"]);
+ if (!Vec3.equal(properties.dimensions, initialDimensions)) {
+ position = adjustPositionPerBoundingBox(position, direction, properties.registrationPoint,
+ properties.dimensions, properties.rotation);
+ position = grid.snapToSurface(grid.snapToGrid(position, false, properties.dimensions),
+ properties.dimensions);
+ Entities.editEntity(entityID, {
+ position: position
+ });
+ selectionManager._update(false, this);
+ } else if (dimensionsCheckCount < MAX_DIMENSIONS_CHECKS) {
+ Script.setTimeout(dimensionsCheckFunction, DIMENSIONS_CHECK_INTERVAL);
+ }
+ };
+ Script.setTimeout(dimensionsCheckFunction, DIMENSIONS_CHECK_INTERVAL);
+ }
+ // Make sure the model entity is loaded before we try to figure out
+ // its dimensions. We need to give ample time to load the entity.
+ var MAX_LOADED_CHECKS = 100; // 100 * 100ms = 10 seconds.
+ var LOADED_CHECK_INTERVAL = 100;
+ var isLoadedCheckCount = 0;
+ var entityIsLoadedCheck = function() {
+ isLoadedCheckCount++;
+ if (isLoadedCheckCount === MAX_LOADED_CHECKS || Entities.isLoaded(entityID)) {
+ var naturalDimensions = Entities.getEntityProperties(entityID, "naturalDimensions").naturalDimensions;
+
+ if (isLoadedCheckCount === MAX_LOADED_CHECKS) {
+ console.log("Model entity failed to load in time: " + (MAX_LOADED_CHECKS * LOADED_CHECK_INTERVAL) + " ... setting dimensions to: " + JSON.stringify(naturalDimensions))
+ }
- var dimensionsCheckCallback = function(){
- // Adjust position of entity per bounding box after it has been created and auto-resized.
- var initialDimensions = Entities.getEntityProperties(entityID, ["dimensions"]).dimensions;
- var DIMENSIONS_CHECK_INTERVAL = 200;
- var MAX_DIMENSIONS_CHECKS = 10;
- var dimensionsCheckCount = 0;
- var dimensionsCheckFunction = function () {
- dimensionsCheckCount++;
- var properties = Entities.getEntityProperties(entityID, ["dimensions", "registrationPoint", "rotation"]);
- if (!Vec3.equal(properties.dimensions, initialDimensions)) {
- position = adjustPositionPerBoundingBox(position, direction, properties.registrationPoint,
- properties.dimensions, properties.rotation);
- position = grid.snapToSurface(grid.snapToGrid(position, false, properties.dimensions),
- properties.dimensions);
Entities.editEntity(entityID, {
- position: position
- });
- selectionManager._update(false, this);
- } else if (dimensionsCheckCount < MAX_DIMENSIONS_CHECKS) {
- Script.setTimeout(dimensionsCheckFunction, DIMENSIONS_CHECK_INTERVAL);
+ visible: true,
+ dimensions: naturalDimensions
+ })
+ dimensionsCheckCallback();
+ // We want to update the selection manager again since the script has moved on without us.
+ selectionManager.clearSelections(this);
+ entityListTool.sendUpdate();
+ selectionManager.setSelections([entityID], this);
+ return;
}
- };
- Script.setTimeout(dimensionsCheckFunction, DIMENSIONS_CHECK_INTERVAL);
- }
- // Make sure the model entity is loaded before we try to figure out
- // its dimensions. We need to give ample time to load the entity.
- var MAX_LOADED_CHECKS = 100; // 100 * 100ms = 10 seconds.
- var LOADED_CHECK_INTERVAL = 100;
- var isLoadedCheckCount = 0;
- var entityIsLoadedCheck = function() {
- isLoadedCheckCount++;
- if (isLoadedCheckCount === MAX_LOADED_CHECKS || Entities.isLoaded(entityID)) {
- var naturalDimensions = Entities.getEntityProperties(entityID, "naturalDimensions").naturalDimensions;
-
- if (isLoadedCheckCount === MAX_LOADED_CHECKS) {
- console.log("Model entity failed to load in time: " + (MAX_LOADED_CHECKS * LOADED_CHECK_INTERVAL) + " ... setting dimensions to: " + JSON.stringify(naturalDimensions))
- }
-
- Entities.editEntity(entityID, {
- visible: true,
- dimensions: naturalDimensions
- })
- dimensionsCheckCallback();
- // We want to update the selection manager again since the script has moved on without us.
- selectionManager.clearSelections(this);
- entityListTool.sendUpdate();
- selectionManager.setSelections([entityID], this);
- return;
+ Script.setTimeout(entityIsLoadedCheck, LOADED_CHECK_INTERVAL);
}
- Script.setTimeout(entityIsLoadedCheck, LOADED_CHECK_INTERVAL);
- }
-
- var POST_ADJUST_ENTITY_TYPES = ["Model"];
- if (POST_ADJUST_ENTITY_TYPES.indexOf(properties.type) !== -1) {
- Script.setTimeout(entityIsLoadedCheck, LOADED_CHECK_INTERVAL);
+
+ var POST_ADJUST_ENTITY_TYPES = ["Model"];
+ if (POST_ADJUST_ENTITY_TYPES.indexOf(properties.type) !== -1) {
+ Script.setTimeout(entityIsLoadedCheck, LOADED_CHECK_INTERVAL);
+ }
+
+ SelectionManager.addEntity(entityID, false, this);
+ SelectionManager.saveProperties();
+ createApp.pushCommandForSelections([{
+ entityID: entityID,
+ properties: properties
+ }], [], true);
+
+ } else {
+ Window.notifyEditError("Can't create " + properties.type + ": " +
+ properties.type + " would be out of bounds.");
}
- SelectionManager.addEntity(entityID, false, this);
- SelectionManager.saveProperties();
- pushCommandForSelections([{
- entityID: entityID,
- properties: properties
- }], [], true);
+ selectionManager.clearSelections(this);
+ entityListTool.sendUpdate();
+ selectionManager.setSelections([entityID], this);
- } else {
- Window.notifyEditError("Can't create " + properties.type + ": " +
- properties.type + " would be out of bounds.");
+ Window.setFocus();
+
+ return entityID;
}
- selectionManager.clearSelections(this);
- entityListTool.sendUpdate();
- selectionManager.setSelections([entityID], this);
-
- Window.setFocus();
-
- return entityID;
- }
-
- function closeExistingDialogWindow() {
- if (dialogWindow) {
- dialogWindow.close();
- dialogWindow = null;
- }
- }
-
- function cleanup() {
- that.setActive(false);
- if (tablet) {
- tablet.removeButton(activeButton);
- }
- if (systemToolbar) {
- systemToolbar.removeButton(EDIT_TOGGLE_BUTTON);
- }
- }
-
- var buttonHandlers = {}; // only used to tablet mode
-
- function addButton(name, handler) {
- buttonHandlers[name] = handler;
- }
-
- var SHAPE_TYPE_NONE = 0;
- var SHAPE_TYPE_SIMPLE_HULL = 1;
- var SHAPE_TYPE_SIMPLE_COMPOUND = 2;
- var SHAPE_TYPE_STATIC_MESH = 3;
- var SHAPE_TYPE_BOX = 4;
- var SHAPE_TYPE_SPHERE = 5;
- var DYNAMIC_DEFAULT = false;
-
- var MATERIAL_MODE_UV = 0;
- var MATERIAL_MODE_PROJECTED = 1;
-
- function handleNewModelDialogResult(result) {
- if (result) {
- var url = result.url;
- var shapeType;
- switch (result.collisionShapeIndex) {
- case SHAPE_TYPE_SIMPLE_HULL:
- shapeType = "simple-hull";
- break;
- case SHAPE_TYPE_SIMPLE_COMPOUND:
- shapeType = "simple-compound";
- break;
- case SHAPE_TYPE_STATIC_MESH:
- shapeType = "static-mesh";
- break;
- case SHAPE_TYPE_BOX:
- shapeType = "box";
- break;
- case SHAPE_TYPE_SPHERE:
- shapeType = "sphere";
- break;
- default:
- shapeType = "none";
+ function closeExistingDialogWindow() {
+ if (dialogWindow) {
+ dialogWindow.close();
+ dialogWindow = null;
}
+ }
- var dynamic = result.dynamic !== null ? result.dynamic : DYNAMIC_DEFAULT;
- if (shapeType === "static-mesh" && dynamic) {
- // The prompt should prevent this case
- print("Error: model cannot be both static mesh and dynamic. This should never happen.");
- } else if (url) {
- createNewEntity({
- type: "Model",
- modelURL: url,
- shapeType: shapeType,
+ function cleanup() {
+ that.setActive(false);
+ if (tablet) {
+ tablet.removeButton(activeButton);
+ }
+ if (systemToolbar) {
+ systemToolbar.removeButton(EDIT_TOGGLE_BUTTON);
+ }
+ }
+
+ var buttonHandlers = {}; // only used to tablet mode
+
+ function addButton(name, handler) {
+ buttonHandlers[name] = handler;
+ }
+
+ var SHAPE_TYPE_NONE = 0;
+ var SHAPE_TYPE_SIMPLE_HULL = 1;
+ var SHAPE_TYPE_SIMPLE_COMPOUND = 2;
+ var SHAPE_TYPE_STATIC_MESH = 3;
+ var SHAPE_TYPE_BOX = 4;
+ var SHAPE_TYPE_SPHERE = 5;
+ var DYNAMIC_DEFAULT = false;
+
+ var MATERIAL_MODE_UV = 0;
+ var MATERIAL_MODE_PROJECTED = 1;
+
+ function handleNewModelDialogResult(result) {
+ if (result) {
+ var url = result.url;
+ var shapeType;
+ switch (result.collisionShapeIndex) {
+ case SHAPE_TYPE_SIMPLE_HULL:
+ shapeType = "simple-hull";
+ break;
+ case SHAPE_TYPE_SIMPLE_COMPOUND:
+ shapeType = "simple-compound";
+ break;
+ case SHAPE_TYPE_STATIC_MESH:
+ shapeType = "static-mesh";
+ break;
+ case SHAPE_TYPE_BOX:
+ shapeType = "box";
+ break;
+ case SHAPE_TYPE_SPHERE:
+ shapeType = "sphere";
+ break;
+ default:
+ shapeType = "none";
+ }
+
+ var dynamic = result.dynamic !== null ? result.dynamic : DYNAMIC_DEFAULT;
+ if (shapeType === "static-mesh" && dynamic) {
+ // The prompt should prevent this case
+ print("Error: model cannot be both static mesh and dynamic. This should never happen.");
+ } else if (url) {
+ createNewEntity({
+ type: "Model",
+ modelURL: url,
+ shapeType: shapeType,
+ grab: {
+ grabbable: result.grabbable
+ },
+ dynamic: dynamic,
+ useOriginalPivot: result.useOriginalPivot
+ });
+ }
+ }
+ }
+
+ function handleNewPolyVoxDialogResult(result) {
+ if (result) {
+ var initialShape = result.initialShapeIndex;
+ var volumeSizeX = parseInt(result.volumeSizeX);
+ var volumeSizeY = parseInt(result.volumeSizeY);
+ var volumeSizeZ = parseInt(result.volumeSizeZ);
+ var voxelSurfaceStyle = parseInt(result.surfaceStyleIndex);
+ var voxelPosition = Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0, z: volumeSizeZ * -1.6 }));
+
+ var polyVoxID = createNewEntity({
+ type: "PolyVox",
+ name: "terrain",
+ dimensions: {
+ x: volumeSizeX,
+ y: volumeSizeY,
+ z: volumeSizeZ
+ },
+ voxelVolumeSize: {
+ x: volumeSizeX,
+ y: volumeSizeY,
+ z: volumeSizeZ
+ },
+ xTextureURL: result.xTextureURL,
+ yTextureURL: result.yTextureURL,
+ zTextureURL: result.zTextureURL,
+ voxelSurfaceStyle: voxelSurfaceStyle,
+ collisionless: !(result.collisions),
grab: {
grabbable: result.grabbable
},
- dynamic: dynamic,
- useOriginalPivot: result.useOriginalPivot
});
- }
- }
- }
-
- function handleNewPolyVoxDialogResult(result) {
- if (result) {
- var initialShape = result.initialShapeIndex;
- var volumeSizeX = parseInt(result.volumeSizeX);
- var volumeSizeY = parseInt(result.volumeSizeY);
- var volumeSizeZ = parseInt(result.volumeSizeZ);
- var voxelSurfaceStyle = parseInt(result.surfaceStyleIndex);
- var voxelPosition = Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0, z: volumeSizeZ * -1.6 }));
-
- var polyVoxID = createNewEntity({
- type: "PolyVox",
- name: "terrain",
- dimensions: {
- x: volumeSizeX,
- y: volumeSizeY,
- z: volumeSizeZ
- },
- voxelVolumeSize: {
- x: volumeSizeX,
- y: volumeSizeY,
- z: volumeSizeZ
- },
- xTextureURL: result.xTextureURL,
- yTextureURL: result.yTextureURL,
- zTextureURL: result.zTextureURL,
- voxelSurfaceStyle: voxelSurfaceStyle,
- collisionless: !(result.collisions),
- grab: {
- grabbable: result.grabbable
- },
- });
-
- Entities.editEntity(polyVoxID, {
- position: voxelPosition
- });
-
- if (polyVoxID){
- switch (initialShape) {
- case 0:
- Entities.setVoxelsInCuboid(polyVoxID, {
- x: Math.round(volumeSizeX / 4),
- y: Math.round(volumeSizeY / 4),
- z: Math.round(volumeSizeZ / 4)
- }, {
- x: Math.round(volumeSizeX / 2.0),
- y: Math.round(volumeSizeY / 2.0),
- z: Math.round(volumeSizeZ / 2.0)
- }, 255);
- break;
- // Plane 1/4
- case 1:
- Entities.setVoxelsInCuboid(polyVoxID, {
- x: 0,
- y: 0,
- z: 0
- }, {
- x: volumeSizeX,
- y: Math.round(volumeSizeY / 4),
- z: volumeSizeZ
- }, 255);
- break;
- // Plane 3/4
- case 2:
- Entities.setVoxelsInCuboid(polyVoxID, {
- x: 0,
- y: 0,
- z: 0
- }, {
- x: volumeSizeX,
- y: Math.round(3 * volumeSizeY / 4),
- z: volumeSizeZ
- }, 255);
- break;
- // Single voxel at center
- case 3:
- Entities.setVoxel(polyVoxID, {
- x: Math.round(volumeSizeX / 2),
- y: Math.round(volumeSizeY / 2),
- z: Math.round(volumeSizeZ / 2)
- }, 255);
- break;
+
+ Entities.editEntity(polyVoxID, {
+ position: voxelPosition
+ });
+
+ if (polyVoxID){
+ switch (initialShape) {
+ case 0:
+ Entities.setVoxelsInCuboid(polyVoxID, {
+ x: Math.round(volumeSizeX / 4),
+ y: Math.round(volumeSizeY / 4),
+ z: Math.round(volumeSizeZ / 4)
+ }, {
+ x: Math.round(volumeSizeX / 2.0),
+ y: Math.round(volumeSizeY / 2.0),
+ z: Math.round(volumeSizeZ / 2.0)
+ }, 255);
+ break;
+ // Plane 1/4
+ case 1:
+ Entities.setVoxelsInCuboid(polyVoxID, {
+ x: 0,
+ y: 0,
+ z: 0
+ }, {
+ x: volumeSizeX,
+ y: Math.round(volumeSizeY / 4),
+ z: volumeSizeZ
+ }, 255);
+ break;
+ // Plane 3/4
+ case 2:
+ Entities.setVoxelsInCuboid(polyVoxID, {
+ x: 0,
+ y: 0,
+ z: 0
+ }, {
+ x: volumeSizeX,
+ y: Math.round(3 * volumeSizeY / 4),
+ z: volumeSizeZ
+ }, 255);
+ break;
+ // Single voxel at center
+ case 3:
+ Entities.setVoxel(polyVoxID, {
+ x: Math.round(volumeSizeX / 2),
+ y: Math.round(volumeSizeY / 2),
+ z: Math.round(volumeSizeZ / 2)
+ }, 255);
+ break;
+ }
}
}
}
- }
- function handleNewMaterialDialogResult(result) {
- if (result) {
- var materialURL = result.textInput;
- if (materialURL === "") {
- materialURL = "materialData";
+ function handleNewMaterialDialogResult(result) {
+ if (result) {
+ var materialURL = result.textInput;
+ if (materialURL === "") {
+ materialURL = "materialData";
+ }
+ //var materialMappingMode;
+ //switch (result.comboBox) {
+ // case MATERIAL_MODE_PROJECTED:
+ // materialMappingMode = "projected";
+ // break;
+ // default:
+ // shapeType = "uv";
+ //}
+ var materialData = "";
+ if (materialURL.startsWith("materialData")) {
+ materialData = JSON.stringify({
+ "materials": {}
+ });
+ }
+
+ var DEFAULT_LAYERED_MATERIAL_PRIORITY = 1;
+ if (materialURL) {
+ createNewEntity({
+ type: "Material",
+ materialURL: materialURL,
+ //materialMappingMode: materialMappingMode,
+ priority: DEFAULT_LAYERED_MATERIAL_PRIORITY,
+ materialData: materialData
+ });
+ }
}
- //var materialMappingMode;
- //switch (result.comboBox) {
- // case MATERIAL_MODE_PROJECTED:
- // materialMappingMode = "projected";
- // break;
- // default:
- // shapeType = "uv";
- //}
- var materialData = "";
- if (materialURL.startsWith("materialData")) {
- materialData = JSON.stringify({
- "materials": {}
- });
+ }
+
+ function fromQml(message) { // messages are {method, params}, like json-rpc. See also sendToQml.
+ var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
+ tablet.popFromStack();
+ switch (message.method) {
+ 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;
+ case "newPolyVoxDialogAdd":
+ handleNewPolyVoxDialogResult(message.params);
+ closeExistingDialogWindow();
+ break;
+ case "newPolyVoxDialogCancel":
+ closeExistingDialogWindow();
+ break;
+ }
+ }
+
+ var entitiesToDelete = [];
+ var deletedEntityTimer = null;
+ var DELETE_ENTITY_TIMER_TIMEOUT = 100;
+
+ function checkDeletedEntityAndUpdate(entityID) {
+ // Allow for multiple entity deletes before updating the entities selected.
+ entitiesToDelete.push(entityID);
+ if (deletedEntityTimer !== null) {
+ Script.clearTimeout(deletedEntityTimer);
+ }
+ deletedEntityTimer = Script.setTimeout(function () {
+ if (entitiesToDelete.length > 0) {
+ selectionManager.removeEntities(entitiesToDelete, this);
+ }
+ entityListTool.removeEntities(entitiesToDelete, selectionManager.selections);
+ entitiesToDelete = [];
+ deletedEntityTimer = null;
+ }, DELETE_ENTITY_TIMER_TIMEOUT);
+ }
+
+ function initialize() {
+ Script.scriptEnding.connect(cleanup);
+ Window.domainChanged.connect(function () {
+ if (isActive) {
+ tablet.gotoHomeScreen();
+ }
+ that.setActive(false);
+ that.clearEntityList();
+ checkEditPermissionsAndUpdate();
+ });
+
+ HMD.displayModeChanged.connect(function() {
+ if (isActive) {
+ tablet.gotoHomeScreen();
+ }
+ that.setActive(false);
+ });
+
+ Entities.canAdjustLocksChanged.connect(function (canAdjustLocks) {
+ if (isActive && !canAdjustLocks) {
+ that.setActive(false);
+ }
+ checkEditPermissionsAndUpdate();
+ });
+
+ Entities.canRezChanged.connect(checkEditPermissionsAndUpdate);
+ Entities.canRezTmpChanged.connect(checkEditPermissionsAndUpdate);
+ Entities.canRezCertifiedChanged.connect(checkEditPermissionsAndUpdate);
+ Entities.canRezTmpCertifiedChanged.connect(checkEditPermissionsAndUpdate);
+ var hasRezPermissions = (Entities.canRez() || Entities.canRezTmp() || Entities.canRezCertified() || Entities.canRezTmpCertified());
+
+ Entities.deletingEntity.connect(checkDeletedEntityAndUpdate);
+
+ var createButtonIconRsrc = (hasRezPermissions ? CREATE_ENABLED_ICON : CREATE_DISABLED_ICON);
+ tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
+ activeButton = tablet.addButton({
+ captionColor: hasRezPermissions ? "#ffffff" : "#888888",
+ icon: createButtonIconRsrc,
+ activeIcon: "icons/tablet-icons/edit-a.svg",
+ text: "CREATE",
+ sortOrder: 10
+ });
+ createButton = activeButton;
+ tablet.screenChanged.connect(function (type, url) {
+ var isGoingToHomescreenOnDesktop = (!shouldUseEditTabletApp() &&
+ (url === 'hifi/tablet/TabletHome.qml' || url === ''));
+ if (isActive && (type !== "QML" || url !== Script.resolvePath("qml/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()) ) {
+ Window.notifyEditError(INSUFFICIENT_PERMISSIONS_ERROR_MSG);
+ return;
+ }
+
+ that.toggle();
+ });
+
+ addButton("importEntitiesButton", function() {
+ importEntitiesFromFile();
+ });
+
+ addButton("importEntitiesFromUrlButton", function() {
+ importEntitiesFromUrl();
+ });
+
+ addButton("openAssetBrowserButton", function() {
+ Window.showAssetServer();
+ });
+ function createNewEntityDialogButtonCallback(entityType) {
+ return function() {
+ if (shouldUseEditTabletApp()) {
+ // tablet version of new-model dialog
+ var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
+ tablet.pushOntoStack(Script.resolvePath("qml/New" + entityType + "Dialog.qml"));
+ } else {
+ closeExistingDialogWindow();
+ var qmlPath = Script.resolvePath("qml/New" + entityType + "Window.qml");
+ var DIALOG_WINDOW_SIZE = { x: 500, y: 300 };
+ if( entityType === "PolyVox" ){
+ DIALOG_WINDOW_SIZE.x = 600;
+ DIALOG_WINDOW_SIZE.y = 500;
+ }
+ dialogWindow = Desktop.createWindow(qmlPath, {
+ title: "New " + entityType + " Entity",
+ additionalFlags: Desktop.ALWAYS_ON_TOP | Desktop.CLOSE_BUTTON_HIDES,
+ presentationMode: Desktop.PresentationMode.NATIVE,
+ size: DIALOG_WINDOW_SIZE,
+ visible: true
+ });
+ dialogWindow.fromQml.connect(fromQml);
+ }
+ };
}
- var DEFAULT_LAYERED_MATERIAL_PRIORITY = 1;
- if (materialURL) {
+ addButton("newModelButton", createNewEntityDialogButtonCallback("Model"));
+
+ addButton("newShapeButton", function () {
createNewEntity({
- type: "Material",
- materialURL: materialURL,
- //materialMappingMode: materialMappingMode,
- priority: DEFAULT_LAYERED_MATERIAL_PRIORITY,
- materialData: materialData
+ type: "Shape",
+ shape: "Cube",
});
- }
+ });
+
+ addButton("newLightButton", function () {
+ createNewEntity({
+ type: "Light",
+ });
+ });
+
+ addButton("newTextButton", function () {
+ createNewEntity({
+ type: "Text",
+ });
+ });
+
+ addButton("newImageButton", function () {
+ createNewEntity({
+ type: "Image",
+ });
+ });
+
+ addButton("newWebButton", function () {
+ createNewEntity({
+ type: "Web",
+ });
+ });
+
+ addButton("newZoneButton", function () {
+ createNewEntity({
+ type: "Zone",
+ });
+ });
+
+ addButton("newParticleButton", function () {
+ createNewEntity({
+ type: "ParticleEffect",
+ });
+ });
+
+ addButton("newMaterialButton", createNewEntityDialogButtonCallback("Material"));
+
+ addButton("newPolyVoxButton", createNewEntityDialogButtonCallback("PolyVox"));
+
+ var deactivateCreateIfDesktopWindowsHidden = function() {
+ if (!shouldUseEditTabletApp() && !entityListTool.isVisible() && !createToolsWindow.isVisible()) {
+ that.setActive(false);
+ }
+ };
+ entityListTool.interactiveWindowHidden.addListener(this, deactivateCreateIfDesktopWindowsHidden);
+ createToolsWindow.interactiveWindowHidden.addListener(this, deactivateCreateIfDesktopWindowsHidden);
+
+ that.setActive(false);
}
- }
- function fromQml(message) { // messages are {method, params}, like json-rpc. See also sendToQml.
- var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
- tablet.popFromStack();
- switch (message.method) {
- 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;
- case "newPolyVoxDialogAdd":
- handleNewPolyVoxDialogResult(message.params);
- closeExistingDialogWindow();
- break;
- case "newPolyVoxDialogCancel":
- closeExistingDialogWindow();
- break;
- }
- }
+ that.clearEntityList = function () {
+ entityListTool.clearEntityList();
+ };
- var entitiesToDelete = [];
- var deletedEntityTimer = null;
- var DELETE_ENTITY_TIMER_TIMEOUT = 100;
-
- function checkDeletedEntityAndUpdate(entityID) {
- // Allow for multiple entity deletes before updating the entities selected.
- entitiesToDelete.push(entityID);
- if (deletedEntityTimer !== null) {
- Script.clearTimeout(deletedEntityTimer);
- }
- deletedEntityTimer = Script.setTimeout(function () {
- if (entitiesToDelete.length > 0) {
- selectionManager.removeEntities(entitiesToDelete, this);
- }
- entityListTool.removeEntities(entitiesToDelete, selectionManager.selections);
- entitiesToDelete = [];
- deletedEntityTimer = null;
- }, DELETE_ENTITY_TIMER_TIMEOUT);
- }
-
- function initialize() {
- Script.scriptEnding.connect(cleanup);
- Window.domainChanged.connect(function () {
- if (isActive) {
+ that.toggle = function () {
+ that.setActive(!isActive);
+ if (!isActive) {
tablet.gotoHomeScreen();
}
- that.setActive(false);
- that.clearEntityList();
- checkEditPermissionsAndUpdate();
- });
+ };
- HMD.displayModeChanged.connect(function() {
- if (isActive) {
- tablet.gotoHomeScreen();
+ that.setActive = function (active) {
+ ContextOverlay.enabled = !active;
+ Settings.setValue(EDIT_SETTING, active);
+ if (active) {
+ Controller.captureEntityClickEvents();
+ } else {
+ Controller.releaseEntityClickEvents();
+
+ closeExistingDialogWindow();
}
- that.setActive(false);
- });
-
- Entities.canAdjustLocksChanged.connect(function (canAdjustLocks) {
- if (isActive && !canAdjustLocks) {
- that.setActive(false);
+ if (active === isActive) {
+ return;
}
- checkEditPermissionsAndUpdate();
- });
-
- Entities.canRezChanged.connect(checkEditPermissionsAndUpdate);
- Entities.canRezTmpChanged.connect(checkEditPermissionsAndUpdate);
- Entities.canRezCertifiedChanged.connect(checkEditPermissionsAndUpdate);
- Entities.canRezTmpCertifiedChanged.connect(checkEditPermissionsAndUpdate);
- var hasRezPermissions = (Entities.canRez() || Entities.canRezTmp() || Entities.canRezCertified() || Entities.canRezTmpCertified());
-
- Entities.deletingEntity.connect(checkDeletedEntityAndUpdate);
-
- var createButtonIconRsrc = (hasRezPermissions ? CREATE_ENABLED_ICON : CREATE_DISABLED_ICON);
- tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
- activeButton = tablet.addButton({
- captionColor: hasRezPermissions ? "#ffffff" : "#888888",
- icon: createButtonIconRsrc,
- activeIcon: "icons/tablet-icons/edit-a.svg",
- text: "CREATE",
- sortOrder: 10
- });
- createButton = activeButton;
- tablet.screenChanged.connect(function (type, url) {
- var isGoingToHomescreenOnDesktop = (!shouldUseEditTabletApp() &&
- (url === 'hifi/tablet/TabletHome.qml' || url === ''));
- if (isActive && (type !== "QML" || url !== Script.resolvePath("qml/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()) ) {
+ if (active && !Entities.canRez() && !Entities.canRezTmp() && !Entities.canRezCertified() && !Entities.canRezTmpCertified()) {
Window.notifyEditError(INSUFFICIENT_PERMISSIONS_ERROR_MSG);
return;
}
+ Messages.sendLocalMessage("edit-events", JSON.stringify({
+ enabled: active
+ }));
+ print("Setting isActive: " + active);
+ isActive = active;
+ activeButton.editProperties({isActive: isActive});
+ undoHistory.setEnabled(isActive);
- that.toggle();
- });
+ editVoxels.setActive(active);
- addButton("importEntitiesButton", function() {
- importEntitiesFromFile();
- });
+ var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
- addButton("importEntitiesFromUrlButton", function() {
- importEntitiesFromUrl();
- });
-
- addButton("openAssetBrowserButton", function() {
- Window.showAssetServer();
- });
- function createNewEntityDialogButtonCallback(entityType) {
- return function() {
- if (shouldUseEditTabletApp()) {
- // tablet version of new-model dialog
- var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
- tablet.pushOntoStack(Script.resolvePath("qml/New" + entityType + "Dialog.qml"));
- } else {
- closeExistingDialogWindow();
- var qmlPath = Script.resolvePath("qml/New" + entityType + "Window.qml");
- var DIALOG_WINDOW_SIZE = { x: 500, y: 300 };
- if( entityType === "PolyVox" ){
- DIALOG_WINDOW_SIZE.x = 600;
- DIALOG_WINDOW_SIZE.y = 500;
- }
- dialogWindow = Desktop.createWindow(qmlPath, {
- title: "New " + entityType + " Entity",
- additionalFlags: Desktop.ALWAYS_ON_TOP | Desktop.CLOSE_BUTTON_HIDES,
- presentationMode: Desktop.PresentationMode.NATIVE,
- size: DIALOG_WINDOW_SIZE,
- visible: true
- });
- dialogWindow.fromQml.connect(fromQml);
- }
- };
- }
-
- addButton("newModelButton", createNewEntityDialogButtonCallback("Model"));
-
- addButton("newShapeButton", function () {
- createNewEntity({
- type: "Shape",
- shape: "Cube",
- });
- });
-
- addButton("newLightButton", function () {
- createNewEntity({
- type: "Light",
- });
- });
-
- addButton("newTextButton", function () {
- createNewEntity({
- type: "Text",
- });
- });
-
- addButton("newImageButton", function () {
- createNewEntity({
- type: "Image",
- });
- });
-
- addButton("newWebButton", function () {
- createNewEntity({
- type: "Web",
- });
- });
-
- addButton("newZoneButton", function () {
- createNewEntity({
- type: "Zone",
- });
- });
-
- addButton("newParticleButton", function () {
- createNewEntity({
- type: "ParticleEffect",
- });
- });
-
- addButton("newMaterialButton", createNewEntityDialogButtonCallback("Material"));
-
- addButton("newPolyVoxButton", createNewEntityDialogButtonCallback("PolyVox"));
-
- var deactivateCreateIfDesktopWindowsHidden = function() {
- if (!shouldUseEditTabletApp() && !entityListTool.isVisible() && !createToolsWindow.isVisible()) {
- that.setActive(false);
- }
- };
- entityListTool.interactiveWindowHidden.addListener(this, deactivateCreateIfDesktopWindowsHidden);
- createToolsWindow.interactiveWindowHidden.addListener(this, deactivateCreateIfDesktopWindowsHidden);
-
- that.setActive(false);
- }
-
- that.clearEntityList = function () {
- entityListTool.clearEntityList();
- };
-
- that.toggle = function () {
- that.setActive(!isActive);
- if (!isActive) {
- tablet.gotoHomeScreen();
- }
- };
-
- that.setActive = function (active) {
- ContextOverlay.enabled = !active;
- Settings.setValue(EDIT_SETTING, active);
- if (active) {
- Controller.captureEntityClickEvents();
- } else {
- Controller.releaseEntityClickEvents();
-
- closeExistingDialogWindow();
- }
- if (active === isActive) {
- return;
- }
- if (active && !Entities.canRez() && !Entities.canRezTmp() && !Entities.canRezCertified() && !Entities.canRezTmpCertified()) {
- Window.notifyEditError(INSUFFICIENT_PERMISSIONS_ERROR_MSG);
- return;
- }
- Messages.sendLocalMessage("edit-events", JSON.stringify({
- enabled: active
- }));
- isActive = active;
- activeButton.editProperties({isActive: isActive});
- undoHistory.setEnabled(isActive);
-
- editVoxels.setActive(active);
-
- var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
-
- if (!isActive) {
- entityListTool.setVisible(false);
- gridTool.setVisible(false);
- grid.setEnabled(false);
- propertiesTool.setVisible(false);
- selectionManager.clearSelections(this);
- cameraManager.disable();
- selectionDisplay.disableTriggerMapping();
- tablet.landscape = false;
- Controller.disableMapping(CONTROLLER_MAPPING_NAME);
- } else {
- if (shouldUseEditTabletApp()) {
- tablet.loadQMLSource(Script.resolvePath("qml/Edit.qml"), true);
+ if (!isActive) {
+ entityListTool.setVisible(false);
+ gridTool.setVisible(false);
+ grid.setEnabled(false);
+ propertiesTool.setVisible(false);
+ selectionManager.clearSelections(this);
+ cameraManager.disable();
+ selectionDisplay.disableTriggerMapping();
+ tablet.landscape = false;
+ Controller.disableMapping(CONTROLLER_MAPPING_NAME);
} else {
- // make other apps inactive while in desktop mode
- tablet.gotoHomeScreen();
+ if (shouldUseEditTabletApp()) {
+ tablet.loadQMLSource(Script.resolvePath("qml/Edit.qml"), true);
+ } else {
+ // make other apps inactive while in desktop mode
+ tablet.gotoHomeScreen();
+ }
+ UserActivityLogger.enabledEdit();
+ entityListTool.setVisible(true);
+ entityListTool.sendUpdate();
+ gridTool.setVisible(true);
+ grid.setEnabled(true);
+ propertiesTool.setVisible(true);
+ selectionDisplay.enableTriggerMapping();
+ print("starting tablet in landscape mode");
+ tablet.landscape = true;
+ Controller.enableMapping(CONTROLLER_MAPPING_NAME);
+ // Not sure what the following was meant to accomplish, but it currently causes
+ // everybody else to think that Interface has lost focus overall. fogbugzid:558
+ // Window.setFocus();
}
- UserActivityLogger.enabledEdit();
- entityListTool.setVisible(true);
- entityListTool.sendUpdate();
- gridTool.setVisible(true);
- grid.setEnabled(true);
- propertiesTool.setVisible(true);
- selectionDisplay.enableTriggerMapping();
- print("starting tablet in landscape mode");
- tablet.landscape = true;
- Controller.enableMapping(CONTROLLER_MAPPING_NAME);
- // Not sure what the following was meant to accomplish, but it currently causes
- // everybody else to think that Interface has lost focus overall. fogbugzid:558
- // Window.setFocus();
- }
- entityIconOverlayManager.setVisible(isActive && Menu.isOptionChecked(MENU_SHOW_ICONS_IN_CREATE_MODE));
- };
+ entityIconOverlayManager.setVisible(isActive && Menu.isOptionChecked(MENU_SHOW_ICONS_IN_CREATE_MODE));
+ };
- initialize();
- return that;
-})();
+ initialize();
+ return that;
+ })();
-var selectedEntityID;
-var orientation;
-var intersection;
+ var selectedEntityID;
+ var orientation;
+ var intersection;
-function rayPlaneIntersection(pickRay, point, normal) { //
- //
- // This version of the test returns the intersection of a line with a plane
- //
- var collides = Vec3.dot(pickRay.direction, normal);
+ createApp.rayPlaneIntersection = function(pickRay, point, normal) { //
+ //
+ // This version of the test returns the intersection of a line with a plane
+ //
+ var collides = Vec3.dot(pickRay.direction, normal);
- var d = -Vec3.dot(point, normal);
- var t = -(Vec3.dot(pickRay.origin, normal) + d) / collides;
+ var d = -Vec3.dot(point, normal);
+ var t = -(Vec3.dot(pickRay.origin, normal) + d) / collides;
- return Vec3.sum(pickRay.origin, Vec3.multiply(pickRay.direction, t));
-}
-
-function rayPlaneIntersection2(pickRay, point, normal) {
- //
- // This version of the test returns false if the ray is directed away from the plane
- //
- var collides = Vec3.dot(pickRay.direction, normal);
- var d = -Vec3.dot(point, normal);
- var t = -(Vec3.dot(pickRay.origin, normal) + d) / collides;
- if (t < 0.0) {
- return false;
- } else {
return Vec3.sum(pickRay.origin, Vec3.multiply(pickRay.direction, t));
}
-}
-function findClickedEntity(event) {
- var pickZones = event.isControl;
-
- if (pickZones) {
- Entities.setZonesArePickable(true);
- }
-
- var pickRay = Camera.computePickRay(event.x, event.y);
- var tabletIDs = getMainTabletIDs();
- if (tabletIDs.length > 0) {
- var overlayResult = Overlays.findRayIntersection(pickRay, true, tabletIDs);
- if (overlayResult.intersects) {
- return null;
- }
- }
-
- var entityResult = Entities.findRayIntersection(pickRay, true); // want precision picking
- var iconResult = entityIconOverlayManager.findRayIntersection(pickRay);
- iconResult.accurate = true;
-
- if (pickZones) {
- Entities.setZonesArePickable(false);
- }
-
- var result;
- if (expectingRotateAsClickedSurface) {
- if (!SelectionManager.hasSelection() || !SelectionManager.hasUnlockedSelection()) {
- audioFeedback.rejection();
- Window.notifyEditError("You have nothing selected, or the selection is locked.");
- expectingRotateAsClickedSurface = false;
- } else {
- //Rotate Selection according the Surface Normal
- var normalRotation = Quat.lookAtSimple(Vec3.ZERO, Vec3.multiply(entityResult.surfaceNormal, -1));
- selectionDisplay.rotateSelection(normalRotation);
- //Translate Selection according the clicked Surface
- var distanceFromSurface;
- if (selectionDisplay.getSpaceMode() === "world"){
- distanceFromSurface = SelectionManager.worldDimensions.z / 2;
- } else {
- distanceFromSurface = SelectionManager.localDimensions.z / 2;
- }
- selectionDisplay.moveSelection(Vec3.sum(entityResult.intersection, Vec3.multiplyQbyV( normalRotation, {"x": 0.0, "y":0.0, "z": distanceFromSurface})));
- selectionManager._update(false, this);
- pushCommandForSelections();
- expectingRotateAsClickedSurface = false;
- audioFeedback.action();
- }
- keepSelectedOnNextClick = true;
- return null;
- } else {
- if (iconResult.intersects) {
- result = iconResult;
- } else if (entityResult.intersects) {
- result = entityResult;
- } else {
- return null;
- }
-
- if (!result.accurate) {
- return null;
- }
-
- var foundEntity = result.entityID;
- return {
- pickRay: pickRay,
- entityID: foundEntity,
- intersection: result.intersection
- };
- }
-}
-
-// Handles selections on overlays while in edit mode by querying entities from
-// entityIconOverlayManager.
-function handleOverlaySelectionToolUpdates(channel, message, sender) {
- var wantDebug = false;
- if (sender !== MyAvatar.sessionUUID || channel !== 'entityToolUpdates')
- return;
-
- var data = JSON.parse(message);
-
- if (data.method === "selectOverlay") {
- if (!selectionDisplay.triggered() || selectionDisplay.triggeredHand === data.hand) {
- if (wantDebug) {
- print("setting selection to overlay " + data.overlayID);
- }
- var entity = entityIconOverlayManager.findEntity(data.overlayID);
-
- if (entity !== null) {
- if (hmdMultiSelectMode) {
- selectionManager.addEntity(entity, true, this);
- } else {
- selectionManager.setSelections([entity], this);
- }
- }
- }
- }
-}
-
-function handleMessagesReceived(channel, message, sender) {
- switch( channel ){
- case 'entityToolUpdates': {
- handleOverlaySelectionToolUpdates( channel, message, sender );
- break;
- }
- default: {
- return;
- }
- }
-}
-
-Messages.subscribe("entityToolUpdates");
-Messages.messageReceived.connect(handleMessagesReceived);
-
-var mouseHasMovedSincePress = false;
-var mousePressStartTime = 0;
-var mousePressStartPosition = {
- x: 0,
- y: 0
-};
-var mouseDown = false;
-
-function mousePressEvent(event) {
- mouseDown = true;
- mousePressStartPosition = {
- x: event.x,
- y: event.y
- };
- mousePressStartTime = Date.now();
- mouseHasMovedSincePress = false;
- mouseCapturedByTool = false;
-
- if (propertyMenu.mousePressEvent(event) || progressDialog.mousePressEvent(event)) {
- mouseCapturedByTool = true;
- return;
- }
- if (isActive) {
- if (cameraManager.mousePressEvent(event) || selectionDisplay.mousePressEvent(event)) {
- // Event handled; do nothing.
- return;
- }
- }
-}
-
-var mouseCapturedByTool = false;
-var lastMousePosition = null;
-var CLICK_TIME_THRESHOLD = 500 * 1000; // 500 ms
-var CLICK_MOVE_DISTANCE_THRESHOLD = 20;
-var IDLE_MOUSE_TIMEOUT = 200;
-
-var lastMouseMoveEvent = null;
-
-function mouseMoveEventBuffered(event) {
- lastMouseMoveEvent = event;
-}
-
-function mouseMove(event) {
- if (mouseDown && !mouseHasMovedSincePress) {
- var timeSincePressMicro = Date.now() - mousePressStartTime;
-
- var dX = mousePressStartPosition.x - event.x;
- var dY = mousePressStartPosition.y - event.y;
- var sqDist = (dX * dX) + (dY * dY);
-
- // If less than CLICK_TIME_THRESHOLD has passed since the mouse click AND the mouse has moved
- // less than CLICK_MOVE_DISTANCE_THRESHOLD distance, then don't register this as a mouse move
- // yet. The goal is to provide mouse clicks that are more lenient to small movements.
- if (timeSincePressMicro < CLICK_TIME_THRESHOLD && sqDist < CLICK_MOVE_DISTANCE_THRESHOLD) {
- return;
- }
- mouseHasMovedSincePress = true;
- }
-
- if (!isActive) {
- return;
- }
-
- // allow the selectionDisplay and cameraManager to handle the event first, if it doesn't handle it, then do our own thing
- if (selectionDisplay.mouseMoveEvent(event) || propertyMenu.mouseMoveEvent(event) || cameraManager.mouseMoveEvent(event)) {
- return;
- }
-
- lastMousePosition = {
- x: event.x,
- y: event.y
- };
-}
-
-function mouseReleaseEvent(event) {
- mouseDown = false;
-
- if (lastMouseMoveEvent) {
- mouseMove(lastMouseMoveEvent);
- lastMouseMoveEvent = null;
- }
- if (propertyMenu.mouseReleaseEvent(event)) {
- return true;
- }
- if (isActive && selectionManager.hasSelection()) {
- tooltip.show(false);
- }
- if (mouseCapturedByTool) {
-
- return;
- }
-
- cameraManager.mouseReleaseEvent(event);
-
- if (!mouseHasMovedSincePress) {
- mouseClickEvent(event);
- }
-}
-
-function wasTabletOrEditHandleClicked(event) {
- var rayPick = Camera.computePickRay(event.x, event.y);
- var result = Overlays.findRayIntersection(rayPick, true);
- if (result.intersects) {
- var overlayID = result.overlayID;
- var tabletIDs = getMainTabletIDs();
- if (tabletIDs.indexOf(overlayID) >= 0) {
- return true;
- } else if (selectionDisplay.isEditHandle(overlayID)) {
- return true;
- }
- }
- return false;
-}
-
-function mouseClickEvent(event) {
- var wantDebug = false;
- var result, properties, tabletClicked;
- if (isActive && event.isLeftButton) {
- result = findClickedEntity(event);
- var tabletOrEditHandleClicked = wasTabletOrEditHandleClicked(event);
- if (tabletOrEditHandleClicked) {
- return;
- }
-
- if (result === null || result === undefined) {
- if (!event.isShifted) {
- if (!keepSelectedOnNextClick) {
- selectionManager.clearSelections(this);
- }
- keepSelectedOnNextClick = false;
- }
- return;
- }
- toolBar.setActive(true);
- var pickRay = result.pickRay;
- var foundEntity = result.entityID;
- if (HMD.tabletID && foundEntity === HMD.tabletID) {
- return;
- }
- properties = Entities.getEntityProperties(foundEntity);
- 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
+ createApp.rayPlaneIntersection2 = function(pickRay, point, normal) {
//
- // |X-A| = (P-A).B
- // X === A + ((P-A).B)B
- // d = |P-X|
+ // This version of the test returns false if the ray is directed away from the plane
+ //
+ var collides = Vec3.dot(pickRay.direction, normal);
+ var d = -Vec3.dot(point, normal);
+ var t = -(Vec3.dot(pickRay.origin, normal) + d) / collides;
+ if (t < 0.0) {
+ return false;
+ } else {
+ return Vec3.sum(pickRay.origin, Vec3.multiply(pickRay.direction, t));
+ }
+ }
- var A = pickRay.origin;
- var B = Vec3.normalize(pickRay.direction);
- var P = properties.position;
+ function findClickedEntity(event) {
+ var pickZones = event.isControl;
- var x = Vec3.dot(Vec3.subtract(P, A), B);
+ if (pickZones) {
+ Entities.setZonesArePickable(true);
+ }
- 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 && selectionManager.editEnabled) {
- selectedEntityID = foundEntity;
- orientation = MyAvatar.orientation;
- intersection = rayPlaneIntersection(pickRay, P, Quat.getForward(orientation));
-
- if (!event.isShifted) {
- selectionManager.setSelections([foundEntity], this);
- } else {
- selectionManager.addEntity(foundEntity, true, this);
- }
- selectionManager.saveProperties();
-
- 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));
+ var pickRay = Camera.computePickRay(event.x, event.y);
+ var tabletIDs = getMainTabletIDs();
+ if (tabletIDs.length > 0) {
+ var overlayResult = Overlays.findRayIntersection(pickRay, true, tabletIDs);
+ if (overlayResult.intersects) {
+ return null;
}
}
- } else if (event.isRightButton) {
- result = findClickedEntity(event);
- if (result) {
- if (SHOULD_SHOW_PROPERTY_MENU !== true) {
+
+ var entityResult = Entities.findRayIntersection(pickRay, true); // want precision picking
+ var iconResult = entityIconOverlayManager.findRayIntersection(pickRay);
+ iconResult.accurate = true;
+
+ if (pickZones) {
+ Entities.setZonesArePickable(false);
+ }
+
+ var result;
+ if (expectingRotateAsClickedSurface) {
+ if (!SelectionManager.hasSelection() || !SelectionManager.hasUnlockedSelection()) {
+ audioFeedback.rejection();
+ Window.notifyEditError("You have nothing selected, or the selection is locked.");
+ expectingRotateAsClickedSurface = false;
+ } else {
+ //Rotate Selection according the Surface Normal
+ var normalRotation = Quat.lookAtSimple(Vec3.ZERO, Vec3.multiply(entityResult.surfaceNormal, -1));
+ selectionDisplay.rotateSelection(normalRotation);
+ //Translate Selection according the clicked Surface
+ var distanceFromSurface;
+ if (selectionDisplay.getSpaceMode() === "world"){
+ distanceFromSurface = SelectionManager.worldDimensions.z / 2;
+ } else {
+ distanceFromSurface = SelectionManager.localDimensions.z / 2;
+ }
+ selectionDisplay.moveSelection(Vec3.sum(entityResult.intersection, Vec3.multiplyQbyV( normalRotation, {"x": 0.0, "y":0.0, "z": distanceFromSurface})));
+ selectionManager._update(false, this);
+ createApp.pushCommandForSelections();
+ expectingRotateAsClickedSurface = false;
+ audioFeedback.action();
+ }
+ keepSelectedOnNextClick = true;
+ return null;
+ } else {
+ if (iconResult.intersects) {
+ result = iconResult;
+ } else if (entityResult.intersects) {
+ result = entityResult;
+ } else {
+ return null;
+ }
+
+ if (!result.accurate) {
+ return null;
+ }
+
+ var foundEntity = result.entityID;
+ return {
+ pickRay: pickRay,
+ entityID: foundEntity,
+ intersection: result.intersection
+ };
+ }
+ }
+
+ // Handles selections on overlays while in edit mode by querying entities from
+ // entityIconOverlayManager.
+ function handleOverlaySelectionToolUpdates(channel, message, sender) {
+ var wantDebug = false;
+ if (sender !== MyAvatar.sessionUUID || channel !== 'entityToolUpdates')
+ return;
+
+ var data = JSON.parse(message);
+
+ if (data.method === "selectOverlay") {
+ if (!selectionDisplay.triggered() || selectionDisplay.triggeredHand === data.hand) {
+ if (wantDebug) {
+ print("setting selection to overlay " + data.overlayID);
+ }
+ var entity = entityIconOverlayManager.findEntity(data.overlayID);
+
+ if (entity !== null) {
+ if (hmdMultiSelectMode) {
+ selectionManager.addEntity(entity, true, this);
+ } else {
+ selectionManager.setSelections([entity], this);
+ }
+ }
+ }
+ }
+ }
+
+ function handleMessagesReceived(channel, message, sender) {
+ switch( channel ){
+ case 'entityToolUpdates': {
+ handleOverlaySelectionToolUpdates( channel, message, sender );
+ break;
+ }
+ default: {
return;
}
- properties = Entities.getEntityProperties(result.entityID);
- if (properties.marketplaceID) {
- propertyMenu.marketplaceID = properties.marketplaceID;
- propertyMenu.updateMenuItemText(showMenuItem, "Show in Marketplace");
- } else {
- propertyMenu.marketplaceID = null;
- propertyMenu.updateMenuItemText(showMenuItem, "No marketplace info");
- }
- propertyMenu.setPosition(event.x, event.y);
- propertyMenu.show();
- } else {
- propertyMenu.hide();
}
}
-}
-Controller.mousePressEvent.connect(mousePressEvent);
-Controller.mouseMoveEvent.connect(mouseMoveEventBuffered);
-Controller.mouseReleaseEvent.connect(mouseReleaseEvent);
+ Messages.subscribe("entityToolUpdates");
+ Messages.messageReceived.connect(handleMessagesReceived);
+ var mouseHasMovedSincePress = false;
+ var mousePressStartTime = 0;
+ var mousePressStartPosition = {
+ x: 0,
+ y: 0
+ };
+ var mouseDown = false;
-// In order for editVoxels and editModels to play nice together, they each check to see if a "delete" menu item already
-// exists. If it doesn't they add it. If it does they don't. They also only delete the menu item if they were the one that
-// added it.
-var originalLightsArePickable = Entities.getLightsArePickable();
+ function mousePressEvent(event) {
+ mouseDown = true;
+ mousePressStartPosition = {
+ x: event.x,
+ y: event.y
+ };
+ mousePressStartTime = Date.now();
+ mouseHasMovedSincePress = false;
+ mouseCapturedByTool = false;
-function setupModelMenus() {
- Menu.addMenuItem({
- menuName: "Edit",
- menuItemName: "Undo",
- shortcutKey: 'Ctrl+Z',
- position: 0,
- });
- Menu.addMenuItem({
- menuName: "Edit",
- menuItemName: "Redo",
- shortcutKey: 'Ctrl+Y',
- position: 1,
- });
-
- Menu.addMenuItem({
- menuName: "Edit",
- menuItemName: MENU_CREATE_SEPARATOR,
- isSeparator: true
- });
- Menu.addMenuItem({
- menuName: "Edit",
- menuItemName: MENU_IMPORT_FROM_FILE,
- afterItem: MENU_CREATE_SEPARATOR
- });
- Menu.addMenuItem({
- menuName: "Edit",
- menuItemName: MENU_IMPORT_FROM_URL,
- afterItem: MENU_IMPORT_FROM_FILE
- });
-
- Menu.addMenu(SUBMENU_ENTITY_EDITOR_PREFERENCES);
-
- Menu.addMenuItem({
- menuName: SUBMENU_ENTITY_EDITOR_PREFERENCES,
- menuItemName: MENU_CREATE_ENTITIES_GRABBABLE,
- position: 0,
- isCheckable: true,
- isChecked: Settings.getValue(SETTING_EDIT_PREFIX + MENU_CREATE_ENTITIES_GRABBABLE, false)
- });
- Menu.addMenuItem({
- menuName: SUBMENU_ENTITY_EDITOR_PREFERENCES,
- menuItemName: MENU_ALLOW_SELECTION_LARGE,
- afterItem: MENU_CREATE_ENTITIES_GRABBABLE,
- isCheckable: true,
- isChecked: Settings.getValue(SETTING_EDIT_PREFIX + MENU_ALLOW_SELECTION_LARGE, true)
- });
- Menu.addMenuItem({
- menuName: SUBMENU_ENTITY_EDITOR_PREFERENCES,
- menuItemName: MENU_ALLOW_SELECTION_SMALL,
- afterItem: MENU_ALLOW_SELECTION_LARGE,
- isCheckable: true,
- isChecked: Settings.getValue(SETTING_EDIT_PREFIX + MENU_ALLOW_SELECTION_SMALL, true)
- });
- Menu.addMenuItem({
- menuName: SUBMENU_ENTITY_EDITOR_PREFERENCES,
- menuItemName: MENU_ALLOW_SELECTION_LIGHTS,
- afterItem: MENU_ALLOW_SELECTION_SMALL,
- isCheckable: true,
- isChecked: Settings.getValue(SETTING_EDIT_PREFIX + MENU_ALLOW_SELECTION_LIGHTS, false)
- });
- Menu.addMenuItem({
- menuName: SUBMENU_ENTITY_EDITOR_PREFERENCES,
- menuItemName: MENU_AUTO_FOCUS_ON_SELECT,
- afterItem: MENU_ALLOW_SELECTION_LIGHTS,
- isCheckable: true,
- isChecked: Settings.getValue(SETTING_AUTO_FOCUS_ON_SELECT) === "true"
- });
- Menu.addMenuItem({
- menuName: SUBMENU_ENTITY_EDITOR_PREFERENCES,
- menuItemName: MENU_EASE_ON_FOCUS,
- afterItem: MENU_AUTO_FOCUS_ON_SELECT,
- isCheckable: true,
- isChecked: Settings.getValue(SETTING_EASE_ON_FOCUS) === "true"
- });
- Menu.addMenuItem({
- menuName: SUBMENU_ENTITY_EDITOR_PREFERENCES,
- menuItemName: MENU_SHOW_ICONS_IN_CREATE_MODE,
- afterItem: MENU_EASE_ON_FOCUS,
- isCheckable: true,
- isChecked: Settings.getValue(SETTING_SHOW_LIGHTS_AND_PARTICLES_IN_EDIT_MODE) !== "false"
- });
- Menu.addMenuItem({
- menuName: SUBMENU_ENTITY_EDITOR_PREFERENCES,
- menuItemName: MENU_ENTITY_LIST_DEFAULT_RADIUS,
- afterItem: MENU_SHOW_ICONS_IN_CREATE_MODE
- });
-
- Entities.setLightsArePickable(false);
-}
-
-setupModelMenus(); // do this when first running our script.
-
-function cleanupModelMenus() {
- Menu.removeMenuItem("Edit", "Undo");
- Menu.removeMenuItem("Edit", "Redo");
-
- Menu.removeMenuItem(SUBMENU_ENTITY_EDITOR_PREFERENCES, MENU_ALLOW_SELECTION_LARGE);
- Menu.removeMenuItem(SUBMENU_ENTITY_EDITOR_PREFERENCES, MENU_ALLOW_SELECTION_SMALL);
- Menu.removeMenuItem(SUBMENU_ENTITY_EDITOR_PREFERENCES, MENU_ALLOW_SELECTION_LIGHTS);
- Menu.removeMenuItem(SUBMENU_ENTITY_EDITOR_PREFERENCES, MENU_AUTO_FOCUS_ON_SELECT);
- Menu.removeMenuItem(SUBMENU_ENTITY_EDITOR_PREFERENCES, MENU_EASE_ON_FOCUS);
- Menu.removeMenuItem(SUBMENU_ENTITY_EDITOR_PREFERENCES, MENU_SHOW_ICONS_IN_CREATE_MODE);
- Menu.removeMenuItem(SUBMENU_ENTITY_EDITOR_PREFERENCES, MENU_CREATE_ENTITIES_GRABBABLE);
- Menu.removeMenuItem(SUBMENU_ENTITY_EDITOR_PREFERENCES, MENU_ENTITY_LIST_DEFAULT_RADIUS);
- Menu.removeMenu(SUBMENU_ENTITY_EDITOR_PREFERENCES);
- Menu.removeMenuItem("Edit", MENU_IMPORT_FROM_URL);
- Menu.removeMenuItem("Edit", MENU_IMPORT_FROM_FILE);
- Menu.removeSeparator("Edit", MENU_CREATE_SEPARATOR);
-}
-
-Script.scriptEnding.connect(function () {
- toolBar.setActive(false);
- Settings.setValue(SETTING_AUTO_FOCUS_ON_SELECT, Menu.isOptionChecked(MENU_AUTO_FOCUS_ON_SELECT));
- Settings.setValue(SETTING_EASE_ON_FOCUS, Menu.isOptionChecked(MENU_EASE_ON_FOCUS));
- Settings.setValue(SETTING_SHOW_LIGHTS_AND_PARTICLES_IN_EDIT_MODE, Menu.isOptionChecked(MENU_SHOW_ICONS_IN_CREATE_MODE));
-
- Settings.setValue(SETTING_EDIT_PREFIX + MENU_ALLOW_SELECTION_LARGE, Menu.isOptionChecked(MENU_ALLOW_SELECTION_LARGE));
- Settings.setValue(SETTING_EDIT_PREFIX + MENU_ALLOW_SELECTION_SMALL, Menu.isOptionChecked(MENU_ALLOW_SELECTION_SMALL));
- Settings.setValue(SETTING_EDIT_PREFIX + MENU_ALLOW_SELECTION_LIGHTS, Menu.isOptionChecked(MENU_ALLOW_SELECTION_LIGHTS));
-
-
- progressDialog.cleanup();
- cleanupModelMenus();
- tooltip.cleanup();
- selectionDisplay.cleanup();
- entityShapeVisualizer.cleanup();
- Entities.setLightsArePickable(originalLightsArePickable);
-
- Overlays.deleteOverlay(importingSVOImageOverlay);
- Overlays.deleteOverlay(importingSVOTextOverlay);
-
- Controller.keyReleaseEvent.disconnect(keyReleaseEvent);
- Controller.keyPressEvent.disconnect(keyPressEvent);
-
- Controller.mousePressEvent.disconnect(mousePressEvent);
- Controller.mouseMoveEvent.disconnect(mouseMoveEventBuffered);
- Controller.mouseReleaseEvent.disconnect(mouseReleaseEvent);
-
- Messages.messageReceived.disconnect(handleMessagesReceived);
- Messages.unsubscribe("entityToolUpdates");
- createButton = null;
-});
-
-var lastOrientation = Camera.orientation;
-var lastPosition = Camera.position;
-
-// Do some stuff regularly, like check for placement of various overlays
-Script.update.connect(function (deltaTime) {
- progressDialog.move();
- selectionDisplay.checkControllerMove();
- var dOrientation = Math.abs(Quat.dot(Camera.orientation, lastOrientation) - 1);
- var dPosition = Vec3.distance(Camera.position, lastPosition);
- if (dOrientation > 0.001 || dPosition > 0.001) {
- propertyMenu.hide();
- lastOrientation = Camera.orientation;
- lastPosition = Camera.position;
- }
- if (lastMouseMoveEvent) {
- mouseMove(lastMouseMoveEvent);
- lastMouseMoveEvent = null;
- }
-});
-
-function insideBox(center, dimensions, point) {
- return (Math.abs(point.x - center.x) <= (dimensions.x / 2.0)) &&
- (Math.abs(point.y - center.y) <= (dimensions.y / 2.0)) &&
- (Math.abs(point.z - center.z) <= (dimensions.z / 2.0));
-}
-
-function selectAllEntitiesInCurrentSelectionBox(keepIfTouching) {
- if (selectionManager.hasSelection()) {
- // Get all entities touching the bounding box of the current selection
- var boundingBoxCorner = Vec3.subtract(selectionManager.worldPosition,
- Vec3.multiply(selectionManager.worldDimensions, 0.5));
- var entities = Entities.findEntitiesInBox(boundingBoxCorner, selectionManager.worldDimensions);
-
- if (!keepIfTouching) {
- var isValid;
- if (selectionManager.localPosition === null || selectionManager.localPosition === undefined) {
- isValid = function (position) {
- return insideBox(selectionManager.worldPosition, selectionManager.worldDimensions, position);
- };
- } else {
- isValid = function (position) {
- var localPosition = Vec3.multiplyQbyV(Quat.inverse(selectionManager.localRotation),
- Vec3.subtract(position,
- selectionManager.localPosition));
- return insideBox(Vec3.ZERO, selectionManager.localDimensions, localPosition);
- };
- }
- for (var i = 0; i < entities.length; ++i) {
- var properties = Entities.getEntityProperties(entities[i]);
- if (!isValid(properties.position)) {
- entities.splice(i, 1);
- --i;
- }
- }
- }
- selectionManager.setSelections(entities, this);
- }
-}
-
-function sortSelectedEntities(selected) {
- var sortedEntities = selected.slice();
- var begin = 0;
- while (begin < sortedEntities.length) {
- var elementRemoved = false;
- var next = begin + 1;
- while (next < sortedEntities.length) {
- var beginID = sortedEntities[begin];
- var nextID = sortedEntities[next];
-
- if (Entities.isChildOfParent(beginID, nextID)) {
- sortedEntities[begin] = nextID;
- sortedEntities[next] = beginID;
- sortedEntities.splice(next, 1);
- elementRemoved = true;
- break;
- } else if (Entities.isChildOfParent(nextID, beginID)) {
- sortedEntities.splice(next, 1);
- elementRemoved = true;
- break;
- }
- next++;
- }
- if (!elementRemoved) {
- begin++;
- }
- }
- return sortedEntities;
-}
-
-function recursiveDelete(entities, childrenList, deletedIDs, entityHostType) {
- var wantDebug = false;
- var entitiesLength = entities.length;
- var initialPropertySets = Entities.getMultipleEntityProperties(entities);
- var entityHostTypes = Entities.getMultipleEntityProperties(entities, 'entityHostType');
- for (var i = 0; i < entitiesLength; ++i) {
- var entityID = entities[i];
-
- if (entityHostTypes[i].entityHostType !== entityHostType) {
- if (wantDebug) {
- console.log("Skipping deletion of entity " + entityID + " with conflicting entityHostType: " +
- entityHostTypes[i].entityHostType + ", expected: " + entityHostType);
- }
- continue;
- }
-
- var children = Entities.getChildrenIDs(entityID);
- var grandchildrenList = [];
- recursiveDelete(children, grandchildrenList, deletedIDs, entityHostType);
- childrenList.push({
- entityID: entityID,
- properties: initialPropertySets[i],
- children: grandchildrenList
- });
- deletedIDs.push(entityID);
- Entities.deleteEntity(entityID);
- }
-}
-
-function unparentSelectedEntities() {
- if (SelectionManager.hasSelection() && SelectionManager.hasUnlockedSelection()) {
- var selectedEntities = selectionManager.selections;
- var parentCheck = false;
-
- if (selectedEntities.length < 1) {
- audioFeedback.rejection();
- Window.notifyEditError("You must have an entity selected in order to unparent it.");
+ if (propertyMenu.mousePressEvent(event) || progressDialog.mousePressEvent(event)) {
+ mouseCapturedByTool = true;
return;
}
- selectedEntities.forEach(function (id, index) {
- var parentId = Entities.getEntityProperties(id, ["parentID"]).parentID;
- if (parentId !== null && parentId.length > 0 && parentId !== Uuid.NULL) {
- parentCheck = true;
+ if (isActive) {
+ if (cameraManager.mousePressEvent(event) || selectionDisplay.mousePressEvent(event)) {
+ // Event handled; do nothing.
+ return;
}
- Entities.editEntity(id, {parentID: null});
+ }
+ }
+
+ var mouseCapturedByTool = false;
+ var lastMousePosition = null;
+ var CLICK_TIME_THRESHOLD = 500 * 1000; // 500 ms
+ var CLICK_MOVE_DISTANCE_THRESHOLD = 20;
+ var IDLE_MOUSE_TIMEOUT = 200;
+
+ var lastMouseMoveEvent = null;
+
+ function mouseMoveEventBuffered(event) {
+ lastMouseMoveEvent = event;
+ }
+
+ function mouseMove(event) {
+ if (mouseDown && !mouseHasMovedSincePress) {
+ var timeSincePressMicro = Date.now() - mousePressStartTime;
+
+ var dX = mousePressStartPosition.x - event.x;
+ var dY = mousePressStartPosition.y - event.y;
+ var sqDist = (dX * dX) + (dY * dY);
+
+ // If less than CLICK_TIME_THRESHOLD has passed since the mouse click AND the mouse has moved
+ // less than CLICK_MOVE_DISTANCE_THRESHOLD distance, then don't register this as a mouse move
+ // yet. The goal is to provide mouse clicks that are more lenient to small movements.
+ if (timeSincePressMicro < CLICK_TIME_THRESHOLD && sqDist < CLICK_MOVE_DISTANCE_THRESHOLD) {
+ return;
+ }
+ mouseHasMovedSincePress = true;
+ }
+
+ if (!isActive) {
+ return;
+ }
+
+ // allow the selectionDisplay and cameraManager to handle the event first, if it doesn't handle it, then do our own thing
+ if (selectionDisplay.mouseMoveEvent(event) || propertyMenu.mouseMoveEvent(event) || cameraManager.mouseMoveEvent(event)) {
+ return;
+ }
+
+ lastMousePosition = {
+ x: event.x,
+ y: event.y
+ };
+ }
+
+ function mouseReleaseEvent(event) {
+ print("mouseReleaseEvent");
+ mouseDown = false;
+
+ if (lastMouseMoveEvent) {
+ mouseMove(lastMouseMoveEvent);
+ lastMouseMoveEvent = null;
+ }
+ if (propertyMenu.mouseReleaseEvent(event)) {
+ print("propertyMenu.mouseReleaseEvent(event)");
return true;
- });
- if (parentCheck) {
- audioFeedback.confirmation();
- if (selectedEntities.length > 1) {
- Window.notify("Entities unparented");
- } else {
- Window.notify("Entity unparented");
- }
- //Refresh
- entityListTool.sendUpdate();
- selectionManager._update(false, this);
- } else {
- audioFeedback.rejection();
- if (selectedEntities.length > 1) {
- Window.notify("Selected Entities have no parents");
- } else {
- Window.notify("Selected Entity does not have a parent");
- }
}
- } else {
- audioFeedback.rejection();
- Window.notifyEditError("You have nothing selected or the selection has locked entities.");
- }
-}
-function parentSelectedEntities() {
- if (SelectionManager.hasSelection() && SelectionManager.hasUnlockedSelection()) {
- var selectedEntities = selectionManager.selections;
- if (selectedEntities.length <= 1) {
- audioFeedback.rejection();
- Window.notifyEditError("You must have multiple entities selected in order to parent them");
+ if (isActive && selectionManager.hasSelection()) {
+ tooltip.show(false);
+ }
+ if (mouseCapturedByTool) {
+ print("mouseCapturedByTool");
return;
}
- var parentCheck = false;
- var lastEntityId = selectedEntities[selectedEntities.length - 1];
- selectedEntities.forEach(function (id, index) {
- if (lastEntityId !== id) {
- var parentId = Entities.getEntityProperties(id, ["parentID"]).parentID;
- if (parentId !== lastEntityId) {
- parentCheck = true;
- }
- Entities.editEntity(id, {parentID: lastEntityId});
+
+ cameraManager.mouseReleaseEvent(event);
+
+ if (!mouseHasMovedSincePress) {
+ print("!mouseHasMovedSincePress: " + JSON.stringify(event));
+ mouseClickEvent(event);
+ } else {
+ print("mouseHasMovedSincePress");
+ }
+ }
+
+ function wasTabletOrEditHandleClicked(event) {
+ var rayPick = Camera.computePickRay(event.x, event.y);
+ var result = Overlays.findRayIntersection(rayPick, true);
+ if (result.intersects) {
+ var overlayID = result.overlayID;
+ var tabletIDs = getMainTabletIDs();
+ if (tabletIDs.indexOf(overlayID) >= 0) {
+ return true;
+ } else if (selectionDisplay.isEditHandle(overlayID)) {
+ return true;
}
+ }
+ return false;
+ }
+
+ function mouseClickEvent(event) {
+ print("mouseClickEvent isActive: " + isActive);
+ var wantDebug = false;
+ var result, properties, tabletClicked;
+ if (isActive && event.isLeftButton) {
+ print("mouseClickEvent isActive && event.isLeftButton");
+ result = findClickedEntity(event);
+ var tabletOrEditHandleClicked = wasTabletOrEditHandleClicked(event);
+ if (tabletOrEditHandleClicked) {
+ return;
+ }
+
+ if (result === null || result === undefined) {
+ if (!event.isShifted) {
+ if (!keepSelectedOnNextClick) {
+ selectionManager.clearSelections(this);
+ }
+ keepSelectedOnNextClick = false;
+ }
+ return;
+ }
+ toolBar.setActive(true);
+ var pickRay = result.pickRay;
+ var foundEntity = result.entityID;
+ if (HMD.tabletID && foundEntity === HMD.tabletID) {
+ return;
+ }
+ properties = Entities.getEntityProperties(foundEntity);
+ 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 && selectionManager.editEnabled) {
+ selectedEntityID = foundEntity;
+ orientation = MyAvatar.orientation;
+ intersection = createApp.rayPlaneIntersection(pickRay, P, Quat.getForward(orientation));
+
+ if (!event.isShifted) {
+ selectionManager.setSelections([foundEntity], this);
+ } else {
+ selectionManager.addEntity(foundEntity, true, this);
+ }
+ selectionManager.saveProperties();
+
+ 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));
+ }
+ }
+ } else if (event.isRightButton) {
+ result = findClickedEntity(event);
+ if (result) {
+ if (SHOULD_SHOW_PROPERTY_MENU !== true) {
+ return;
+ }
+ properties = Entities.getEntityProperties(result.entityID);
+ if (properties.marketplaceID) {
+ propertyMenu.marketplaceID = properties.marketplaceID;
+ propertyMenu.updateMenuItemText(showMenuItem, "Show in Marketplace");
+ } else {
+ propertyMenu.marketplaceID = null;
+ propertyMenu.updateMenuItemText(showMenuItem, "No marketplace info");
+ }
+ propertyMenu.setPosition(event.x, event.y);
+ propertyMenu.show();
+ } else {
+ propertyMenu.hide();
+ }
+ }
+ }
+
+ Controller.mousePressEvent.connect(mousePressEvent);
+ Controller.mouseMoveEvent.connect(mouseMoveEventBuffered);
+ Controller.mouseReleaseEvent.connect(mouseReleaseEvent);
+
+
+ // In order for editVoxels and editModels to play nice together, they each check to see if a "delete" menu item already
+ // exists. If it doesn't they add it. If it does they don't. They also only delete the menu item if they were the one that
+ // added it.
+ var originalLightsArePickable = Entities.getLightsArePickable();
+
+ function setupModelMenus() {
+ Menu.addMenuItem({
+ menuName: "Edit",
+ menuItemName: "Undo",
+ shortcutKey: 'Ctrl+Z',
+ position: 0,
+ });
+ Menu.addMenuItem({
+ menuName: "Edit",
+ menuItemName: "Redo",
+ shortcutKey: 'Ctrl+Y',
+ position: 1,
});
- if (parentCheck) {
- audioFeedback.confirmation();
- Window.notify("Entities parented");
- //Refresh
- entityListTool.sendUpdate();
- selectionManager._update(false, this);
- } else {
- audioFeedback.rejection();
- Window.notify("Entities are already parented to last");
- }
- } else {
- audioFeedback.rejection();
- Window.notifyEditError("You have nothing selected or the selection has locked entities.");
- }
-}
-function deleteSelectedEntities() {
- if (SelectionManager.hasSelection() && SelectionManager.hasUnlockedSelection()) {
- var deletedIDs = [];
+ Menu.addMenuItem({
+ menuName: "Edit",
+ menuItemName: MENU_CREATE_SEPARATOR,
+ isSeparator: true
+ });
+ Menu.addMenuItem({
+ menuName: "Edit",
+ menuItemName: MENU_IMPORT_FROM_FILE,
+ afterItem: MENU_CREATE_SEPARATOR
+ });
+ Menu.addMenuItem({
+ menuName: "Edit",
+ menuItemName: MENU_IMPORT_FROM_URL,
+ afterItem: MENU_IMPORT_FROM_FILE
+ });
- SelectionManager.saveProperties();
- var savedProperties = [];
- var newSortedSelection = sortSelectedEntities(selectionManager.selections);
- var entityHostTypes = Entities.getMultipleEntityProperties(newSortedSelection, 'entityHostType');
- for (var i = 0; i < newSortedSelection.length; ++i) {
- var entityID = newSortedSelection[i];
- var initialProperties = SelectionManager.savedProperties[entityID];
- if (initialProperties.locked ||
- (initialProperties.avatarEntity && initialProperties.owningAvatarID !== MyAvatar.sessionUUID)) {
+ Menu.addMenu(SUBMENU_ENTITY_EDITOR_PREFERENCES);
+
+ Menu.addMenuItem({
+ menuName: SUBMENU_ENTITY_EDITOR_PREFERENCES,
+ menuItemName: MENU_CREATE_ENTITIES_GRABBABLE,
+ position: 0,
+ isCheckable: true,
+ isChecked: Settings.getValue(SETTING_EDIT_PREFIX + MENU_CREATE_ENTITIES_GRABBABLE, false)
+ });
+ Menu.addMenuItem({
+ menuName: SUBMENU_ENTITY_EDITOR_PREFERENCES,
+ menuItemName: MENU_ALLOW_SELECTION_LARGE,
+ afterItem: MENU_CREATE_ENTITIES_GRABBABLE,
+ isCheckable: true,
+ isChecked: Settings.getValue(SETTING_EDIT_PREFIX + MENU_ALLOW_SELECTION_LARGE, true)
+ });
+ Menu.addMenuItem({
+ menuName: SUBMENU_ENTITY_EDITOR_PREFERENCES,
+ menuItemName: MENU_ALLOW_SELECTION_SMALL,
+ afterItem: MENU_ALLOW_SELECTION_LARGE,
+ isCheckable: true,
+ isChecked: Settings.getValue(SETTING_EDIT_PREFIX + MENU_ALLOW_SELECTION_SMALL, true)
+ });
+ Menu.addMenuItem({
+ menuName: SUBMENU_ENTITY_EDITOR_PREFERENCES,
+ menuItemName: MENU_ALLOW_SELECTION_LIGHTS,
+ afterItem: MENU_ALLOW_SELECTION_SMALL,
+ isCheckable: true,
+ isChecked: Settings.getValue(SETTING_EDIT_PREFIX + MENU_ALLOW_SELECTION_LIGHTS, false)
+ });
+ Menu.addMenuItem({
+ menuName: SUBMENU_ENTITY_EDITOR_PREFERENCES,
+ menuItemName: MENU_AUTO_FOCUS_ON_SELECT,
+ afterItem: MENU_ALLOW_SELECTION_LIGHTS,
+ isCheckable: true,
+ isChecked: Settings.getValue(SETTING_AUTO_FOCUS_ON_SELECT) === "true"
+ });
+ Menu.addMenuItem({
+ menuName: SUBMENU_ENTITY_EDITOR_PREFERENCES,
+ menuItemName: MENU_EASE_ON_FOCUS,
+ afterItem: MENU_AUTO_FOCUS_ON_SELECT,
+ isCheckable: true,
+ isChecked: Settings.getValue(SETTING_EASE_ON_FOCUS) === "true"
+ });
+ Menu.addMenuItem({
+ menuName: SUBMENU_ENTITY_EDITOR_PREFERENCES,
+ menuItemName: MENU_SHOW_ICONS_IN_CREATE_MODE,
+ afterItem: MENU_EASE_ON_FOCUS,
+ isCheckable: true,
+ isChecked: Settings.getValue(SETTING_SHOW_LIGHTS_AND_PARTICLES_IN_EDIT_MODE) !== "false"
+ });
+ Menu.addMenuItem({
+ menuName: SUBMENU_ENTITY_EDITOR_PREFERENCES,
+ menuItemName: MENU_ENTITY_LIST_DEFAULT_RADIUS,
+ afterItem: MENU_SHOW_ICONS_IN_CREATE_MODE
+ });
+
+ Entities.setLightsArePickable(false);
+ }
+
+ setupModelMenus(); // do this when first running our script.
+
+ function cleanupModelMenus() {
+ Menu.removeMenuItem("Edit", "Undo");
+ Menu.removeMenuItem("Edit", "Redo");
+
+ Menu.removeMenuItem(SUBMENU_ENTITY_EDITOR_PREFERENCES, MENU_ALLOW_SELECTION_LARGE);
+ Menu.removeMenuItem(SUBMENU_ENTITY_EDITOR_PREFERENCES, MENU_ALLOW_SELECTION_SMALL);
+ Menu.removeMenuItem(SUBMENU_ENTITY_EDITOR_PREFERENCES, MENU_ALLOW_SELECTION_LIGHTS);
+ Menu.removeMenuItem(SUBMENU_ENTITY_EDITOR_PREFERENCES, MENU_AUTO_FOCUS_ON_SELECT);
+ Menu.removeMenuItem(SUBMENU_ENTITY_EDITOR_PREFERENCES, MENU_EASE_ON_FOCUS);
+ Menu.removeMenuItem(SUBMENU_ENTITY_EDITOR_PREFERENCES, MENU_SHOW_ICONS_IN_CREATE_MODE);
+ Menu.removeMenuItem(SUBMENU_ENTITY_EDITOR_PREFERENCES, MENU_CREATE_ENTITIES_GRABBABLE);
+ Menu.removeMenuItem(SUBMENU_ENTITY_EDITOR_PREFERENCES, MENU_ENTITY_LIST_DEFAULT_RADIUS);
+ Menu.removeMenu(SUBMENU_ENTITY_EDITOR_PREFERENCES);
+ Menu.removeMenuItem("Edit", MENU_IMPORT_FROM_URL);
+ Menu.removeMenuItem("Edit", MENU_IMPORT_FROM_FILE);
+ Menu.removeSeparator("Edit", MENU_CREATE_SEPARATOR);
+ }
+
+ Script.scriptEnding.connect(function () {
+ toolBar.setActive(false);
+ Settings.setValue(SETTING_AUTO_FOCUS_ON_SELECT, Menu.isOptionChecked(MENU_AUTO_FOCUS_ON_SELECT));
+ Settings.setValue(SETTING_EASE_ON_FOCUS, Menu.isOptionChecked(MENU_EASE_ON_FOCUS));
+ Settings.setValue(SETTING_SHOW_LIGHTS_AND_PARTICLES_IN_EDIT_MODE, Menu.isOptionChecked(MENU_SHOW_ICONS_IN_CREATE_MODE));
+
+ Settings.setValue(SETTING_EDIT_PREFIX + MENU_ALLOW_SELECTION_LARGE, Menu.isOptionChecked(MENU_ALLOW_SELECTION_LARGE));
+ Settings.setValue(SETTING_EDIT_PREFIX + MENU_ALLOW_SELECTION_SMALL, Menu.isOptionChecked(MENU_ALLOW_SELECTION_SMALL));
+ Settings.setValue(SETTING_EDIT_PREFIX + MENU_ALLOW_SELECTION_LIGHTS, Menu.isOptionChecked(MENU_ALLOW_SELECTION_LIGHTS));
+
+
+ progressDialog.cleanup();
+ cleanupModelMenus();
+ tooltip.cleanup();
+ selectionDisplay.cleanup();
+ entityShapeVisualizer.cleanup();
+ Entities.setLightsArePickable(originalLightsArePickable);
+
+ Overlays.deleteOverlay(importingSVOImageOverlay);
+ Overlays.deleteOverlay(importingSVOTextOverlay);
+
+ Controller.keyReleaseEvent.disconnect(keyReleaseEvent);
+ Controller.keyPressEvent.disconnect(keyPressEvent);
+
+ Controller.mousePressEvent.disconnect(mousePressEvent);
+ Controller.mouseMoveEvent.disconnect(mouseMoveEventBuffered);
+ Controller.mouseReleaseEvent.disconnect(mouseReleaseEvent);
+
+ Messages.messageReceived.disconnect(handleMessagesReceived);
+ Messages.unsubscribe("entityToolUpdates");
+ createButton = null;
+ });
+
+ var lastOrientation = Camera.orientation;
+ var lastPosition = Camera.position;
+
+ // Do some stuff regularly, like check for placement of various overlays
+ Script.update.connect(function (deltaTime) {
+ progressDialog.move();
+ selectionDisplay.checkControllerMove();
+ var dOrientation = Math.abs(Quat.dot(Camera.orientation, lastOrientation) - 1);
+ var dPosition = Vec3.distance(Camera.position, lastPosition);
+ if (dOrientation > 0.001 || dPosition > 0.001) {
+ propertyMenu.hide();
+ lastOrientation = Camera.orientation;
+ lastPosition = Camera.position;
+ }
+ if (lastMouseMoveEvent) {
+ mouseMove(lastMouseMoveEvent);
+ lastMouseMoveEvent = null;
+ }
+ });
+
+ function insideBox(center, dimensions, point) {
+ return (Math.abs(point.x - center.x) <= (dimensions.x / 2.0)) &&
+ (Math.abs(point.y - center.y) <= (dimensions.y / 2.0)) &&
+ (Math.abs(point.z - center.z) <= (dimensions.z / 2.0));
+ }
+
+ function selectAllEntitiesInCurrentSelectionBox(keepIfTouching) {
+ if (selectionManager.hasSelection()) {
+ // Get all entities touching the bounding box of the current selection
+ var boundingBoxCorner = Vec3.subtract(selectionManager.worldPosition,
+ Vec3.multiply(selectionManager.worldDimensions, 0.5));
+ var entities = Entities.findEntitiesInBox(boundingBoxCorner, selectionManager.worldDimensions);
+
+ if (!keepIfTouching) {
+ var isValid;
+ if (selectionManager.localPosition === null || selectionManager.localPosition === undefined) {
+ isValid = function (position) {
+ return insideBox(selectionManager.worldPosition, selectionManager.worldDimensions, position);
+ };
+ } else {
+ isValid = function (position) {
+ var localPosition = Vec3.multiplyQbyV(Quat.inverse(selectionManager.localRotation),
+ Vec3.subtract(position,
+ selectionManager.localPosition));
+ return insideBox(Vec3.ZERO, selectionManager.localDimensions, localPosition);
+ };
+ }
+ for (var i = 0; i < entities.length; ++i) {
+ var properties = Entities.getEntityProperties(entities[i]);
+ if (!isValid(properties.position)) {
+ entities.splice(i, 1);
+ --i;
+ }
+ }
+ }
+ selectionManager.setSelections(entities, this);
+ }
+ }
+
+ function sortSelectedEntities(selected) {
+ var sortedEntities = selected.slice();
+ var begin = 0;
+ while (begin < sortedEntities.length) {
+ var elementRemoved = false;
+ var next = begin + 1;
+ while (next < sortedEntities.length) {
+ var beginID = sortedEntities[begin];
+ var nextID = sortedEntities[next];
+
+ if (Entities.isChildOfParent(beginID, nextID)) {
+ sortedEntities[begin] = nextID;
+ sortedEntities[next] = beginID;
+ sortedEntities.splice(next, 1);
+ elementRemoved = true;
+ break;
+ } else if (Entities.isChildOfParent(nextID, beginID)) {
+ sortedEntities.splice(next, 1);
+ elementRemoved = true;
+ break;
+ }
+ next++;
+ }
+ if (!elementRemoved) {
+ begin++;
+ }
+ }
+ return sortedEntities;
+ }
+
+ function recursiveDelete(entities, childrenList, deletedIDs, entityHostType) {
+ var wantDebug = false;
+ var entitiesLength = entities.length;
+ var initialPropertySets = Entities.getMultipleEntityProperties(entities);
+ var entityHostTypes = Entities.getMultipleEntityProperties(entities, 'entityHostType');
+ for (var i = 0; i < entitiesLength; ++i) {
+ var entityID = entities[i];
+
+ if (entityHostTypes[i].entityHostType !== entityHostType) {
+ if (wantDebug) {
+ console.log("Skipping deletion of entity " + entityID + " with conflicting entityHostType: " +
+ entityHostTypes[i].entityHostType + ", expected: " + entityHostType);
+ }
continue;
}
+
var children = Entities.getChildrenIDs(entityID);
- var childList = [];
- recursiveDelete(children, childList, deletedIDs, entityHostTypes[i].entityHostType);
- savedProperties.push({
+ var grandchildrenList = [];
+ recursiveDelete(children, grandchildrenList, deletedIDs, entityHostType);
+ childrenList.push({
entityID: entityID,
- properties: initialProperties,
- children: childList
+ properties: initialPropertySets[i],
+ children: grandchildrenList
});
deletedIDs.push(entityID);
Entities.deleteEntity(entityID);
}
-
- if (savedProperties.length > 0) {
- SelectionManager.clearSelections(this);
- pushCommandForSelections([], savedProperties);
- entityListTool.deleteEntities(deletedIDs);
- }
- } else {
- audioFeedback.rejection();
- Window.notifyEditError("You have nothing selected or the selection has locked entities.");
- }
-}
-
-function toggleSelectedEntitiesLocked() {
- if (SelectionManager.hasSelection()) {
- var locked = !Entities.getEntityProperties(SelectionManager.selections[0], ["locked"]).locked;
- for (var i = 0; i < selectionManager.selections.length; i++) {
- var entityID = SelectionManager.selections[i];
- Entities.editEntity(entityID, {
- locked: locked
- });
- }
- entityListTool.sendUpdate();
- selectionManager._update(false, this);
- }
-}
-
-function toggleSelectedEntitiesVisible() {
- if (SelectionManager.hasSelection()) {
- var visible = !Entities.getEntityProperties(SelectionManager.selections[0], ["visible"]).visible;
- for (var i = 0; i < selectionManager.selections.length; i++) {
- var entityID = SelectionManager.selections[i];
- Entities.editEntity(entityID, {
- visible: visible
- });
- }
- entityListTool.sendUpdate();
- selectionManager._update(false, this);
- }
-}
-
-function onFileSaveChanged(filename) {
- Window.saveFileChanged.disconnect(onFileSaveChanged);
- if (filename !== "") {
- var success = Clipboard.exportEntities(filename, selectionManager.selections);
- if (!success) {
- Window.notifyEditError("Export failed.");
- }
- }
-}
-
-function onFileOpenChanged(filename) {
- // disconnect the event, otherwise the requests will stack up
- try {
- // Not all calls to onFileOpenChanged() connect an event.
- Window.browseChanged.disconnect(onFileOpenChanged);
- } catch (e) {
- // Ignore.
}
- var importURL = null;
- if (filename !== "") {
- importURL = filename;
- if (!/^(http|https):\/\//.test(filename)) {
- importURL = "file:///" + importURL;
- }
- }
- if (importURL) {
- if (!isActive && (Entities.canRez() && Entities.canRezTmp() && Entities.canRezCertified() && Entities.canRezTmpCertified())) {
- toolBar.toggle();
- }
- importSVO(importURL);
- }
-}
+ function unparentSelectedEntities() {
+ if (SelectionManager.hasSelection() && SelectionManager.hasUnlockedSelection()) {
+ var selectedEntities = selectionManager.selections;
+ var parentCheck = false;
-function onPromptTextChanged(prompt) {
- Window.promptTextChanged.disconnect(onPromptTextChanged);
- if (prompt !== "") {
- if (!isActive && (Entities.canRez() && Entities.canRezTmp() && Entities.canRezCertified() && Entities.canRezTmpCertified())) {
- toolBar.toggle();
- }
- importSVO(prompt);
- }
-}
-
-function onPromptTextChangedDefaultRadiusUserPref(prompt) {
- Window.promptTextChanged.disconnect(onPromptTextChangedDefaultRadiusUserPref);
- if (prompt !== "") {
- var radius = parseInt(prompt);
- if (radius < 0 || isNaN(radius)){
- radius = 100;
- }
- Settings.setValue(SETTING_ENTITY_LIST_DEFAULT_RADIUS, radius);
- }
-}
-
-function handleMenuEvent(menuItem) {
- if (menuItem === MENU_ALLOW_SELECTION_SMALL) {
- allowSmallModels = Menu.isOptionChecked(MENU_ALLOW_SELECTION_SMALL);
- } else if (menuItem === MENU_ALLOW_SELECTION_LARGE) {
- allowLargeModels = Menu.isOptionChecked(MENU_ALLOW_SELECTION_LARGE);
- } else if (menuItem === MENU_ALLOW_SELECTION_LIGHTS) {
- Entities.setLightsArePickable(Menu.isOptionChecked(MENU_ALLOW_SELECTION_LIGHTS));
- } else if (menuItem === "Delete") {
- deleteSelectedEntities();
- } else if (menuItem === "Undo") {
- undoHistory.undo();
- } else if (menuItem === "Redo") {
- undoHistory.redo();
- } else if (menuItem === MENU_SHOW_ICONS_IN_CREATE_MODE) {
- entityIconOverlayManager.setVisible(isActive && Menu.isOptionChecked(MENU_SHOW_ICONS_IN_CREATE_MODE));
- } else if (menuItem === MENU_CREATE_ENTITIES_GRABBABLE) {
- Settings.setValue(SETTING_EDIT_PREFIX + menuItem, Menu.isOptionChecked(menuItem));
- } else if (menuItem === MENU_ENTITY_LIST_DEFAULT_RADIUS) {
- Window.promptTextChanged.connect(onPromptTextChangedDefaultRadiusUserPref);
- Window.promptAsync("Entity List Default Radius (in meters)", "" + Settings.getValue(SETTING_ENTITY_LIST_DEFAULT_RADIUS, 100));
- } else if (menuItem === MENU_IMPORT_FROM_FILE) {
- importEntitiesFromFile();
- } else if (menuItem === MENU_IMPORT_FROM_URL) {
- importEntitiesFromUrl();
- }
- tooltip.show(false);
-}
-
-var HALF_TREE_SCALE = 16384;
-
-function getPositionToCreateEntity(extra) {
- var CREATE_DISTANCE = 2;
- var position;
- var delta = extra !== undefined ? extra : 0;
- if (Camera.mode === "entity" || Camera.mode === "independent") {
- position = Vec3.sum(Camera.position, Vec3.multiply(Quat.getForward(Camera.orientation), CREATE_DISTANCE + delta));
- } else {
- position = Vec3.sum(MyAvatar.position, Vec3.multiply(Quat.getForward(MyAvatar.orientation), CREATE_DISTANCE + delta));
- }
-
- if (position.x > HALF_TREE_SCALE || position.y > HALF_TREE_SCALE || position.z > HALF_TREE_SCALE) {
- return null;
- }
- return position;
-}
-
-function importSVO(importURL) {
- if (!Entities.canRez() && !Entities.canRezTmp() &&
- !Entities.canRezCertified() && !Entities.canRezTmpCertified()) {
- Window.notifyEditError(INSUFFICIENT_PERMISSIONS_IMPORT_ERROR_MSG);
- return;
- }
-
- Overlays.editOverlay(importingSVOTextOverlay, {
- visible: true
- });
- Overlays.editOverlay(importingSVOImageOverlay, {
- visible: true
- });
-
- var success = Clipboard.importEntities(importURL);
-
- if (success) {
- var VERY_LARGE = 10000;
- var isLargeImport = Clipboard.getClipboardContentsLargestDimension() >= VERY_LARGE;
- var position = Vec3.ZERO;
- if (!isLargeImport) {
- position = getPositionToCreateEntity(Clipboard.getClipboardContentsLargestDimension() / 2);
- }
- if (position !== null && position !== undefined) {
- var pastedEntityIDs = Clipboard.pasteEntities(position);
- if (!isLargeImport) {
- // The first entity in Clipboard gets the specified position with the rest being relative to it. Therefore, move
- // entities after they're imported so that they're all the correct distance in front of and with geometric mean
- // centered on the avatar/camera direction.
- var deltaPosition = Vec3.ZERO;
- var entityPositions = [];
- var entityParentIDs = [];
-
- var propType = Entities.getEntityProperties(pastedEntityIDs[0], ["type"]).type;
- var NO_ADJUST_ENTITY_TYPES = ["Zone", "Light", "ParticleEffect"];
- if (NO_ADJUST_ENTITY_TYPES.indexOf(propType) === -1) {
- var targetDirection;
- if (Camera.mode === "entity" || Camera.mode === "independent") {
- targetDirection = Camera.orientation;
- } else {
- targetDirection = MyAvatar.orientation;
- }
- targetDirection = Vec3.multiplyQbyV(targetDirection, Vec3.UNIT_Z);
-
- var targetPosition = getPositionToCreateEntity();
- var deltaParallel = HALF_TREE_SCALE; // Distance to move entities parallel to targetDirection.
- var deltaPerpendicular = Vec3.ZERO; // Distance to move entities perpendicular to targetDirection.
- for (var i = 0, length = pastedEntityIDs.length; i < length; i++) {
- var curLoopEntityProps = Entities.getEntityProperties(pastedEntityIDs[i], ["position", "dimensions",
- "registrationPoint", "rotation", "parentID"]);
- var adjustedPosition = adjustPositionPerBoundingBox(targetPosition, targetDirection,
- curLoopEntityProps.registrationPoint, curLoopEntityProps.dimensions, curLoopEntityProps.rotation);
- var delta = Vec3.subtract(adjustedPosition, curLoopEntityProps.position);
- var distance = Vec3.dot(delta, targetDirection);
- deltaParallel = Math.min(distance, deltaParallel);
- deltaPerpendicular = Vec3.sum(Vec3.subtract(delta, Vec3.multiply(distance, targetDirection)),
- deltaPerpendicular);
- entityPositions[i] = curLoopEntityProps.position;
- entityParentIDs[i] = curLoopEntityProps.parentID;
- }
- deltaPerpendicular = Vec3.multiply(1 / pastedEntityIDs.length, deltaPerpendicular);
- deltaPosition = Vec3.sum(Vec3.multiply(deltaParallel, targetDirection), deltaPerpendicular);
+ if (selectedEntities.length < 1) {
+ audioFeedback.rejection();
+ Window.notifyEditError("You must have an entity selected in order to unparent it.");
+ return;
+ }
+ selectedEntities.forEach(function (id, index) {
+ var parentId = Entities.getEntityProperties(id, ["parentID"]).parentID;
+ if (parentId !== null && parentId.length > 0 && parentId !== Uuid.NULL) {
+ parentCheck = true;
}
-
- if (grid.getSnapToGrid()) {
- var firstEntityProps = Entities.getEntityProperties(pastedEntityIDs[0], ["position", "dimensions",
- "registrationPoint"]);
- var positionPreSnap = Vec3.sum(deltaPosition, firstEntityProps.position);
- position = grid.snapToSurface(grid.snapToGrid(positionPreSnap, false, firstEntityProps.dimensions,
- firstEntityProps.registrationPoint), firstEntityProps.dimensions, firstEntityProps.registrationPoint);
- deltaPosition = Vec3.subtract(position, firstEntityProps.position);
+ Entities.editEntity(id, {parentID: null});
+ return true;
+ });
+ if (parentCheck) {
+ audioFeedback.confirmation();
+ if (selectedEntities.length > 1) {
+ Window.notify("Entities unparented");
+ } else {
+ Window.notify("Entity unparented");
}
-
- if (!Vec3.equal(deltaPosition, Vec3.ZERO)) {
- for (var editEntityIndex = 0, numEntities = pastedEntityIDs.length; editEntityIndex < numEntities; editEntityIndex++) {
- if (Uuid.isNull(entityParentIDs[editEntityIndex])) {
- Entities.editEntity(pastedEntityIDs[editEntityIndex], {
- position: Vec3.sum(deltaPosition, entityPositions[editEntityIndex])
- });
- }
- }
+ //Refresh
+ entityListTool.sendUpdate();
+ selectionManager._update(false, this);
+ } else {
+ audioFeedback.rejection();
+ if (selectedEntities.length > 1) {
+ Window.notify("Selected Entities have no parents");
+ } else {
+ Window.notify("Selected Entity does not have a parent");
}
}
-
- if (isActive) {
- selectionManager.setSelections(pastedEntityIDs, this);
+ } else {
+ audioFeedback.rejection();
+ Window.notifyEditError("You have nothing selected or the selection has locked entities.");
+ }
+ }
+ function parentSelectedEntities() {
+ if (SelectionManager.hasSelection() && SelectionManager.hasUnlockedSelection()) {
+ var selectedEntities = selectionManager.selections;
+ if (selectedEntities.length <= 1) {
+ audioFeedback.rejection();
+ Window.notifyEditError("You must have multiple entities selected in order to parent them");
+ return;
}
- } else {
- Window.notifyEditError("Can't import entities: entities would be out of bounds.");
- }
- } else {
- Window.notifyEditError("There was an error importing the entity file.");
- }
-
- Overlays.editOverlay(importingSVOTextOverlay, {
- visible: false
- });
- Overlays.editOverlay(importingSVOImageOverlay, {
- visible: false
- });
-}
-Window.svoImportRequested.connect(importSVO);
-
-Menu.menuItemEvent.connect(handleMenuEvent);
-
-var keyPressEvent = function (event) {
- if (isActive) {
- cameraManager.keyPressEvent(event);
- }
-};
-var keyReleaseEvent = function (event) {
- if (isActive) {
- cameraManager.keyReleaseEvent(event);
- }
-};
-Controller.keyReleaseEvent.connect(keyReleaseEvent);
-Controller.keyPressEvent.connect(keyPressEvent);
-
-function deleteKey(value) {
- if (value === 0) { // on release
- deleteSelectedEntities();
- }
-}
-function deselectKey(value) {
- if (value === 0) { // on release
- selectionManager.clearSelections(this);
- }
-}
-function toggleKey(value) {
- if (value === 0) { // on release
- selectionDisplay.toggleSpaceMode();
- }
-}
-function focusKey(value) {
- if (value === 0) { // on release
- setCameraFocusToSelection();
- }
-}
-function gridKey(value) {
- if (value === 0) { // on release
- alignGridToSelection();
- }
-}
-function viewGridKey(value) {
- if (value === 0) { // on release
- toggleGridVisibility();
- }
-}
-function snapKey(value) {
- if (value === 0) { // on release
- entityListTool.toggleSnapToGrid();
- }
-}
-function gridToAvatarKey(value) {
- if (value === 0) { // on release
- alignGridToAvatar();
- }
-}
-function rotateAsNextClickedSurfaceKey(value) {
- if (value === 0) { // on release
- rotateAsNextClickedSurface();
- }
-}
-function quickRotate90xKey(value) {
- if (value === 0) { // on release
- selectionDisplay.rotate90degreeSelection("X");
- }
-}
-function quickRotate90yKey(value) {
- if (value === 0) { // on release
- selectionDisplay.rotate90degreeSelection("Y");
- }
-}
-function quickRotate90zKey(value) {
- if (value === 0) { // on release
- selectionDisplay.rotate90degreeSelection("Z");
- }
-}
-function recursiveAdd(newParentID, parentData) {
- if (parentData.children !== undefined) {
- var children = parentData.children;
- for (var i = 0; i < children.length; i++) {
- var childProperties = children[i].properties;
- childProperties.parentID = newParentID;
- var newChildID = Entities.addEntity(childProperties);
- recursiveAdd(newChildID, children[i]);
- }
- }
-}
-
-var UndoHistory = function(onUpdate) {
- this.history = [];
- // The current position is the index of the last executed action in the history array.
- //
- // -1 0 1 2 3 <- position
- // A B C D <- actions in history
- //
- // If our lastExecutedIndex is 1, the last executed action is B.
- // If we undo, we undo B (index 1). If we redo, we redo C (index 2).
- this.lastExecutedIndex = -1;
- this.enabled = true;
- this.onUpdate = onUpdate;
-};
-
-UndoHistory.prototype.pushCommand = function(undoFn, undoArgs, redoFn, redoArgs) {
- if (!this.enabled) {
- return;
- }
- // Delete any history following the last executed action.
- this.history.splice(this.lastExecutedIndex + 1);
- this.history.push({
- undoFn: undoFn,
- undoArgs: undoArgs,
- redoFn: redoFn,
- redoArgs: redoArgs
- });
- this.lastExecutedIndex++;
-
- if (this.onUpdate) {
- this.onUpdate();
- }
-};
-UndoHistory.prototype.setEnabled = function(enabled) {
- this.enabled = enabled;
- if (this.onUpdate) {
- this.onUpdate();
- }
-};
-UndoHistory.prototype.canUndo = function() {
- return this.enabled && this.lastExecutedIndex >= 0;
-};
-UndoHistory.prototype.canRedo = function() {
- return this.enabled && this.lastExecutedIndex < this.history.length - 1;
-};
-UndoHistory.prototype.undo = function() {
- if (!this.canUndo()) {
- console.warn("Cannot undo action");
- return;
- }
-
- var command = this.history[this.lastExecutedIndex];
- command.undoFn(command.undoArgs);
- this.lastExecutedIndex--;
-
- if (this.onUpdate) {
- this.onUpdate();
- }
-};
-UndoHistory.prototype.redo = function() {
- if (!this.canRedo()) {
- console.warn("Cannot redo action");
- return;
- }
-
- var command = this.history[this.lastExecutedIndex + 1];
- command.redoFn(command.redoArgs);
- this.lastExecutedIndex++;
-
- if (this.onUpdate) {
- this.onUpdate();
- }
-};
-
-function updateUndoRedoMenuItems() {
- Menu.setMenuEnabled("Edit > Undo", undoHistory.canUndo());
- Menu.setMenuEnabled("Edit > Redo", undoHistory.canRedo());
-}
-var undoHistory = new UndoHistory(updateUndoRedoMenuItems);
-updateUndoRedoMenuItems();
-
-// When an entity has been deleted we need a way to "undo" this deletion. Because it's not currently
-// possible to create an entity with a specific id, earlier undo commands to the deleted entity
-// will fail if there isn't a way to find the new entity id.
-var DELETED_ENTITY_MAP = {};
-
-function applyEntityProperties(data) {
- var editEntities = data.editEntities;
- var createEntities = data.createEntities;
- var deleteEntities = data.deleteEntities;
- var selectedEntityIDs = [];
- var selectEdits = createEntities.length === 0 || !data.selectCreated;
- var i, entityID, entityProperties;
- for (i = 0; i < createEntities.length; i++) {
- entityID = createEntities[i].entityID;
- entityProperties = createEntities[i].properties;
- var newEntityID = Entities.addEntity(entityProperties);
- recursiveAdd(newEntityID, createEntities[i]);
- DELETED_ENTITY_MAP[entityID] = newEntityID;
- if (data.selectCreated) {
- selectedEntityIDs.push(newEntityID);
- }
- }
- for (i = 0; i < deleteEntities.length; i++) {
- entityID = deleteEntities[i].entityID;
- if (DELETED_ENTITY_MAP[entityID] !== undefined) {
- entityID = DELETED_ENTITY_MAP[entityID];
- }
- Entities.deleteEntity(entityID);
- var index = selectedEntityIDs.indexOf(entityID);
- if (index >= 0) {
- selectedEntityIDs.splice(index, 1);
- }
- }
- for (i = 0; i < editEntities.length; i++) {
- entityID = editEntities[i].entityID;
- if (DELETED_ENTITY_MAP[entityID] !== undefined) {
- entityID = DELETED_ENTITY_MAP[entityID];
- }
- entityProperties = editEntities[i].properties;
- if (entityProperties !== null) {
- Entities.editEntity(entityID, entityProperties);
- }
- if (selectEdits) {
- selectedEntityIDs.push(entityID);
- }
- }
-
- // We might be getting an undo while edit.js is disabled. If that is the case, don't set
- // our selections, causing the edit widgets to display.
- if (isActive) {
- selectionManager.setSelections(selectedEntityIDs, this);
- selectionManager.saveProperties();
- }
-}
-
-// For currently selected entities, push a command to the UndoStack that uses the current entity properties for the
-// redo command, and the saved properties for the undo command. Also, include create and delete entity data.
-function pushCommandForSelections(createdEntityData, deletedEntityData, doNotSaveEditProperties) {
- doNotSaveEditProperties = false;
- var undoData = {
- editEntities: [],
- createEntities: deletedEntityData || [],
- deleteEntities: createdEntityData || [],
- selectCreated: true
- };
- var redoData = {
- editEntities: [],
- createEntities: createdEntityData || [],
- deleteEntities: deletedEntityData || [],
- selectCreated: true
- };
- for (var i = 0; i < SelectionManager.selections.length; i++) {
- var entityID = SelectionManager.selections[i];
- var initialProperties = SelectionManager.savedProperties[entityID];
- var currentProperties = null;
- if (!initialProperties) {
- continue;
- }
-
- if (doNotSaveEditProperties) {
- initialProperties = null;
- } else {
- currentProperties = Entities.getEntityProperties(entityID);
- }
-
- undoData.editEntities.push({
- entityID: entityID,
- properties: initialProperties
- });
- redoData.editEntities.push({
- entityID: entityID,
- properties: currentProperties
- });
- }
- undoHistory.pushCommand(applyEntityProperties, undoData, applyEntityProperties, redoData);
-}
-
-var ServerScriptStatusMonitor = function(entityID, statusCallback) {
- var self = this;
-
- self.entityID = entityID;
- self.active = true;
- self.sendRequestTimerID = null;
-
- var onStatusReceived = function(success, isRunning, status, errorInfo) {
- if (self.active) {
- statusCallback({
- statusRetrieved: success,
- isRunning: isRunning,
- status: status,
- errorInfo: errorInfo
- });
- self.sendRequestTimerID = Script.setTimeout(function() {
- if (self.active) {
- Entities.getServerScriptStatus(entityID, onStatusReceived);
+ var parentCheck = false;
+ var lastEntityId = selectedEntities[selectedEntities.length - 1];
+ selectedEntities.forEach(function (id, index) {
+ if (lastEntityId !== id) {
+ var parentId = Entities.getEntityProperties(id, ["parentID"]).parentID;
+ if (parentId !== lastEntityId) {
+ parentCheck = true;
+ }
+ Entities.editEntity(id, {parentID: lastEntityId});
}
- }, 1000);
- }
- };
- self.stop = function() {
- self.active = false;
- };
+ });
- Entities.getServerScriptStatus(entityID, onStatusReceived);
-};
-
-var PropertiesTool = function (opts) {
- var that = {};
-
- var webView = null;
- webView = Tablet.getTablet("com.highfidelity.interface.tablet.system");
- webView.setVisible = function(value) {};
-
- var visible = false;
-
- // This keeps track of the last entity ID that was selected. If multiple entities
- // are selected or if no entity is selected this will be `null`.
- var currentSelectedEntityID = null;
- var statusMonitor = null;
- var blockPropertyUpdates = false;
-
- that.setVisible = function (newVisible) {
- visible = newVisible;
- webView.setVisible(shouldUseEditTabletApp() && visible);
- createToolsWindow.setVisible(!shouldUseEditTabletApp() && visible);
- };
-
- that.setVisible(false);
-
- function emitScriptEvent(data) {
- var dataString = JSON.stringify(data);
- webView.emitScriptEvent(dataString);
- createToolsWindow.emitScriptEvent(dataString);
- }
-
- function updateScriptStatus(info) {
- info.type = "server_script_status";
- emitScriptEvent(info);
- }
-
- function resetScriptStatus() {
- updateScriptStatus({
- statusRetrieved: undefined,
- isRunning: undefined,
- status: "",
- errorInfo: ""
- });
- }
-
- that.setSpaceMode = function(spaceMode) {
- emitScriptEvent({
- type: 'setSpaceMode',
- spaceMode: spaceMode
- })
- };
-
- function updateSelections(selectionUpdated, caller) {
- if (HMD.active && visible) {
- webView.setLandscape(true);
+ if (parentCheck) {
+ audioFeedback.confirmation();
+ Window.notify("Entities parented");
+ //Refresh
+ entityListTool.sendUpdate();
+ selectionManager._update(false, this);
+ } else {
+ audioFeedback.rejection();
+ Window.notify("Entities are already parented to last");
+ }
} else {
- if (!visible) {
- hmdMultiSelectMode = false;
- webView.setLandscape(false);
+ audioFeedback.rejection();
+ Window.notifyEditError("You have nothing selected or the selection has locked entities.");
+ }
+ }
+ function deleteSelectedEntities() {
+ if (SelectionManager.hasSelection() && SelectionManager.hasUnlockedSelection()) {
+ var deletedIDs = [];
+
+ SelectionManager.saveProperties();
+ var savedProperties = [];
+ var newSortedSelection = sortSelectedEntities(selectionManager.selections);
+ var entityHostTypes = Entities.getMultipleEntityProperties(newSortedSelection, 'entityHostType');
+ for (var i = 0; i < newSortedSelection.length; ++i) {
+ var entityID = newSortedSelection[i];
+ var initialProperties = SelectionManager.savedProperties[entityID];
+ if (initialProperties.locked ||
+ (initialProperties.avatarEntity && initialProperties.owningAvatarID !== MyAvatar.sessionUUID)) {
+ continue;
+ }
+ var children = Entities.getChildrenIDs(entityID);
+ var childList = [];
+ recursiveDelete(children, childList, deletedIDs, entityHostTypes[i].entityHostType);
+ savedProperties.push({
+ entityID: entityID,
+ properties: initialProperties,
+ children: childList
+ });
+ deletedIDs.push(entityID);
+ Entities.deleteEntity(entityID);
+ }
+
+ if (savedProperties.length > 0) {
+ SelectionManager.clearSelections(this);
+ createApp.pushCommandForSelections([], savedProperties);
+ entityListTool.deleteEntities(deletedIDs);
+ }
+ } else {
+ audioFeedback.rejection();
+ Window.notifyEditError("You have nothing selected or the selection has locked entities.");
+ }
+ }
+
+ function toggleSelectedEntitiesLocked() {
+ if (SelectionManager.hasSelection()) {
+ var locked = !Entities.getEntityProperties(SelectionManager.selections[0], ["locked"]).locked;
+ for (var i = 0; i < selectionManager.selections.length; i++) {
+ var entityID = SelectionManager.selections[i];
+ Entities.editEntity(entityID, {
+ locked: locked
+ });
+ }
+ entityListTool.sendUpdate();
+ selectionManager._update(false, this);
+ }
+ }
+
+ function toggleSelectedEntitiesVisible() {
+ if (SelectionManager.hasSelection()) {
+ var visible = !Entities.getEntityProperties(SelectionManager.selections[0], ["visible"]).visible;
+ for (var i = 0; i < selectionManager.selections.length; i++) {
+ var entityID = SelectionManager.selections[i];
+ Entities.editEntity(entityID, {
+ visible: visible
+ });
+ }
+ entityListTool.sendUpdate();
+ selectionManager._update(false, this);
+ }
+ }
+
+ function onFileSaveChanged(filename) {
+ Window.saveFileChanged.disconnect(onFileSaveChanged);
+ if (filename !== "") {
+ var success = Clipboard.exportEntities(filename, selectionManager.selections);
+ if (!success) {
+ Window.notifyEditError("Export failed.");
}
}
-
- if (blockPropertyUpdates) {
+ }
+
+ function onFileOpenChanged(filename) {
+ // disconnect the event, otherwise the requests will stack up
+ try {
+ // Not all calls to onFileOpenChanged() connect an event.
+ Window.browseChanged.disconnect(onFileOpenChanged);
+ } catch (e) {
+ // Ignore.
+ }
+
+ var importURL = null;
+ if (filename !== "") {
+ importURL = filename;
+ if (!/^(http|https):\/\//.test(filename)) {
+ importURL = "file:///" + importURL;
+ }
+ }
+ if (importURL) {
+ if (!isActive && (Entities.canRez() && Entities.canRezTmp() && Entities.canRezCertified() && Entities.canRezTmpCertified())) {
+ toolBar.toggle();
+ }
+ importSVO(importURL);
+ }
+ }
+
+ function onPromptTextChanged(prompt) {
+ Window.promptTextChanged.disconnect(onPromptTextChanged);
+ if (prompt !== "") {
+ if (!isActive && (Entities.canRez() && Entities.canRezTmp() && Entities.canRezCertified() && Entities.canRezTmpCertified())) {
+ toolBar.toggle();
+ }
+ importSVO(prompt);
+ }
+ }
+
+ function onPromptTextChangedDefaultRadiusUserPref(prompt) {
+ Window.promptTextChanged.disconnect(onPromptTextChangedDefaultRadiusUserPref);
+ if (prompt !== "") {
+ var radius = parseInt(prompt);
+ if (radius < 0 || isNaN(radius)){
+ radius = 100;
+ }
+ Settings.setValue(SETTING_ENTITY_LIST_DEFAULT_RADIUS, radius);
+ }
+ }
+
+ function handleMenuEvent(menuItem) {
+ if (menuItem === MENU_ALLOW_SELECTION_SMALL) {
+ allowSmallModels = Menu.isOptionChecked(MENU_ALLOW_SELECTION_SMALL);
+ } else if (menuItem === MENU_ALLOW_SELECTION_LARGE) {
+ allowLargeModels = Menu.isOptionChecked(MENU_ALLOW_SELECTION_LARGE);
+ } else if (menuItem === MENU_ALLOW_SELECTION_LIGHTS) {
+ Entities.setLightsArePickable(Menu.isOptionChecked(MENU_ALLOW_SELECTION_LIGHTS));
+ } else if (menuItem === "Delete") {
+ deleteSelectedEntities();
+ } else if (menuItem === "Undo") {
+ undoHistory.undo();
+ } else if (menuItem === "Redo") {
+ undoHistory.redo();
+ } else if (menuItem === MENU_SHOW_ICONS_IN_CREATE_MODE) {
+ entityIconOverlayManager.setVisible(isActive && Menu.isOptionChecked(MENU_SHOW_ICONS_IN_CREATE_MODE));
+ } else if (menuItem === MENU_CREATE_ENTITIES_GRABBABLE) {
+ Settings.setValue(SETTING_EDIT_PREFIX + menuItem, Menu.isOptionChecked(menuItem));
+ } else if (menuItem === MENU_ENTITY_LIST_DEFAULT_RADIUS) {
+ Window.promptTextChanged.connect(onPromptTextChangedDefaultRadiusUserPref);
+ Window.promptAsync("Entity List Default Radius (in meters)", "" + Settings.getValue(SETTING_ENTITY_LIST_DEFAULT_RADIUS, 100));
+ } else if (menuItem === MENU_IMPORT_FROM_FILE) {
+ importEntitiesFromFile();
+ } else if (menuItem === MENU_IMPORT_FROM_URL) {
+ importEntitiesFromUrl();
+ }
+ tooltip.show(false);
+ }
+
+ var HALF_TREE_SCALE = 16384;
+
+ function getPositionToCreateEntity(extra) {
+ var CREATE_DISTANCE = 2;
+ var position;
+ var delta = extra !== undefined ? extra : 0;
+ if (Camera.mode === "entity" || Camera.mode === "independent") {
+ position = Vec3.sum(Camera.position, Vec3.multiply(Quat.getForward(Camera.orientation), CREATE_DISTANCE + delta));
+ } else {
+ position = Vec3.sum(MyAvatar.position, Vec3.multiply(Quat.getForward(MyAvatar.orientation), CREATE_DISTANCE + delta));
+ }
+
+ if (position.x > HALF_TREE_SCALE || position.y > HALF_TREE_SCALE || position.z > HALF_TREE_SCALE) {
+ return null;
+ }
+ return position;
+ }
+
+ function importSVO(importURL) {
+ if (!Entities.canRez() && !Entities.canRezTmp() &&
+ !Entities.canRezCertified() && !Entities.canRezTmpCertified()) {
+ Window.notifyEditError(INSUFFICIENT_PERMISSIONS_IMPORT_ERROR_MSG);
return;
}
- var data = {
- type: 'update',
- spaceMode: selectionDisplay.getSpaceMode(),
- isPropertiesToolUpdate: caller === this,
+ Overlays.editOverlay(importingSVOTextOverlay, {
+ visible: true
+ });
+ Overlays.editOverlay(importingSVOImageOverlay, {
+ visible: true
+ });
+
+ var success = Clipboard.importEntities(importURL);
+
+ if (success) {
+ var VERY_LARGE = 10000;
+ var isLargeImport = Clipboard.getClipboardContentsLargestDimension() >= VERY_LARGE;
+ var position = Vec3.ZERO;
+ if (!isLargeImport) {
+ position = getPositionToCreateEntity(Clipboard.getClipboardContentsLargestDimension() / 2);
+ }
+ if (position !== null && position !== undefined) {
+ var pastedEntityIDs = Clipboard.pasteEntities(position);
+ if (!isLargeImport) {
+ // The first entity in Clipboard gets the specified position with the rest being relative to it. Therefore, move
+ // entities after they're imported so that they're all the correct distance in front of and with geometric mean
+ // centered on the avatar/camera direction.
+ var deltaPosition = Vec3.ZERO;
+ var entityPositions = [];
+ var entityParentIDs = [];
+
+ var propType = Entities.getEntityProperties(pastedEntityIDs[0], ["type"]).type;
+ var NO_ADJUST_ENTITY_TYPES = ["Zone", "Light", "ParticleEffect"];
+ if (NO_ADJUST_ENTITY_TYPES.indexOf(propType) === -1) {
+ var targetDirection;
+ if (Camera.mode === "entity" || Camera.mode === "independent") {
+ targetDirection = Camera.orientation;
+ } else {
+ targetDirection = MyAvatar.orientation;
+ }
+ targetDirection = Vec3.multiplyQbyV(targetDirection, Vec3.UNIT_Z);
+
+ var targetPosition = getPositionToCreateEntity();
+ var deltaParallel = HALF_TREE_SCALE; // Distance to move entities parallel to targetDirection.
+ var deltaPerpendicular = Vec3.ZERO; // Distance to move entities perpendicular to targetDirection.
+ for (var i = 0, length = pastedEntityIDs.length; i < length; i++) {
+ var curLoopEntityProps = Entities.getEntityProperties(pastedEntityIDs[i], ["position", "dimensions",
+ "registrationPoint", "rotation", "parentID"]);
+ var adjustedPosition = adjustPositionPerBoundingBox(targetPosition, targetDirection,
+ curLoopEntityProps.registrationPoint, curLoopEntityProps.dimensions, curLoopEntityProps.rotation);
+ var delta = Vec3.subtract(adjustedPosition, curLoopEntityProps.position);
+ var distance = Vec3.dot(delta, targetDirection);
+ deltaParallel = Math.min(distance, deltaParallel);
+ deltaPerpendicular = Vec3.sum(Vec3.subtract(delta, Vec3.multiply(distance, targetDirection)),
+ deltaPerpendicular);
+ entityPositions[i] = curLoopEntityProps.position;
+ entityParentIDs[i] = curLoopEntityProps.parentID;
+ }
+ deltaPerpendicular = Vec3.multiply(1 / pastedEntityIDs.length, deltaPerpendicular);
+ deltaPosition = Vec3.sum(Vec3.multiply(deltaParallel, targetDirection), deltaPerpendicular);
+ }
+
+ if (grid.getSnapToGrid()) {
+ var firstEntityProps = Entities.getEntityProperties(pastedEntityIDs[0], ["position", "dimensions",
+ "registrationPoint"]);
+ var positionPreSnap = Vec3.sum(deltaPosition, firstEntityProps.position);
+ position = grid.snapToSurface(grid.snapToGrid(positionPreSnap, false, firstEntityProps.dimensions,
+ firstEntityProps.registrationPoint), firstEntityProps.dimensions, firstEntityProps.registrationPoint);
+ deltaPosition = Vec3.subtract(position, firstEntityProps.position);
+ }
+
+ if (!Vec3.equal(deltaPosition, Vec3.ZERO)) {
+ for (var editEntityIndex = 0, numEntities = pastedEntityIDs.length; editEntityIndex < numEntities; editEntityIndex++) {
+ if (Uuid.isNull(entityParentIDs[editEntityIndex])) {
+ Entities.editEntity(pastedEntityIDs[editEntityIndex], {
+ position: Vec3.sum(deltaPosition, entityPositions[editEntityIndex])
+ });
+ }
+ }
+ }
+ }
+
+ if (isActive) {
+ selectionManager.setSelections(pastedEntityIDs, this);
+ }
+ } else {
+ Window.notifyEditError("Can't import entities: entities would be out of bounds.");
+ }
+ } else {
+ Window.notifyEditError("There was an error importing the entity file.");
+ }
+
+ Overlays.editOverlay(importingSVOTextOverlay, {
+ visible: false
+ });
+ Overlays.editOverlay(importingSVOImageOverlay, {
+ visible: false
+ });
+ }
+ Window.svoImportRequested.connect(importSVO);
+
+ Menu.menuItemEvent.connect(handleMenuEvent);
+
+ var keyPressEvent = function (event) {
+ if (isActive) {
+ cameraManager.keyPressEvent(event);
+ }
+ };
+ var keyReleaseEvent = function (event) {
+ if (isActive) {
+ cameraManager.keyReleaseEvent(event);
+ }
+ };
+ Controller.keyReleaseEvent.connect(keyReleaseEvent);
+ Controller.keyPressEvent.connect(keyPressEvent);
+
+ function deleteKey(value) {
+ if (value === 0) { // on release
+ deleteSelectedEntities();
+ }
+ }
+ function deselectKey(value) {
+ if (value === 0) { // on release
+ selectionManager.clearSelections(this);
+ }
+ }
+ function toggleKey(value) {
+ if (value === 0) { // on release
+ selectionDisplay.toggleSpaceMode();
+ }
+ }
+ function focusKey(value) {
+ if (value === 0) { // on release
+ setCameraFocusToSelection();
+ }
+ }
+ function gridKey(value) {
+ if (value === 0) { // on release
+ alignGridToSelection();
+ }
+ }
+ function viewGridKey(value) {
+ if (value === 0) { // on release
+ toggleGridVisibility();
+ }
+ }
+ function snapKey(value) {
+ if (value === 0) { // on release
+ entityListTool.toggleSnapToGrid();
+ }
+ }
+ function gridToAvatarKey(value) {
+ if (value === 0) { // on release
+ alignGridToAvatar();
+ }
+ }
+ function rotateAsNextClickedSurfaceKey(value) {
+ if (value === 0) { // on release
+ rotateAsNextClickedSurface();
+ }
+ }
+ function quickRotate90xKey(value) {
+ if (value === 0) { // on release
+ selectionDisplay.rotate90degreeSelection("X");
+ }
+ }
+ function quickRotate90yKey(value) {
+ if (value === 0) { // on release
+ selectionDisplay.rotate90degreeSelection("Y");
+ }
+ }
+ function quickRotate90zKey(value) {
+ if (value === 0) { // on release
+ selectionDisplay.rotate90degreeSelection("Z");
+ }
+ }
+ function recursiveAdd(newParentID, parentData) {
+ if (parentData.children !== undefined) {
+ var children = parentData.children;
+ for (var i = 0; i < children.length; i++) {
+ var childProperties = children[i].properties;
+ childProperties.parentID = newParentID;
+ var newChildID = Entities.addEntity(childProperties);
+ recursiveAdd(newChildID, children[i]);
+ }
+ }
+ }
+
+ var UndoHistory = function(onUpdate) {
+ this.history = [];
+ // The current position is the index of the last executed action in the history array.
+ //
+ // -1 0 1 2 3 <- position
+ // A B C D <- actions in history
+ //
+ // If our lastExecutedIndex is 1, the last executed action is B.
+ // If we undo, we undo B (index 1). If we redo, we redo C (index 2).
+ this.lastExecutedIndex = -1;
+ this.enabled = true;
+ this.onUpdate = onUpdate;
+ };
+
+ UndoHistory.prototype.pushCommand = function(undoFn, undoArgs, redoFn, redoArgs) {
+ if (!this.enabled) {
+ return;
+ }
+ // Delete any history following the last executed action.
+ this.history.splice(this.lastExecutedIndex + 1);
+ this.history.push({
+ undoFn: undoFn,
+ undoArgs: undoArgs,
+ redoFn: redoFn,
+ redoArgs: redoArgs
+ });
+ this.lastExecutedIndex++;
+
+ if (this.onUpdate) {
+ this.onUpdate();
+ }
+ };
+ UndoHistory.prototype.setEnabled = function(enabled) {
+ this.enabled = enabled;
+ if (this.onUpdate) {
+ this.onUpdate();
+ }
+ };
+ UndoHistory.prototype.canUndo = function() {
+ return this.enabled && this.lastExecutedIndex >= 0;
+ };
+ UndoHistory.prototype.canRedo = function() {
+ return this.enabled && this.lastExecutedIndex < this.history.length - 1;
+ };
+ UndoHistory.prototype.undo = function() {
+ if (!this.canUndo()) {
+ console.warn("Cannot undo action");
+ return;
+ }
+
+ var command = this.history[this.lastExecutedIndex];
+ command.undoFn(command.undoArgs);
+ this.lastExecutedIndex--;
+
+ if (this.onUpdate) {
+ this.onUpdate();
+ }
+ };
+ UndoHistory.prototype.redo = function() {
+ if (!this.canRedo()) {
+ console.warn("Cannot redo action");
+ return;
+ }
+
+ var command = this.history[this.lastExecutedIndex + 1];
+ command.redoFn(command.redoArgs);
+ this.lastExecutedIndex++;
+
+ if (this.onUpdate) {
+ this.onUpdate();
+ }
+ };
+
+ function updateUndoRedoMenuItems() {
+ Menu.setMenuEnabled("Edit > Undo", undoHistory.canUndo());
+ Menu.setMenuEnabled("Edit > Redo", undoHistory.canRedo());
+ }
+ var undoHistory = new UndoHistory(updateUndoRedoMenuItems);
+ updateUndoRedoMenuItems();
+
+ // When an entity has been deleted we need a way to "undo" this deletion. Because it's not currently
+ // possible to create an entity with a specific id, earlier undo commands to the deleted entity
+ // will fail if there isn't a way to find the new entity id.
+ var DELETED_ENTITY_MAP = {};
+
+ function applyEntityProperties(data) {
+ var editEntities = data.editEntities;
+ var createEntities = data.createEntities;
+ var deleteEntities = data.deleteEntities;
+ var selectedEntityIDs = [];
+ var selectEdits = createEntities.length === 0 || !data.selectCreated;
+ var i, entityID, entityProperties;
+ for (i = 0; i < createEntities.length; i++) {
+ entityID = createEntities[i].entityID;
+ entityProperties = createEntities[i].properties;
+ var newEntityID = Entities.addEntity(entityProperties);
+ recursiveAdd(newEntityID, createEntities[i]);
+ DELETED_ENTITY_MAP[entityID] = newEntityID;
+ if (data.selectCreated) {
+ selectedEntityIDs.push(newEntityID);
+ }
+ }
+ for (i = 0; i < deleteEntities.length; i++) {
+ entityID = deleteEntities[i].entityID;
+ if (DELETED_ENTITY_MAP[entityID] !== undefined) {
+ entityID = DELETED_ENTITY_MAP[entityID];
+ }
+ Entities.deleteEntity(entityID);
+ var index = selectedEntityIDs.indexOf(entityID);
+ if (index >= 0) {
+ selectedEntityIDs.splice(index, 1);
+ }
+ }
+ for (i = 0; i < editEntities.length; i++) {
+ entityID = editEntities[i].entityID;
+ if (DELETED_ENTITY_MAP[entityID] !== undefined) {
+ entityID = DELETED_ENTITY_MAP[entityID];
+ }
+ entityProperties = editEntities[i].properties;
+ if (entityProperties !== null) {
+ Entities.editEntity(entityID, entityProperties);
+ }
+ if (selectEdits) {
+ selectedEntityIDs.push(entityID);
+ }
+ }
+
+ // We might be getting an undo while edit.js is disabled. If that is the case, don't set
+ // our selections, causing the edit widgets to display.
+ if (isActive) {
+ selectionManager.setSelections(selectedEntityIDs, this);
+ selectionManager.saveProperties();
+ }
+ }
+
+ // For currently selected entities, push a command to the UndoStack that uses the current entity properties for the
+ // redo command, and the saved properties for the undo command. Also, include create and delete entity data.
+ createApp.pushCommandForSelections = function (createdEntityData, deletedEntityData, doNotSaveEditProperties) {
+ doNotSaveEditProperties = false;
+ var undoData = {
+ editEntities: [],
+ createEntities: deletedEntityData || [],
+ deleteEntities: createdEntityData || [],
+ selectCreated: true
+ };
+ var redoData = {
+ editEntities: [],
+ createEntities: createdEntityData || [],
+ deleteEntities: deletedEntityData || [],
+ selectCreated: true
+ };
+ for (var i = 0; i < SelectionManager.selections.length; i++) {
+ var entityID = SelectionManager.selections[i];
+ var initialProperties = SelectionManager.savedProperties[entityID];
+ var currentProperties = null;
+ if (!initialProperties) {
+ continue;
+ }
+
+ if (doNotSaveEditProperties) {
+ initialProperties = null;
+ } else {
+ currentProperties = Entities.getEntityProperties(entityID);
+ }
+
+ undoData.editEntities.push({
+ entityID: entityID,
+ properties: initialProperties
+ });
+ redoData.editEntities.push({
+ entityID: entityID,
+ properties: currentProperties
+ });
+ }
+ undoHistory.pushCommand(applyEntityProperties, undoData, applyEntityProperties, redoData);
+ }
+
+ var ServerScriptStatusMonitor = function(entityID, statusCallback) {
+ var self = this;
+
+ self.entityID = entityID;
+ self.active = true;
+ self.sendRequestTimerID = null;
+
+ var onStatusReceived = function(success, isRunning, status, errorInfo) {
+ if (self.active) {
+ statusCallback({
+ statusRetrieved: success,
+ isRunning: isRunning,
+ status: status,
+ errorInfo: errorInfo
+ });
+ self.sendRequestTimerID = Script.setTimeout(function() {
+ if (self.active) {
+ Entities.getServerScriptStatus(entityID, onStatusReceived);
+ }
+ }, 1000);
+ }
+ };
+ self.stop = function() {
+ self.active = false;
};
- if (selectionUpdated) {
- resetScriptStatus();
+ Entities.getServerScriptStatus(entityID, onStatusReceived);
+ };
- if (selectionManager.selections.length !== 1) {
- if (statusMonitor !== null) {
- statusMonitor.stop();
- statusMonitor = null;
- }
- currentSelectedEntityID = null;
- } else if (currentSelectedEntityID !== selectionManager.selections[0]) {
- if (statusMonitor !== null) {
- statusMonitor.stop();
- }
- var entityID = selectionManager.selections[0];
- currentSelectedEntityID = entityID;
- statusMonitor = new ServerScriptStatusMonitor(entityID, updateScriptStatus);
- }
+ var PropertiesTool = function (opts) {
+ var that = {};
+
+ var webView = null;
+ webView = Tablet.getTablet("com.highfidelity.interface.tablet.system");
+ webView.setVisible = function(value) {};
+
+ var visible = false;
+
+ // This keeps track of the last entity ID that was selected. If multiple entities
+ // are selected or if no entity is selected this will be `null`.
+ var currentSelectedEntityID = null;
+ var statusMonitor = null;
+ var blockPropertyUpdates = false;
+
+ that.setVisible = function (newVisible) {
+ visible = newVisible;
+ webView.setVisible(shouldUseEditTabletApp() && visible);
+ createToolsWindow.setVisible(!shouldUseEditTabletApp() && visible);
+ };
+
+ that.setVisible(false);
+
+ function emitScriptEvent(data) {
+ var dataString = JSON.stringify(data);
+ webView.emitScriptEvent(dataString);
+ createToolsWindow.emitScriptEvent(dataString);
}
- var selections = [];
- for (var i = 0; i < selectionManager.selections.length; i++) {
- var entity = {};
- entity.id = selectionManager.selections[i];
- entity.properties = Entities.getEntityProperties(selectionManager.selections[i]);
- if (entity.properties.rotation !== undefined) {
- entity.properties.rotation = Quat.safeEulerAngles(entity.properties.rotation);
- }
- if (entity.properties.localRotation !== undefined) {
- entity.properties.localRotation = Quat.safeEulerAngles(entity.properties.localRotation);
- }
- if (entity.properties.emitOrientation !== undefined) {
- entity.properties.emitOrientation = Quat.safeEulerAngles(entity.properties.emitOrientation);
- }
- if (entity.properties.keyLight !== undefined && entity.properties.keyLight.direction !== undefined) {
- entity.properties.keyLight.direction = Vec3.toPolar(entity.properties.keyLight.direction);
- entity.properties.keyLight.direction.z = 0.0;
- }
- selections.push(entity);
+ function updateScriptStatus(info) {
+ info.type = "server_script_status";
+ emitScriptEvent(info);
}
- data.selections = selections;
- emitScriptEvent(data);
- }
- selectionManager.addEventListener(updateSelections, this);
-
-
- var onWebEventReceived = function(data) {
- try {
- data = JSON.parse(data);
- } catch(e) {
- return;
- }
- var i, properties, dY, diff, newPosition;
- if (data.type === "update") {
-
- if (data.properties || data.propertiesMap) {
- var propertiesMap = data.propertiesMap;
- if (propertiesMap === undefined) {
- propertiesMap = [{
- entityIDs: data.ids,
- properties: data.properties,
- }];
- }
-
- var sendListUpdate = false;
- propertiesMap.forEach(function(propertiesObject) {
- var properties = propertiesObject.properties;
- var updateEntityIDs = propertiesObject.entityIDs;
- if (properties.dynamic === false) {
- // this object is leaving dynamic, so we zero its velocities
- properties.localVelocity = Vec3.ZERO;
- properties.localAngularVelocity = Vec3.ZERO;
- }
- if (properties.rotation !== undefined) {
- properties.rotation = Quat.fromVec3Degrees(properties.rotation);
- }
- if (properties.localRotation !== undefined) {
- properties.localRotation = Quat.fromVec3Degrees(properties.localRotation);
- }
- if (properties.emitOrientation !== undefined) {
- properties.emitOrientation = Quat.fromVec3Degrees(properties.emitOrientation);
- }
- if (properties.keyLight !== undefined && properties.keyLight.direction !== undefined) {
- var currentKeyLightDirection = Vec3.toPolar(Entities.getEntityProperties(selectionManager.selections[0], ['keyLight.direction']).keyLight.direction);
- if (properties.keyLight.direction.x === undefined) {
- properties.keyLight.direction.x = currentKeyLightDirection.x;
- }
- if (properties.keyLight.direction.y === undefined) {
- properties.keyLight.direction.y = currentKeyLightDirection.y;
- }
- properties.keyLight.direction = Vec3.fromPolar(properties.keyLight.direction.x, properties.keyLight.direction.y);
- }
-
- updateEntityIDs.forEach(function (entityID) {
- Entities.editEntity(entityID, properties);
- });
-
- if (properties.name !== undefined || properties.modelURL !== undefined || properties.imageURL !== undefined ||
- properties.materialURL !== undefined || properties.visible !== undefined || properties.locked !== undefined) {
-
- sendListUpdate = true;
- }
-
- });
- if (sendListUpdate) {
- entityListTool.sendUpdate();
- }
- }
-
- if (data.onlyUpdateEntities) {
- blockPropertyUpdates = true;
- } else {
- pushCommandForSelections();
- SelectionManager.saveProperties();
- }
- selectionManager._update(false, this);
- blockPropertyUpdates = false;
-
- if (data.snapToGrid !== undefined) {
- entityListTool.setListMenuSnapToGrid(data.snapToGrid);
- }
- } else if (data.type === 'saveUserData' || data.type === 'saveMaterialData') {
- data.ids.forEach(function(entityID) {
- Entities.editEntity(entityID, data.properties);
+ function resetScriptStatus() {
+ updateScriptStatus({
+ statusRetrieved: undefined,
+ isRunning: undefined,
+ status: "",
+ errorInfo: ""
});
- } else if (data.type === "showMarketplace") {
- showMarketplace();
- } else if (data.type === "action") {
- if (data.action === "moveSelectionToGrid") {
- if (selectionManager.hasSelection()) {
- selectionManager.saveProperties();
- dY = grid.getOrigin().y - (selectionManager.worldPosition.y - selectionManager.worldDimensions.y / 2);
- diff = {
- x: 0,
- y: dY,
- z: 0
- };
- for (i = 0; i < selectionManager.selections.length; i++) {
- properties = selectionManager.savedProperties[selectionManager.selections[i]];
- newPosition = Vec3.sum(properties.position, diff);
- Entities.editEntity(selectionManager.selections[i], {
- position: newPosition
- });
- }
- pushCommandForSelections();
- selectionManager._update(false, this);
+ }
+
+ that.setSpaceMode = function(spaceMode) {
+ emitScriptEvent({
+ type: 'setSpaceMode',
+ spaceMode: spaceMode
+ })
+ };
+
+ function updateSelections(selectionUpdated, caller) {
+ if (HMD.active && visible) {
+ webView.setLandscape(true);
+ } else {
+ if (!visible) {
+ hmdMultiSelectMode = false;
+ webView.setLandscape(false);
}
- } else if (data.action === "moveAllToGrid") {
- if (selectionManager.hasSelection()) {
- selectionManager.saveProperties();
- for (i = 0; i < selectionManager.selections.length; i++) {
- properties = selectionManager.savedProperties[selectionManager.selections[i]];
- var bottomY = properties.boundingBox.center.y - properties.boundingBox.dimensions.y / 2;
- dY = grid.getOrigin().y - bottomY;
+ }
+
+ if (blockPropertyUpdates) {
+ return;
+ }
+
+ var data = {
+ type: 'update',
+ spaceMode: selectionDisplay.getSpaceMode(),
+ isPropertiesToolUpdate: caller === this,
+ };
+
+ if (selectionUpdated) {
+ resetScriptStatus();
+
+ if (selectionManager.selections.length !== 1) {
+ if (statusMonitor !== null) {
+ statusMonitor.stop();
+ statusMonitor = null;
+ }
+ currentSelectedEntityID = null;
+ } else if (currentSelectedEntityID !== selectionManager.selections[0]) {
+ if (statusMonitor !== null) {
+ statusMonitor.stop();
+ }
+ var entityID = selectionManager.selections[0];
+ currentSelectedEntityID = entityID;
+ statusMonitor = new ServerScriptStatusMonitor(entityID, updateScriptStatus);
+ }
+ }
+
+ var selections = [];
+ for (var i = 0; i < selectionManager.selections.length; i++) {
+ var entity = {};
+ entity.id = selectionManager.selections[i];
+ entity.properties = Entities.getEntityProperties(selectionManager.selections[i]);
+ if (entity.properties.rotation !== undefined) {
+ entity.properties.rotation = Quat.safeEulerAngles(entity.properties.rotation);
+ }
+ if (entity.properties.localRotation !== undefined) {
+ entity.properties.localRotation = Quat.safeEulerAngles(entity.properties.localRotation);
+ }
+ if (entity.properties.emitOrientation !== undefined) {
+ entity.properties.emitOrientation = Quat.safeEulerAngles(entity.properties.emitOrientation);
+ }
+ if (entity.properties.keyLight !== undefined && entity.properties.keyLight.direction !== undefined) {
+ entity.properties.keyLight.direction = Vec3.toPolar(entity.properties.keyLight.direction);
+ entity.properties.keyLight.direction.z = 0.0;
+ }
+ selections.push(entity);
+ }
+ data.selections = selections;
+
+ emitScriptEvent(data);
+ }
+ selectionManager.addEventListener(updateSelections, this);
+
+
+ var onWebEventReceived = function(data) {
+ try {
+ data = JSON.parse(data);
+ } catch(e) {
+ return;
+ }
+ var i, properties, dY, diff, newPosition;
+ if (data.type === "update") {
+
+ if (data.properties || data.propertiesMap) {
+ var propertiesMap = data.propertiesMap;
+ if (propertiesMap === undefined) {
+ propertiesMap = [{
+ entityIDs: data.ids,
+ properties: data.properties,
+ }];
+ }
+
+ var sendListUpdate = false;
+ propertiesMap.forEach(function(propertiesObject) {
+ var properties = propertiesObject.properties;
+ var updateEntityIDs = propertiesObject.entityIDs;
+ if (properties.dynamic === false) {
+ // this object is leaving dynamic, so we zero its velocities
+ properties.localVelocity = Vec3.ZERO;
+ properties.localAngularVelocity = Vec3.ZERO;
+ }
+ if (properties.rotation !== undefined) {
+ properties.rotation = Quat.fromVec3Degrees(properties.rotation);
+ }
+ if (properties.localRotation !== undefined) {
+ properties.localRotation = Quat.fromVec3Degrees(properties.localRotation);
+ }
+ if (properties.emitOrientation !== undefined) {
+ properties.emitOrientation = Quat.fromVec3Degrees(properties.emitOrientation);
+ }
+ if (properties.keyLight !== undefined && properties.keyLight.direction !== undefined) {
+ var currentKeyLightDirection = Vec3.toPolar(Entities.getEntityProperties(selectionManager.selections[0], ['keyLight.direction']).keyLight.direction);
+ if (properties.keyLight.direction.x === undefined) {
+ properties.keyLight.direction.x = currentKeyLightDirection.x;
+ }
+ if (properties.keyLight.direction.y === undefined) {
+ properties.keyLight.direction.y = currentKeyLightDirection.y;
+ }
+ properties.keyLight.direction = Vec3.fromPolar(properties.keyLight.direction.x, properties.keyLight.direction.y);
+ }
+
+ updateEntityIDs.forEach(function (entityID) {
+ Entities.editEntity(entityID, properties);
+ });
+
+ if (properties.name !== undefined || properties.modelURL !== undefined || properties.imageURL !== undefined ||
+ properties.materialURL !== undefined || properties.visible !== undefined || properties.locked !== undefined) {
+
+ sendListUpdate = true;
+ }
+
+ });
+ if (sendListUpdate) {
+ entityListTool.sendUpdate();
+ }
+ }
+
+ if (data.onlyUpdateEntities) {
+ blockPropertyUpdates = true;
+ } else {
+ createApp.pushCommandForSelections();
+ SelectionManager.saveProperties();
+ }
+ selectionManager._update(false, this);
+ blockPropertyUpdates = false;
+
+ if (data.snapToGrid !== undefined) {
+ entityListTool.setListMenuSnapToGrid(data.snapToGrid);
+ }
+ } else if (data.type === 'saveUserData' || data.type === 'saveMaterialData') {
+ data.ids.forEach(function(entityID) {
+ Entities.editEntity(entityID, data.properties);
+ });
+ } else if (data.type === "showMarketplace") {
+ showMarketplace();
+ } else if (data.type === "action") {
+ if (data.action === "moveSelectionToGrid") {
+ if (selectionManager.hasSelection()) {
+ selectionManager.saveProperties();
+ dY = grid.getOrigin().y - (selectionManager.worldPosition.y - selectionManager.worldDimensions.y / 2);
diff = {
x: 0,
y: dY,
z: 0
};
- newPosition = Vec3.sum(properties.position, diff);
- Entities.editEntity(selectionManager.selections[i], {
- position: newPosition
- });
- }
- pushCommandForSelections();
- selectionManager._update(false, this);
- }
- } else if (data.action === "resetToNaturalDimensions") {
- if (selectionManager.hasSelection()) {
- selectionManager.saveProperties();
- for (i = 0; i < selectionManager.selections.length; i++) {
- properties = selectionManager.savedProperties[selectionManager.selections[i]];
- var naturalDimensions = properties.naturalDimensions;
-
- // If any of the natural dimensions are not 0, resize
- if (properties.type === "Model" && naturalDimensions.x === 0 && naturalDimensions.y === 0 &&
- naturalDimensions.z === 0) {
- Window.notifyEditError("Cannot reset entity to its natural dimensions: Model URL" +
- " is invalid or the model has not yet been loaded.");
- } else {
+ for (i = 0; i < selectionManager.selections.length; i++) {
+ properties = selectionManager.savedProperties[selectionManager.selections[i]];
+ newPosition = Vec3.sum(properties.position, diff);
Entities.editEntity(selectionManager.selections[i], {
- dimensions: properties.naturalDimensions
+ position: newPosition
+ });
+ }
+ createApp.pushCommandForSelections();
+ selectionManager._update(false, this);
+ }
+ } else if (data.action === "moveAllToGrid") {
+ if (selectionManager.hasSelection()) {
+ selectionManager.saveProperties();
+ for (i = 0; i < selectionManager.selections.length; i++) {
+ properties = selectionManager.savedProperties[selectionManager.selections[i]];
+ var bottomY = properties.boundingBox.center.y - properties.boundingBox.dimensions.y / 2;
+ dY = grid.getOrigin().y - bottomY;
+ diff = {
+ x: 0,
+ y: dY,
+ z: 0
+ };
+ newPosition = Vec3.sum(properties.position, diff);
+ Entities.editEntity(selectionManager.selections[i], {
+ position: newPosition
+ });
+ }
+ createApp.pushCommandForSelections();
+ selectionManager._update(false, this);
+ }
+ } else if (data.action === "resetToNaturalDimensions") {
+ if (selectionManager.hasSelection()) {
+ selectionManager.saveProperties();
+ for (i = 0; i < selectionManager.selections.length; i++) {
+ properties = selectionManager.savedProperties[selectionManager.selections[i]];
+ var naturalDimensions = properties.naturalDimensions;
+
+ // If any of the natural dimensions are not 0, resize
+ if (properties.type === "Model" && naturalDimensions.x === 0 && naturalDimensions.y === 0 &&
+ naturalDimensions.z === 0) {
+ Window.notifyEditError("Cannot reset entity to its natural dimensions: Model URL" +
+ " is invalid or the model has not yet been loaded.");
+ } else {
+ Entities.editEntity(selectionManager.selections[i], {
+ dimensions: properties.naturalDimensions
+ });
+ }
+ }
+ createApp.pushCommandForSelections();
+ selectionManager._update(false, this);
+ }
+ } else if (data.action === "previewCamera") {
+ if (selectionManager.hasSelection()) {
+ Camera.mode = "entity";
+ Camera.cameraEntity = selectionManager.selections[0];
+ }
+ } else if (data.action === "rescaleDimensions") {
+ var multiplier = data.percentage / 100.0;
+ if (selectionManager.hasSelection()) {
+ selectionManager.saveProperties();
+ for (i = 0; i < selectionManager.selections.length; i++) {
+ properties = selectionManager.savedProperties[selectionManager.selections[i]];
+ Entities.editEntity(selectionManager.selections[i], {
+ dimensions: Vec3.multiply(multiplier, properties.dimensions)
+ });
+ }
+ createApp.pushCommandForSelections();
+ selectionManager._update(false, this);
+ }
+ } else if (data.action === "reloadClientScripts") {
+ if (selectionManager.hasSelection()) {
+ var timestamp = Date.now();
+ for (i = 0; i < selectionManager.selections.length; i++) {
+ Entities.editEntity(selectionManager.selections[i], {
+ scriptTimestamp: timestamp
});
}
}
- pushCommandForSelections();
- selectionManager._update(false, this);
- }
- } else if (data.action === "previewCamera") {
- if (selectionManager.hasSelection()) {
- Camera.mode = "entity";
- Camera.cameraEntity = selectionManager.selections[0];
- }
- } else if (data.action === "rescaleDimensions") {
- var multiplier = data.percentage / 100.0;
- if (selectionManager.hasSelection()) {
- selectionManager.saveProperties();
- for (i = 0; i < selectionManager.selections.length; i++) {
- properties = selectionManager.savedProperties[selectionManager.selections[i]];
- Entities.editEntity(selectionManager.selections[i], {
- dimensions: Vec3.multiply(multiplier, properties.dimensions)
- });
+ } else if (data.action === "reloadServerScripts") {
+ if (selectionManager.hasSelection()) {
+ for (i = 0; i < selectionManager.selections.length; i++) {
+ Entities.reloadServerScripts(selectionManager.selections[i]);
+ }
}
- pushCommandForSelections();
- selectionManager._update(false, this);
- }
- } else if (data.action === "reloadClientScripts") {
- if (selectionManager.hasSelection()) {
- var timestamp = Date.now();
- for (i = 0; i < selectionManager.selections.length; i++) {
- Entities.editEntity(selectionManager.selections[i], {
- scriptTimestamp: timestamp
- });
+ } else if (data.action === "copyPosition") {
+ if (selectionManager.selections.length === 1) {
+ selectionManager.saveProperties();
+ properties = selectionManager.savedProperties[selectionManager.selections[0]];
+ copiedPosition = properties.position;
+ Window.copyToClipboard(JSON.stringify(copiedPosition));
}
- }
- } else if (data.action === "reloadServerScripts") {
- if (selectionManager.hasSelection()) {
- for (i = 0; i < selectionManager.selections.length; i++) {
- Entities.reloadServerScripts(selectionManager.selections[i]);
+ } else if (data.action === "copyRotation") {
+ if (selectionManager.selections.length === 1) {
+ selectionManager.saveProperties();
+ properties = selectionManager.savedProperties[selectionManager.selections[0]];
+ copiedRotation = properties.rotation;
+ Window.copyToClipboard(JSON.stringify(copiedRotation));
}
- }
- } else if (data.action === "copyPosition") {
- if (selectionManager.selections.length === 1) {
- selectionManager.saveProperties();
- properties = selectionManager.savedProperties[selectionManager.selections[0]];
- copiedPosition = properties.position;
- Window.copyToClipboard(JSON.stringify(copiedPosition));
- }
- } else if (data.action === "copyRotation") {
- if (selectionManager.selections.length === 1) {
- selectionManager.saveProperties();
- properties = selectionManager.savedProperties[selectionManager.selections[0]];
- copiedRotation = properties.rotation;
- Window.copyToClipboard(JSON.stringify(copiedRotation));
- }
- } else if (data.action === "pastePosition") {
- if (copiedPosition !== undefined && selectionManager.selections.length > 0 && SelectionManager.hasUnlockedSelection()) {
- selectionManager.saveProperties();
- for (i = 0; i < selectionManager.selections.length; i++) {
- Entities.editEntity(selectionManager.selections[i], {
- position: copiedPosition
- });
- }
- pushCommandForSelections();
- selectionManager._update(false, this);
- } else {
- audioFeedback.rejection();
- }
- } else if (data.action === "pasteRotation") {
- if (copiedRotation !== undefined && selectionManager.selections.length > 0 && SelectionManager.hasUnlockedSelection()) {
- selectionManager.saveProperties();
- for (i = 0; i < selectionManager.selections.length; i++) {
- Entities.editEntity(selectionManager.selections[i], {
- rotation: copiedRotation
- });
- }
- pushCommandForSelections();
- selectionManager._update(false, this);
- } else {
- audioFeedback.rejection();
- }
- } else if (data.action === "setRotationToZero") {
- if (selectionManager.selections.length === 1 && SelectionManager.hasUnlockedSelection()) {
- selectionManager.saveProperties();
- var parentState = getParentState(selectionManager.selections[0]);
- if ((parentState === "PARENT_CHILDREN" || parentState === "CHILDREN") && selectionDisplay.getSpaceMode() === "local" ) {
- Entities.editEntity(selectionManager.selections[0], {
- localRotation: Quat.IDENTITY
- });
+ } else if (data.action === "pastePosition") {
+ if (copiedPosition !== undefined && selectionManager.selections.length > 0 && SelectionManager.hasUnlockedSelection()) {
+ selectionManager.saveProperties();
+ for (i = 0; i < selectionManager.selections.length; i++) {
+ Entities.editEntity(selectionManager.selections[i], {
+ position: copiedPosition
+ });
+ }
+ createApp.pushCommandForSelections();
+ selectionManager._update(false, this);
} else {
- Entities.editEntity(selectionManager.selections[0], {
- rotation: Quat.IDENTITY
- });
+ audioFeedback.rejection();
+ }
+ } else if (data.action === "pasteRotation") {
+ if (copiedRotation !== undefined && selectionManager.selections.length > 0 && SelectionManager.hasUnlockedSelection()) {
+ selectionManager.saveProperties();
+ for (i = 0; i < selectionManager.selections.length; i++) {
+ Entities.editEntity(selectionManager.selections[i], {
+ rotation: copiedRotation
+ });
+ }
+ createApp.pushCommandForSelections();
+ selectionManager._update(false, this);
+ } else {
+ audioFeedback.rejection();
+ }
+ } else if (data.action === "setRotationToZero") {
+ if (selectionManager.selections.length === 1 && SelectionManager.hasUnlockedSelection()) {
+ selectionManager.saveProperties();
+ var parentState = getParentState(selectionManager.selections[0]);
+ if ((parentState === "PARENT_CHILDREN" || parentState === "CHILDREN") && selectionDisplay.getSpaceMode() === "local" ) {
+ Entities.editEntity(selectionManager.selections[0], {
+ localRotation: Quat.IDENTITY
+ });
+ } else {
+ Entities.editEntity(selectionManager.selections[0], {
+ rotation: Quat.IDENTITY
+ });
+ }
+ createApp.pushCommandForSelections();
+ selectionManager._update(false, this);
+ } else {
+ audioFeedback.rejection();
}
- pushCommandForSelections();
- selectionManager._update(false, this);
- } else {
- audioFeedback.rejection();
}
+ } else if (data.type === "propertiesPageReady") {
+ updateSelections(true);
+ } else if (data.type === "tooltipsRequest") {
+ emitScriptEvent({
+ type: 'tooltipsReply',
+ tooltips: Script.require('./assets/data/createAppTooltips.json'),
+ hmdActive: HMD.active,
+ });
+ } else if (data.type === "propertyRangeRequest") {
+ var propertyRanges = {};
+ data.properties.forEach(function (property) {
+ propertyRanges[property] = Entities.getPropertyInfo(property);
+ });
+ emitScriptEvent({
+ type: 'propertyRangeReply',
+ propertyRanges: propertyRanges,
+ });
+ } else if (data.type === "materialTargetRequest") {
+ var parentModelData;
+ var properties = Entities.getEntityProperties(data.entityID, ["type", "parentID"]);
+ if (properties.type === "Material" && properties.parentID !== Uuid.NULL) {
+ var parentType = Entities.getEntityProperties(properties.parentID, ["type"]).type;
+ if (parentType === "Model" || Entities.getNestableType(properties.parentID) === "avatar") {
+ parentModelData = Graphics.getModel(properties.parentID);
+ } else if (parentType === "Shape" || parentType === "Box" || parentType === "Sphere") {
+ parentModelData = {};
+ parentModelData.numMeshes = 1;
+ parentModelData.materialNames = [];
+ }
+ }
+ emitScriptEvent({
+ type: 'materialTargetReply',
+ entityID: data.entityID,
+ materialTargetData: parentModelData,
+ });
+ } else if (data.type === "zoneListRequest") {
+ emitScriptEvent({
+ type: 'zoneListRequest',
+ zones: getExistingZoneList()
+ });
}
- } else if (data.type === "propertiesPageReady") {
- updateSelections(true);
- } else if (data.type === "tooltipsRequest") {
+ };
+
+ HMD.displayModeChanged.connect(function() {
emitScriptEvent({
- type: 'tooltipsReply',
- tooltips: Script.require('./assets/data/createAppTooltips.json'),
+ type: 'hmdActiveChanged',
hmdActive: HMD.active,
});
- } else if (data.type === "propertyRangeRequest") {
- var propertyRanges = {};
- data.properties.forEach(function (property) {
- propertyRanges[property] = Entities.getPropertyInfo(property);
- });
- emitScriptEvent({
- type: 'propertyRangeReply',
- propertyRanges: propertyRanges,
- });
- } else if (data.type === "materialTargetRequest") {
- var parentModelData;
- var properties = Entities.getEntityProperties(data.entityID, ["type", "parentID"]);
- if (properties.type === "Material" && properties.parentID !== Uuid.NULL) {
- var parentType = Entities.getEntityProperties(properties.parentID, ["type"]).type;
- if (parentType === "Model" || Entities.getNestableType(properties.parentID) === "avatar") {
- parentModelData = Graphics.getModel(properties.parentID);
- } else if (parentType === "Shape" || parentType === "Box" || parentType === "Sphere") {
- parentModelData = {};
- parentModelData.numMeshes = 1;
- parentModelData.materialNames = [];
- }
- }
- emitScriptEvent({
- type: 'materialTargetReply',
- entityID: data.entityID,
- materialTargetData: parentModelData,
- });
- } else if (data.type === "zoneListRequest") {
- emitScriptEvent({
- type: 'zoneListRequest',
- zones: getExistingZoneList()
- });
- }
- };
-
- HMD.displayModeChanged.connect(function() {
- emitScriptEvent({
- type: 'hmdActiveChanged',
- hmdActive: HMD.active,
});
- });
- createToolsWindow.webEventReceived.addListener(this, onWebEventReceived);
+ createToolsWindow.webEventReceived.addListener(this, onWebEventReceived);
- webView.webEventReceived.connect(this, onWebEventReceived);
+ webView.webEventReceived.connect(this, onWebEventReceived);
- return that;
-};
-
-
-var PopupMenu = function () {
- var self = this;
-
- var MENU_ITEM_HEIGHT = 21;
- var MENU_ITEM_SPACING = 1;
- var TEXT_MARGIN = 7;
-
- var overlays = [];
- var overlayInfo = {};
-
- var visible = false;
-
- var upColor = {
- red: 0,
- green: 0,
- blue: 0
- };
- var downColor = {
- red: 192,
- green: 192,
- blue: 192
- };
- var overColor = {
- red: 128,
- green: 128,
- blue: 128
+ return that;
};
- self.onSelectMenuItem = function () {};
- self.addMenuItem = function (name) {
- var id = Overlays.addOverlay("text", {
- text: name,
- backgroundAlpha: 1.0,
- backgroundColor: upColor,
- topMargin: TEXT_MARGIN,
- leftMargin: TEXT_MARGIN,
- width: 210,
- height: MENU_ITEM_HEIGHT,
- font: {
- size: 12
- },
- visible: false
- });
- overlays.push(id);
- overlayInfo[id] = {
- name: name
+ var PopupMenu = function () {
+ var self = this;
+
+ var MENU_ITEM_HEIGHT = 21;
+ var MENU_ITEM_SPACING = 1;
+ var TEXT_MARGIN = 7;
+
+ var overlays = [];
+ var overlayInfo = {};
+
+ var visible = false;
+
+ var upColor = {
+ red: 0,
+ green: 0,
+ blue: 0
+ };
+ var downColor = {
+ red: 192,
+ green: 192,
+ blue: 192
+ };
+ var overColor = {
+ red: 128,
+ green: 128,
+ blue: 128
};
- return id;
- };
- self.updateMenuItemText = function (id, newText) {
- Overlays.editOverlay(id, {
- text: newText
- });
- };
+ self.onSelectMenuItem = function () {};
- self.setPosition = function (x, y) {
- for (var key in overlayInfo) {
- Overlays.editOverlay(key, {
- x: x,
- y: y
+ self.addMenuItem = function (name) {
+ var id = Overlays.addOverlay("text", {
+ text: name,
+ backgroundAlpha: 1.0,
+ backgroundColor: upColor,
+ topMargin: TEXT_MARGIN,
+ leftMargin: TEXT_MARGIN,
+ width: 210,
+ height: MENU_ITEM_HEIGHT,
+ font: {
+ size: 12
+ },
+ visible: false
});
- y += MENU_ITEM_HEIGHT + MENU_ITEM_SPACING;
- }
- };
+ overlays.push(id);
+ overlayInfo[id] = {
+ name: name
+ };
+ return id;
+ };
- self.onSelected = function () {};
-
- var pressingOverlay = null;
- var hoveringOverlay = null;
-
- self.mousePressEvent = function (event) {
- if (event.isLeftButton) {
- var overlay = Overlays.getOverlayAtPoint({
- x: event.x,
- y: event.y
+ self.updateMenuItemText = function (id, newText) {
+ Overlays.editOverlay(id, {
+ text: newText
});
- if (overlay in overlayInfo) {
- pressingOverlay = overlay;
- Overlays.editOverlay(pressingOverlay, {
- backgroundColor: downColor
- });
- } else {
- self.hide();
- }
- return false;
- }
- };
- self.mouseMoveEvent = function (event) {
- if (visible) {
- var overlay = Overlays.getOverlayAtPoint({
- x: event.x,
- y: event.y
- });
- if (!pressingOverlay) {
- if (hoveringOverlay !== null && overlay !== hoveringOverlay) {
- Overlays.editOverlay(hoveringOverlay, {
- backgroundColor: upColor
- });
- hoveringOverlay = null;
- }
- if (overlay !== hoveringOverlay && overlay in overlayInfo) {
- Overlays.editOverlay(overlay, {
- backgroundColor: overColor
- });
- hoveringOverlay = overlay;
- }
- }
- }
- return false;
- };
- self.mouseReleaseEvent = function (event) {
- var overlay = Overlays.getOverlayAtPoint({
- x: event.x,
- y: event.y
- });
- if (pressingOverlay !== null && pressingOverlay !== undefined) {
- if (overlay === pressingOverlay) {
- self.onSelectMenuItem(overlayInfo[overlay].name);
- }
- Overlays.editOverlay(pressingOverlay, {
- backgroundColor: upColor
- });
- pressingOverlay = null;
- self.hide();
- }
- };
+ };
- self.setVisible = function (newVisible) {
- if (newVisible !== visible) {
- visible = newVisible;
+ self.setPosition = function (x, y) {
for (var key in overlayInfo) {
Overlays.editOverlay(key, {
- visible: newVisible
+ x: x,
+ y: y
});
+ y += MENU_ITEM_HEIGHT + MENU_ITEM_SPACING;
+ }
+ };
+
+ self.onSelected = function () {};
+
+ var pressingOverlay = null;
+ var hoveringOverlay = null;
+
+ self.mousePressEvent = function (event) {
+ if (event.isLeftButton) {
+ var overlay = Overlays.getOverlayAtPoint({
+ x: event.x,
+ y: event.y
+ });
+ if (overlay in overlayInfo) {
+ pressingOverlay = overlay;
+ Overlays.editOverlay(pressingOverlay, {
+ backgroundColor: downColor
+ });
+ } else {
+ self.hide();
+ }
+ return false;
+ }
+ };
+ self.mouseMoveEvent = function (event) {
+ if (visible) {
+ var overlay = Overlays.getOverlayAtPoint({
+ x: event.x,
+ y: event.y
+ });
+ if (!pressingOverlay) {
+ if (hoveringOverlay !== null && overlay !== hoveringOverlay) {
+ Overlays.editOverlay(hoveringOverlay, {
+ backgroundColor: upColor
+ });
+ hoveringOverlay = null;
+ }
+ if (overlay !== hoveringOverlay && overlay in overlayInfo) {
+ Overlays.editOverlay(overlay, {
+ backgroundColor: overColor
+ });
+ hoveringOverlay = overlay;
+ }
+ }
+ }
+ return false;
+ };
+ self.mouseReleaseEvent = function (event) {
+ var overlay = Overlays.getOverlayAtPoint({
+ x: event.x,
+ y: event.y
+ });
+ if (pressingOverlay !== null && pressingOverlay !== undefined) {
+ if (overlay === pressingOverlay) {
+ self.onSelectMenuItem(overlayInfo[overlay].name);
+ }
+ Overlays.editOverlay(pressingOverlay, {
+ backgroundColor: upColor
+ });
+ pressingOverlay = null;
+ self.hide();
+ }
+ };
+
+ self.setVisible = function (newVisible) {
+ if (newVisible !== visible) {
+ visible = newVisible;
+ for (var key in overlayInfo) {
+ Overlays.editOverlay(key, {
+ visible: newVisible
+ });
+ }
+ }
+ };
+ self.show = function () {
+ self.setVisible(true);
+ };
+ self.hide = function () {
+ self.setVisible(false);
+ };
+
+ function cleanup() {
+ ContextOverlay.enabled = true;
+ for (var i = 0; i < overlays.length; i++) {
+ Overlays.deleteOverlay(overlays[i]);
+ }
+ Controller.mousePressEvent.disconnect(self.mousePressEvent);
+ Controller.mouseMoveEvent.disconnect(self.mouseMoveEvent);
+ Controller.mouseReleaseEvent.disconnect(self.mouseReleaseEvent);
+
+ Entities.canRezChanged.disconnect(checkEditPermissionsAndUpdate);
+ Entities.canRezTmpChanged.disconnect(checkEditPermissionsAndUpdate);
+ Entities.canRezCertifiedChanged.disconnect(checkEditPermissionsAndUpdate);
+ Entities.canRezTmpCertifiedChanged.disconnect(checkEditPermissionsAndUpdate);
+ }
+
+ Controller.mousePressEvent.connect(self.mousePressEvent);
+ Controller.mouseMoveEvent.connect(self.mouseMoveEvent);
+ Controller.mouseReleaseEvent.connect(self.mouseReleaseEvent);
+ Script.scriptEnding.connect(cleanup);
+
+ return this;
+ };
+
+ function whenPressed(fn) {
+ return function(value) {
+ if (value > 0) {
+ fn();
+ }
+ };
+ }
+
+ function whenReleased(fn) {
+ return function(value) {
+ if (value === 0) {
+ fn();
+ }
+ };
+ }
+
+ var isOnMacPlatform = Controller.getValue(Controller.Hardware.Application.PlatformMac);
+
+ var mapping = Controller.newMapping(CONTROLLER_MAPPING_NAME);
+ if (isOnMacPlatform) {
+ mapping.from([Controller.Hardware.Keyboard.Backspace]).to(deleteKey);
+ } else {
+ mapping.from([Controller.Hardware.Keyboard.Delete]).to(deleteKey);
+ }
+ mapping.from([Controller.Hardware.Keyboard.T]).to(toggleKey);
+ mapping.from([Controller.Hardware.Keyboard.F]).to(focusKey);
+ mapping.from([Controller.Hardware.Keyboard.J]).to(gridKey);
+ mapping.from([Controller.Hardware.Keyboard.G]).to(viewGridKey);
+ mapping.from([Controller.Hardware.Keyboard.H]).to(snapKey);
+ mapping.from([Controller.Hardware.Keyboard.K]).to(gridToAvatarKey);
+ mapping.from([Controller.Hardware.Keyboard["0"]]).to(rotateAsNextClickedSurfaceKey);
+ mapping.from([Controller.Hardware.Keyboard["7"]]).to(quickRotate90xKey);
+ mapping.from([Controller.Hardware.Keyboard["8"]]).to(quickRotate90yKey);
+ mapping.from([Controller.Hardware.Keyboard["9"]]).to(quickRotate90zKey);
+ mapping.from([Controller.Hardware.Keyboard.X])
+ .when([Controller.Hardware.Keyboard.Control])
+ .to(whenReleased(function() { selectionManager.cutSelectedEntities() }));
+ mapping.from([Controller.Hardware.Keyboard.C])
+ .when([Controller.Hardware.Keyboard.Control])
+ .to(whenReleased(function() { selectionManager.copySelectedEntities() }));
+ mapping.from([Controller.Hardware.Keyboard.V])
+ .when([Controller.Hardware.Keyboard.Control])
+ .to(whenReleased(function() { selectionManager.pasteEntities() }));
+ mapping.from([Controller.Hardware.Keyboard.D])
+ .when([Controller.Hardware.Keyboard.Control])
+ .to(whenReleased(function() { selectionManager.duplicateSelection() }));
+
+ // Bind undo to ctrl-shift-z to maintain backwards-compatibility
+ mapping.from([Controller.Hardware.Keyboard.Z])
+ .when([Controller.Hardware.Keyboard.Control, Controller.Hardware.Keyboard.Shift])
+ .to(whenPressed(function() { undoHistory.redo() }));
+
+
+ mapping.from([Controller.Hardware.Keyboard.P])
+ .when([Controller.Hardware.Keyboard.Control, Controller.Hardware.Keyboard.Shift])
+ .to(whenReleased(function() { unparentSelectedEntities(); }));
+
+ mapping.from([Controller.Hardware.Keyboard.P])
+ .when([Controller.Hardware.Keyboard.Control, !Controller.Hardware.Keyboard.Shift])
+ .to(whenReleased(function() { parentSelectedEntities(); }));
+
+ var keyUpEventFromUIWindow = function(keyUpEvent) {
+ var WANT_DEBUG_MISSING_SHORTCUTS = false;
+
+ var pressedValue = 0.0;
+
+ if ((!isOnMacPlatform && keyUpEvent.keyCodeString === "Delete")
+ || (isOnMacPlatform && keyUpEvent.keyCodeString === "Backspace")) {
+
+ deleteKey(pressedValue);
+ } else if (keyUpEvent.keyCodeString === "T") {
+ toggleKey(pressedValue);
+ } else if (keyUpEvent.keyCodeString === "F") {
+ focusKey(pressedValue);
+ } else if (keyUpEvent.keyCodeString === "J") {
+ gridKey(pressedValue);
+ } else if (keyUpEvent.keyCodeString === "G") {
+ viewGridKey(pressedValue);
+ } else if (keyUpEvent.keyCodeString === "H") {
+ snapKey(pressedValue);
+ } else if (keyUpEvent.keyCodeString === "K") {
+ gridToAvatarKey(pressedValue);
+ } else if (keyUpEvent.keyCodeString === "0") {
+ rotateAsNextClickedSurfaceKey(pressedValue);
+ } else if (keyUpEvent.keyCodeString === "7") {
+ quickRotate90xKey(pressedValue);
+ } else if (keyUpEvent.keyCodeString === "8") {
+ quickRotate90yKey(pressedValue);
+ } else if (keyUpEvent.keyCodeString === "9") {
+ quickRotate90zKey(pressedValue);
+ } else if (keyUpEvent.controlKey && keyUpEvent.keyCodeString === "X") {
+ selectionManager.cutSelectedEntities();
+ } else if (keyUpEvent.controlKey && keyUpEvent.keyCodeString === "C") {
+ selectionManager.copySelectedEntities();
+ } else if (keyUpEvent.controlKey && keyUpEvent.keyCodeString === "V") {
+ selectionManager.pasteEntities();
+ } else if (keyUpEvent.controlKey && keyUpEvent.keyCodeString === "D") {
+ selectionManager.duplicateSelection();
+ } else if (!isOnMacPlatform && keyUpEvent.controlKey && !keyUpEvent.shiftKey && keyUpEvent.keyCodeString === "Z") {
+ undoHistory.undo(); // undo is only handled via handleMenuItem on Mac
+ } else if (keyUpEvent.controlKey && !keyUpEvent.shiftKey && keyUpEvent.keyCodeString === "P") {
+ parentSelectedEntities();
+ } else if (keyUpEvent.controlKey && keyUpEvent.shiftKey && keyUpEvent.keyCodeString === "P") {
+ unparentSelectedEntities();
+ } else if (!isOnMacPlatform &&
+ ((keyUpEvent.controlKey && keyUpEvent.shiftKey && keyUpEvent.keyCodeString === "Z") ||
+ (keyUpEvent.controlKey && keyUpEvent.keyCodeString === "Y"))) {
+ undoHistory.redo(); // redo is only handled via handleMenuItem on Mac
+ } else if (WANT_DEBUG_MISSING_SHORTCUTS) {
+ console.warn("unhandled key event: " + JSON.stringify(keyUpEvent))
+ }
+ };
+
+ var propertyMenu = new PopupMenu();
+
+ propertyMenu.onSelectMenuItem = function (name) {
+
+ if (propertyMenu.marketplaceID) {
+ showMarketplace(propertyMenu.marketplaceID);
+ }
+ };
+
+ var showMenuItem = propertyMenu.addMenuItem("Show in Marketplace");
+
+ var propertiesTool = new PropertiesTool();
+
+ selectionDisplay.onSpaceModeChange = function(spaceMode) {
+ entityListTool.setSpaceMode(spaceMode);
+ propertiesTool.setSpaceMode(spaceMode);
+ };
+
+ function getExistingZoneList() {
+ var center = { "x": 0, "y": 0, "z": 0 };
+ var existingZoneIDs = Entities.findEntitiesByType("Zone", center, ENTIRE_DOMAIN_SCAN_RADIUS);
+ var listExistingZones = [];
+ var thisZone = {};
+ var properties;
+ for (var k = 0; k < existingZoneIDs.length; k++) {
+ properties = Entities.getEntityProperties(existingZoneIDs[k], ["name"]);
+ thisZone = {
+ "id": existingZoneIDs[k],
+ "name": properties.name
+ };
+ listExistingZones.push(thisZone);
+ }
+ listExistingZones.sort(zoneSortOrder);
+ return listExistingZones;
+ }
+
+ function zoneSortOrder(a, b) {
+ var nameA = a.name.toUpperCase();
+ var nameB = b.name.toUpperCase();
+ if (nameA > nameB) {
+ return 1;
+ } else if (nameA < nameB) {
+ return -1;
+ }
+ if (a.name > b.name) {
+ return 1;
+ } else if (a.name < b.name) {
+ return -1;
+ }
+ return 0;
+ }
+
+ //print("getParentState added");
+ //function getParentState(id) {
+ createApp.getParentState = function(id) {
+ var state = "NONE";
+ var properties = Entities.getEntityProperties(id, ["parentID"]);
+ var children = getDomainOnlyChildrenIDs(id);
+ if (properties.parentID !== Uuid.NULL) {
+ if (children.length > 0) {
+ state = "PARENT_CHILDREN";
+ } else {
+ state = "CHILDREN";
+ }
+ } else {
+ if (children.length > 0) {
+ state = "PARENT";
}
}
- };
- self.show = function () {
- self.setVisible(true);
- };
- self.hide = function () {
- self.setVisible(false);
- };
+ return state;
+ }
- function cleanup() {
- ContextOverlay.enabled = true;
- for (var i = 0; i < overlays.length; i++) {
- Overlays.deleteOverlay(overlays[i]);
+ //print("Global object after getParentState" + JSON.stringify(globalThis));
+
+ function getDomainOnlyChildrenIDs(id) {
+ var allChildren = Entities.getChildrenIDs(id);
+ var realChildren = [];
+ var properties;
+ for (var i = 0; i < allChildren.length; i++) {
+ properties = Entities.getEntityProperties(allChildren[i], ["name"]);
+ if (properties.name !== undefined && properties.name !== entityShapeVisualizerSessionName) {
+ realChildren.push(allChildren[i]);
+ }
}
- Controller.mousePressEvent.disconnect(self.mousePressEvent);
- Controller.mouseMoveEvent.disconnect(self.mouseMoveEvent);
- Controller.mouseReleaseEvent.disconnect(self.mouseReleaseEvent);
-
- Entities.canRezChanged.disconnect(checkEditPermissionsAndUpdate);
- Entities.canRezTmpChanged.disconnect(checkEditPermissionsAndUpdate);
- Entities.canRezCertifiedChanged.disconnect(checkEditPermissionsAndUpdate);
- Entities.canRezTmpCertifiedChanged.disconnect(checkEditPermissionsAndUpdate);
+ return realChildren;
}
- Controller.mousePressEvent.connect(self.mousePressEvent);
- Controller.mouseMoveEvent.connect(self.mouseMoveEvent);
- Controller.mouseReleaseEvent.connect(self.mouseReleaseEvent);
- Script.scriptEnding.connect(cleanup);
-
- return this;
-};
-
-function whenPressed(fn) {
- return function(value) {
- if (value > 0) {
- fn();
- }
- };
-}
-
-function whenReleased(fn) {
- return function(value) {
- if (value === 0) {
- fn();
- }
- };
-}
-
-var isOnMacPlatform = Controller.getValue(Controller.Hardware.Application.PlatformMac);
-
-var mapping = Controller.newMapping(CONTROLLER_MAPPING_NAME);
-if (isOnMacPlatform) {
- mapping.from([Controller.Hardware.Keyboard.Backspace]).to(deleteKey);
-} else {
- mapping.from([Controller.Hardware.Keyboard.Delete]).to(deleteKey);
-}
-mapping.from([Controller.Hardware.Keyboard.T]).to(toggleKey);
-mapping.from([Controller.Hardware.Keyboard.F]).to(focusKey);
-mapping.from([Controller.Hardware.Keyboard.J]).to(gridKey);
-mapping.from([Controller.Hardware.Keyboard.G]).to(viewGridKey);
-mapping.from([Controller.Hardware.Keyboard.H]).to(snapKey);
-mapping.from([Controller.Hardware.Keyboard.K]).to(gridToAvatarKey);
-mapping.from([Controller.Hardware.Keyboard["0"]]).to(rotateAsNextClickedSurfaceKey);
-mapping.from([Controller.Hardware.Keyboard["7"]]).to(quickRotate90xKey);
-mapping.from([Controller.Hardware.Keyboard["8"]]).to(quickRotate90yKey);
-mapping.from([Controller.Hardware.Keyboard["9"]]).to(quickRotate90zKey);
-mapping.from([Controller.Hardware.Keyboard.X])
- .when([Controller.Hardware.Keyboard.Control])
- .to(whenReleased(function() { selectionManager.cutSelectedEntities() }));
-mapping.from([Controller.Hardware.Keyboard.C])
- .when([Controller.Hardware.Keyboard.Control])
- .to(whenReleased(function() { selectionManager.copySelectedEntities() }));
-mapping.from([Controller.Hardware.Keyboard.V])
- .when([Controller.Hardware.Keyboard.Control])
- .to(whenReleased(function() { selectionManager.pasteEntities() }));
-mapping.from([Controller.Hardware.Keyboard.D])
- .when([Controller.Hardware.Keyboard.Control])
- .to(whenReleased(function() { selectionManager.duplicateSelection() }));
-
-// Bind undo to ctrl-shift-z to maintain backwards-compatibility
-mapping.from([Controller.Hardware.Keyboard.Z])
- .when([Controller.Hardware.Keyboard.Control, Controller.Hardware.Keyboard.Shift])
- .to(whenPressed(function() { undoHistory.redo() }));
-
-
-mapping.from([Controller.Hardware.Keyboard.P])
- .when([Controller.Hardware.Keyboard.Control, Controller.Hardware.Keyboard.Shift])
- .to(whenReleased(function() { unparentSelectedEntities(); }));
-
-mapping.from([Controller.Hardware.Keyboard.P])
- .when([Controller.Hardware.Keyboard.Control, !Controller.Hardware.Keyboard.Shift])
- .to(whenReleased(function() { parentSelectedEntities(); }));
-
-var keyUpEventFromUIWindow = function(keyUpEvent) {
- var WANT_DEBUG_MISSING_SHORTCUTS = false;
-
- var pressedValue = 0.0;
-
- if ((!isOnMacPlatform && keyUpEvent.keyCodeString === "Delete")
- || (isOnMacPlatform && keyUpEvent.keyCodeString === "Backspace")) {
-
- deleteKey(pressedValue);
- } else if (keyUpEvent.keyCodeString === "T") {
- toggleKey(pressedValue);
- } else if (keyUpEvent.keyCodeString === "F") {
- focusKey(pressedValue);
- } else if (keyUpEvent.keyCodeString === "J") {
- gridKey(pressedValue);
- } else if (keyUpEvent.keyCodeString === "G") {
- viewGridKey(pressedValue);
- } else if (keyUpEvent.keyCodeString === "H") {
- snapKey(pressedValue);
- } else if (keyUpEvent.keyCodeString === "K") {
- gridToAvatarKey(pressedValue);
- } else if (keyUpEvent.keyCodeString === "0") {
- rotateAsNextClickedSurfaceKey(pressedValue);
- } else if (keyUpEvent.keyCodeString === "7") {
- quickRotate90xKey(pressedValue);
- } else if (keyUpEvent.keyCodeString === "8") {
- quickRotate90yKey(pressedValue);
- } else if (keyUpEvent.keyCodeString === "9") {
- quickRotate90zKey(pressedValue);
- } else if (keyUpEvent.controlKey && keyUpEvent.keyCodeString === "X") {
- selectionManager.cutSelectedEntities();
- } else if (keyUpEvent.controlKey && keyUpEvent.keyCodeString === "C") {
- selectionManager.copySelectedEntities();
- } else if (keyUpEvent.controlKey && keyUpEvent.keyCodeString === "V") {
- selectionManager.pasteEntities();
- } else if (keyUpEvent.controlKey && keyUpEvent.keyCodeString === "D") {
- selectionManager.duplicateSelection();
- } else if (!isOnMacPlatform && keyUpEvent.controlKey && !keyUpEvent.shiftKey && keyUpEvent.keyCodeString === "Z") {
- undoHistory.undo(); // undo is only handled via handleMenuItem on Mac
- } else if (keyUpEvent.controlKey && !keyUpEvent.shiftKey && keyUpEvent.keyCodeString === "P") {
- parentSelectedEntities();
- } else if (keyUpEvent.controlKey && keyUpEvent.shiftKey && keyUpEvent.keyCodeString === "P") {
- unparentSelectedEntities();
- } else if (!isOnMacPlatform &&
- ((keyUpEvent.controlKey && keyUpEvent.shiftKey && keyUpEvent.keyCodeString === "Z") ||
- (keyUpEvent.controlKey && keyUpEvent.keyCodeString === "Y"))) {
- undoHistory.redo(); // redo is only handled via handleMenuItem on Mac
- } else if (WANT_DEBUG_MISSING_SHORTCUTS) {
- console.warn("unhandled key event: " + JSON.stringify(keyUpEvent))
+ function importEntitiesFromFile() {
+ Window.browseChanged.connect(onFileOpenChanged);
+ Window.browseAsync("Select .json to Import", "", "*.json");
}
-};
-var propertyMenu = new PopupMenu();
-
-propertyMenu.onSelectMenuItem = function (name) {
-
- if (propertyMenu.marketplaceID) {
- showMarketplace(propertyMenu.marketplaceID);
+ function importEntitiesFromUrl() {
+ Window.promptTextChanged.connect(onPromptTextChanged);
+ Window.promptAsync("URL of a .json to import", "");
}
-};
-var showMenuItem = propertyMenu.addMenuItem("Show in Marketplace");
-
-var propertiesTool = new PropertiesTool();
-
-selectionDisplay.onSpaceModeChange = function(spaceMode) {
- entityListTool.setSpaceMode(spaceMode);
- propertiesTool.setSpaceMode(spaceMode);
-};
-
-function getExistingZoneList() {
- var center = { "x": 0, "y": 0, "z": 0 };
- var existingZoneIDs = Entities.findEntitiesByType("Zone", center, ENTIRE_DOMAIN_SCAN_RADIUS);
- var listExistingZones = [];
- var thisZone = {};
- var properties;
- for (var k = 0; k < existingZoneIDs.length; k++) {
- properties = Entities.getEntityProperties(existingZoneIDs[k], ["name"]);
- thisZone = {
- "id": existingZoneIDs[k],
- "name": properties.name
- };
- listExistingZones.push(thisZone);
- }
- listExistingZones.sort(zoneSortOrder);
- return listExistingZones;
-}
-
-function zoneSortOrder(a, b) {
- var nameA = a.name.toUpperCase();
- var nameB = b.name.toUpperCase();
- if (nameA > nameB) {
- return 1;
- } else if (nameA < nameB) {
- return -1;
- }
- if (a.name > b.name) {
- return 1;
- } else if (a.name < b.name) {
- return -1;
- }
- return 0;
-}
-
-//print("getParentState added");
-function getParentState(id) {
- var state = "NONE";
- var properties = Entities.getEntityProperties(id, ["parentID"]);
- var children = getDomainOnlyChildrenIDs(id);
- if (properties.parentID !== Uuid.NULL) {
- if (children.length > 0) {
- state = "PARENT_CHILDREN";
- } else {
- state = "CHILDREN";
- }
- } else {
- if (children.length > 0) {
- state = "PARENT";
+ function setCameraFocusToSelection() {
+ cameraManager.enable();
+ if (selectionManager.hasSelection()) {
+ cameraManager.focus(selectionManager.worldPosition, selectionManager.worldDimensions,
+ Menu.isOptionChecked(MENU_EASE_ON_FOCUS));
}
}
- return state;
-}
-//print("Global object after getParentState" + JSON.stringify(globalThis));
-
-function getDomainOnlyChildrenIDs(id) {
- var allChildren = Entities.getChildrenIDs(id);
- var realChildren = [];
- var properties;
- for (var i = 0; i < allChildren.length; i++) {
- properties = Entities.getEntityProperties(allChildren[i], ["name"]);
- if (properties.name !== undefined && properties.name !== entityShapeVisualizerSessionName) {
- realChildren.push(allChildren[i]);
+ function alignGridToSelection() {
+ if (selectionManager.hasSelection()) {
+ if (!grid.getVisible()) {
+ grid.setVisible(true, true);
+ }
+ grid.moveToSelection();
}
}
- return realChildren;
-}
-function importEntitiesFromFile() {
- Window.browseChanged.connect(onFileOpenChanged);
- Window.browseAsync("Select .json to Import", "", "*.json");
-}
-
-function importEntitiesFromUrl() {
- Window.promptTextChanged.connect(onPromptTextChanged);
- Window.promptAsync("URL of a .json to import", "");
-}
-
-function setCameraFocusToSelection() {
- cameraManager.enable();
- if (selectionManager.hasSelection()) {
- cameraManager.focus(selectionManager.worldPosition, selectionManager.worldDimensions,
- Menu.isOptionChecked(MENU_EASE_ON_FOCUS));
- }
-}
-
-function alignGridToSelection() {
- if (selectionManager.hasSelection()) {
+ function alignGridToAvatar() {
if (!grid.getVisible()) {
grid.setVisible(true, true);
}
- grid.moveToSelection();
+ grid.moveToAvatar();
}
-}
-function alignGridToAvatar() {
- if (!grid.getVisible()) {
- grid.setVisible(true, true);
+ function toggleGridVisibility() {
+ if (!grid.getVisible()) {
+ grid.setVisible(true, true);
+ } else {
+ grid.setVisible(false, true);
+ }
}
- grid.moveToAvatar();
-}
-function toggleGridVisibility() {
- if (!grid.getVisible()) {
- grid.setVisible(true, true);
- } else {
- grid.setVisible(false, true);
+ function rotateAsNextClickedSurface() {
+ if (!SelectionManager.hasSelection() || !SelectionManager.hasUnlockedSelection()) {
+ audioFeedback.rejection();
+ Window.notifyEditError("You have nothing selected, or the selection is locked.");
+ expectingRotateAsClickedSurface = false;
+ } else {
+ expectingRotateAsClickedSurface = true;
+ }
}
-}
-function rotateAsNextClickedSurface() {
- if (!SelectionManager.hasSelection() || !SelectionManager.hasUnlockedSelection()) {
- audioFeedback.rejection();
- Window.notifyEditError("You have nothing selected, or the selection is locked.");
- expectingRotateAsClickedSurface = false;
- } else {
- expectingRotateAsClickedSurface = true;
- }
-}
-
-//}()); // END LOCAL_SCOPE
+}()); // END LOCAL_SCOPE
+//}(); // END LOCAL_SCOPE
diff --git a/scripts/system/create/entityList/entityList.js b/scripts/system/create/entityList/entityList.js
index 47a04ad0bd..bd82d9a424 100644
--- a/scripts/system/create/entityList/entityList.js
+++ b/scripts/system/create/entityList/entityList.js
@@ -218,7 +218,7 @@ var EntityListTool = function(shouldUseEditTabletApp) {
url = properties.imageURL;
}
//print("Global object before getParentState call: " + JSON.stringify(globalThis));
- var parentStatus = getParentState(ids[i]);
+ var parentStatus = that.createApp.getParentState(ids[i]);
var parentState = "";
if (parentStatus === "PARENT") {
parentState = "A";
diff --git a/scripts/system/create/entitySelectionTool/entitySelectionTool.js b/scripts/system/create/entitySelectionTool/entitySelectionTool.js
index f5469bada7..397ce4b030 100644
--- a/scripts/system/create/entitySelectionTool/entitySelectionTool.js
+++ b/scripts/system/create/entitySelectionTool/entitySelectionTool.js
@@ -83,12 +83,15 @@ SelectionManager = (function() {
// FUNCTION: HANDLE ENTITY SELECTION TOOL UPDATES
function handleEntitySelectionToolUpdates(channel, message, sender) {
+ //print("Channel: " + channel + " Sender: " + sender + " Message: " + JSON.stringify(message));
if (channel !== 'entityToolUpdates') {
return;
}
+ print("handleEntitySelectionToolUpdates entityToolUpdates");
if (sender !== MyAvatar.sessionUUID) {
return;
}
+ print("handleEntitySelectionToolUpdates MyAvatar.sessionUUID");
var wantDebug = false;
var messageParsed;
@@ -99,6 +102,7 @@ SelectionManager = (function() {
return;
}
+ print("handleEntitySelectionToolUpdates JSON.parse(message): " + messageParsed.method);
if (messageParsed.method === "selectEntity") {
if (!that.editEnabled) {
return;
@@ -125,7 +129,7 @@ SelectionManager = (function() {
}
selectionDisplay.moveSelection(Vec3.sum(messageParsed.intersection, Vec3.multiplyQbyV( normalRotation, {"x": 0.0, "y":0.0, "z": distanceFromSurface})));
that._update(false, this);
- pushCommandForSelections();
+ that.createApp.pushCommandForSelections();
expectingRotateAsClickedSurface = false;
audioFeedback.action();
}
@@ -147,6 +151,7 @@ SelectionManager = (function() {
that.clearSelections();
}
} else if (messageParsed.method === "pointingAt") {
+ print("handleEntitySelectionToolUpdates pointingAt");
if (messageParsed.hand === Controller.Standard.RightHand) {
that.pointingAtDesktopWindowRight = messageParsed.desktopWindow;
that.pointingAtTabletRight = messageParsed.tablet;
@@ -232,6 +237,8 @@ SelectionManager = (function() {
};
that.setSelections = function(entityIDs, caller) {
+ print("setSelections: " + JSON.stringify(entityIDs));
+ Script.logBacktrace("setSelections");
that.selections = [];
for (var i = 0; i < entityIDs.length; i++) {
var entityID = entityIDs[i];
@@ -723,7 +730,7 @@ SelectionManager = (function() {
var newPosition = Vec3.sum(relativePosition, targetPosition);
Entities.editEntity(id, { "position": newPosition });
}
- pushCommandForSelections();
+ that.createApp.pushCommandForSelections();
that._update(false, this);
} else {
audioFeedback.rejection();
@@ -2002,7 +2009,7 @@ SelectionDisplay = (function() {
var handleBoundingBoxColor = COLOR_BOUNDING_EDGE;
if (SelectionManager.selections.length === 1) {
- var parentState = getParentState(SelectionManager.selections[0]);
+ var parentState = that.createApp.getParentState(SelectionManager.selections[0]);
if (parentState === "CHILDREN") {
handleBoundingBoxColor = COLOR_BOUNDING_EDGE_CHILDREN;
} else if (parentState === "PARENT") {
@@ -2504,7 +2511,7 @@ SelectionDisplay = (function() {
}
updateSelectionsRotation(axisRotation, SelectionManager.worldPosition);
SelectionManager._update(false, this);
- pushCommandForSelections();
+ that.createApp.pushCommandForSelections();
audioFeedback.action();
}
};
@@ -2585,7 +2592,7 @@ SelectionDisplay = (function() {
print(" starting elevation: " + startingElevation);
}
- initialPick = rayPlaneIntersection(pickRay, pickPlanePosition, pickPlaneNormal);
+ initialPick = that.createApp.rayPlaneIntersection(pickRay, pickPlanePosition, pickPlaneNormal);
if (debugPickPlaneEnabled) {
that.showDebugPickPlane(pickPlanePosition, pickPlaneNormal);
@@ -2598,7 +2605,7 @@ SelectionDisplay = (function() {
}
},
onEnd: function(event, reason) {
- pushCommandForSelections(duplicatedEntityIDs);
+ that.createApp.pushCommandForSelections(duplicatedEntityIDs);
if (isConstrained) {
Entities.editEntity(xRailToolEntity, {
visible: false,
@@ -2617,7 +2624,7 @@ SelectionDisplay = (function() {
var wantDebug = false;
var pickRay = generalComputePickRay(event.x, event.y);
- var newPick = rayPlaneIntersection2(pickRay, pickPlanePosition, pickPlaneNormal);
+ var newPick = that.createApp.rayPlaneIntersection2(pickRay, pickPlanePosition, pickPlaneNormal);
// If the pick ray doesn't hit the pick plane in this direction, do nothing.
// this will happen when someone drags across the horizon from the side they started on.
@@ -2722,7 +2729,7 @@ SelectionDisplay = (function() {
var negateAndHalve = -0.5;
var cornerPosition = Vec3.sum(startPosition, Vec3.multiply(negateAndHalve, SelectionManager.worldDimensions));
vector = Vec3.subtract(
- grid.snapToGrid(Vec3.sum(cornerPosition, vector), constrainMajorOnly),
+ that.grid.snapToGrid(Vec3.sum(cornerPosition, vector), constrainMajorOnly),
cornerPosition);
// editing a parent will cause all the children to automatically follow along, so don't
@@ -2801,7 +2808,7 @@ SelectionDisplay = (function() {
axisVector = Vec3.multiplyQbyV(rotation, axisVector);
pickPlaneNormal = Vec3.cross(Vec3.cross(pickRay.direction, axisVector), axisVector);
pickPlanePosition = SelectionManager.worldPosition;
- initialPick = rayPlaneIntersection(pickRay, pickPlanePosition, pickPlaneNormal);
+ initialPick = that.createApp.rayPlaneIntersection(pickRay, pickPlanePosition, pickPlaneNormal);
SelectionManager.saveProperties();
that.resetPreviousHandleColor();
@@ -2822,7 +2829,7 @@ SelectionDisplay = (function() {
}
},
onEnd: function(event, reason) {
- pushCommandForSelections(duplicatedEntityIDs);
+ that.createApp.pushCommandForSelections(duplicatedEntityIDs);
},
onMove: function(event) {
var pickRay = generalComputePickRay(event.x, event.y);
@@ -2832,7 +2839,7 @@ SelectionDisplay = (function() {
pickRay = previousPickRay;
}
- var newPick = rayPlaneIntersection(pickRay, pickPlanePosition, pickPlaneNormal);
+ var newPick = that.createApp.rayPlaneIntersection(pickRay, pickPlanePosition, pickPlaneNormal);
if (debugPickPlaneEnabled) {
that.showDebugPickPlaneHit(newPick);
}
@@ -2850,8 +2857,8 @@ SelectionDisplay = (function() {
var dotVector = Vec3.dot(vector, projectionVector);
vector = Vec3.multiply(dotVector, projectionVector);
- var gridOrigin = grid.getOrigin();
- vector = Vec3.subtract(grid.snapToGrid(Vec3.sum(vector, gridOrigin)), gridOrigin);
+ var gridOrigin = that.grid.getOrigin();
+ vector = Vec3.subtract(that.grid.snapToGrid(Vec3.sum(vector, gridOrigin)), gridOrigin);
var wantDebug = false;
if (wantDebug) {
@@ -2962,7 +2969,7 @@ SelectionDisplay = (function() {
pickPlaneNormal = Vec3.cross(Vec3.cross(pickRay.direction, axisVector), axisVector);
pickPlanePosition = Vec3.sum(initialPosition, Vec3.multiplyQbyV(rotation, scaledOffsetWorld));
- initialPick = rayPlaneIntersection(pickRay, pickPlanePosition, pickPlaneNormal);
+ initialPick = that.createApp.rayPlaneIntersection(pickRay, pickPlanePosition, pickPlaneNormal);
that.setHandleTranslateVisible(false);
that.setHandleRotateVisible(false);
@@ -3008,8 +3015,8 @@ SelectionDisplay = (function() {
Entities.editEntity(stretchPanel, { visible: false, ignorePickIntersection: true });
}
activeStretchCubePanelOffset = null;
-
- pushCommandForSelections();
+
+ that.createApp.pushCommandForSelections();
},
onMove: function(event) {
var pickRay = generalComputePickRay(event.x, event.y);
@@ -3019,7 +3026,7 @@ SelectionDisplay = (function() {
pickRay = previousPickRay;
}
- var newPick = rayPlaneIntersection(pickRay, pickPlanePosition, pickPlaneNormal);
+ var newPick = that.createApp.rayPlaneIntersection(pickRay, pickPlanePosition, pickPlaneNormal);
if (debugPickPlaneEnabled) {
that.showDebugPickPlaneHit(newPick);
}
@@ -3029,7 +3036,7 @@ SelectionDisplay = (function() {
changeInDimensions = Vec3.multiply(dotVector, axisVector);
changeInDimensions = Vec3.multiplyQbyV(Quat.inverse(rotation), changeInDimensions);
changeInDimensions = Vec3.multiplyVbyV(mask, changeInDimensions);
- changeInDimensions = grid.snapToSpacing(changeInDimensions);
+ changeInDimensions = that.grid.snapToSpacing(changeInDimensions);
changeInDimensions = Vec3.multiply(NEGATE_VECTOR, Vec3.multiplyVbyV(signs, changeInDimensions));
var newDimensions = Vec3.sum(initialDimensions, changeInDimensions);
@@ -3088,7 +3095,7 @@ SelectionDisplay = (function() {
pickPlanePosition = initialPosition;
pickPlaneNormal = Vec3.subtract(pickRay.origin, pickPlanePosition);
- initialPick = rayPlaneIntersection(pickRay, pickPlanePosition, pickPlaneNormal);
+ initialPick = that.createApp.rayPlaneIntersection(pickRay, pickPlanePosition, pickPlaneNormal);
that.setHandleTranslateVisible(false);
that.setHandleRotateVisible(false);
@@ -3120,8 +3127,8 @@ SelectionDisplay = (function() {
Entities.editEntity(SelectionManager.selections[0], {collidesWith: newCollidesWith});
that.replaceCollisionsAfterStretch = false;
}
-
- pushCommandForSelections();
+
+ that.createApp.pushCommandForSelections();
},
onMove: function(event) {
var pickRay = generalComputePickRay(event.x, event.y);
@@ -3131,7 +3138,7 @@ SelectionDisplay = (function() {
pickRay = previousPickRay;
}
- var newPick = rayPlaneIntersection(pickRay, pickPlanePosition, pickPlaneNormal);
+ var newPick = that.createApp.rayPlaneIntersection(pickRay, pickPlanePosition, pickPlaneNormal);
if (debugPickPlaneEnabled) {
that.showDebugPickPlaneHit(newPick);
}
@@ -3140,7 +3147,7 @@ SelectionDisplay = (function() {
var dimensionsMultiple = toCameraDistance * SCALE_DIMENSIONS_CAMERA_DISTANCE_MULTIPLE;
var changeInDimensions = Vec3.subtract(newPick, initialPick);
changeInDimensions = Vec3.multiplyQbyV(Quat.inverse(Camera.orientation), changeInDimensions);
- changeInDimensions = grid.snapToSpacing(changeInDimensions);
+ changeInDimensions = that.grid.snapToSpacing(changeInDimensions);
changeInDimensions = Vec3.multiply(changeInDimensions, dimensionsMultiple);
var averageDimensionChange = (changeInDimensions.x + changeInDimensions.y + changeInDimensions.z) / 3;
@@ -3309,7 +3316,7 @@ SelectionDisplay = (function() {
// editOverlays may not have committed rotation changes.
// Compute zero position based on where the toolEntity will be eventually.
- var initialPick = rayPlaneIntersection(pickRay, rotationCenter, rotationNormal);
+ var initialPick = that.createApp.rayPlaneIntersection(pickRay, rotationCenter, rotationNormal);
// In case of a parallel ray, this will be null, which will cause early-out
// in the onMove helper.
rotationZero = initialPick;
@@ -3343,7 +3350,7 @@ SelectionDisplay = (function() {
}
});
Entities.editEntity(handleRotateCurrentRing, { visible: false, ignorePickIntersection: true });
- pushCommandForSelections();
+ that.createApp.pushCommandForSelections();
if (wantDebug) {
print("================== " + getMode() + "(addHandleRotateTool onEnd) <- =======================");
}
@@ -3364,7 +3371,7 @@ SelectionDisplay = (function() {
}
var pickRay = generalComputePickRay(event.x, event.y);
- var result = rayPlaneIntersection(pickRay, rotationCenter, rotationNormal);
+ var result = that.createApp.rayPlaneIntersection(pickRay, rotationCenter, rotationNormal);
if (result) {
var centerToZero = Vec3.subtract(rotationZero, rotationCenter);
var centerToIntersect = Vec3.subtract(result, rotationCenter);
diff --git a/scripts/system/libraries/gridTool.js b/scripts/system/libraries/gridTool.js
index 4674e5925d..81edf761bd 100644
--- a/scripts/system/libraries/gridTool.js
+++ b/scripts/system/libraries/gridTool.js
@@ -292,8 +292,8 @@ GridTool = function(opts) {
var dataString = JSON.stringify(data);
webView.emitScriptEvent(dataString);
createToolsWindow.emitScriptEvent(dataString);
- if (selectionDisplay) {
- selectionDisplay.updateHandles();
+ if (that.selectionDisplay) {
+ that.selectionDisplay.updateHandles();
}
});