+
Native Input Range Slider
+
+
+
+
Bootstrap Slider
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/scripts/developer/tests/sliderTestMain.js b/scripts/developer/tests/sliderTestMain.js
new file mode 100644
index 0000000000..22bf4fa911
--- /dev/null
+++ b/scripts/developer/tests/sliderTestMain.js
@@ -0,0 +1,35 @@
+(function () {
+ var HTML_URL = Script.resolvePath("sliderTest.html");
+ var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
+ var button = tablet.addButton({
+ text: "SLIDER"
+ });
+
+ function onClicked() {
+ tablet.gotoWebScreen(HTML_URL);
+ }
+
+ button.clicked.connect(onClicked);
+
+ var onSliderTestScreen = false;
+ function onScreenChanged(type, url) {
+ if (type === "Web" && url === HTML_URL) {
+ // when switching to the slider page, change inputMode to "Mouse", this should make the sliders work.
+ onSliderTestScreen = true;
+ Overlays.editOverlay(HMD.tabletScreenID, { inputMode: "Mouse" });
+ } else if (onSliderTestScreen) {
+ // when switching off of the slider page, change inputMode to back to "Touch".
+ onSliderTestScreen = false;
+ Overlays.editOverlay(HMD.tabletScreenID, { inputMode: "Touch" });
+ }
+ }
+
+ tablet.screenChanged.connect(onScreenChanged);
+
+ function cleanup() {
+ tablet.removeButton(button);
+ tablet.screenChanged.disconnect(onScreenChanged);
+ }
+ Script.scriptEnding.connect(cleanup);
+
+}());
diff --git a/scripts/developer/utilities/audio/stats.qml b/scripts/developer/utilities/audio/Stats.qml
similarity index 93%
rename from scripts/developer/utilities/audio/stats.qml
rename to scripts/developer/utilities/audio/Stats.qml
index 346e5e3544..7f559ea664 100644
--- a/scripts/developer/utilities/audio/stats.qml
+++ b/scripts/developer/utilities/audio/Stats.qml
@@ -1,5 +1,5 @@
//
-// stats.qml
+// Stats.qml
// scripts/developer/utilities/audio
//
// Created by Zach Pomerantz on 9/22/2016
@@ -12,22 +12,21 @@ import QtQuick 2.5
import QtQuick.Controls 1.4
import QtQuick.Layouts 1.3
+import "../../../../resources/qml/controls-uit" as HifiControls
+
Column {
id: stats
width: parent.width
- height: parent.height
property bool showGraphs: toggleGraphs.checked
- RowLayout {
+ Item {
width: parent.width
height: 30
- Button {
+ HifiControls.Button {
id: toggleGraphs
property bool checked: false
-
- Layout.alignment: Qt.AlignCenter
-
+ anchors.horizontalCenter: parent.horizontalCenter
text: checked ? "Hide graphs" : "Show graphs"
onClicked: function() { checked = !checked; }
}
@@ -35,11 +34,9 @@ Column {
Grid {
width: parent.width
- height: parent.height - 30
Column {
width: parent.width / 2
- height: parent.height
Section {
label: "Latency"
@@ -76,7 +73,6 @@ Column {
Column {
width: parent.width / 2
- height: parent.height
Section {
label: "Mixer (upstream)"
@@ -92,4 +88,3 @@ Column {
}
}
}
-
diff --git a/scripts/developer/utilities/audio/TabletStats.qml b/scripts/developer/utilities/audio/TabletStats.qml
new file mode 100644
index 0000000000..130b90f032
--- /dev/null
+++ b/scripts/developer/utilities/audio/TabletStats.qml
@@ -0,0 +1,89 @@
+//
+// TabletStats.qml
+// scripts/developer/utilities/audio
+//
+// Created by David Rowe on 3 Mar 2017.
+// Copyright 2017 High Fidelity, Inc.
+//
+// Distributed under the Apache License, Version 2.0.
+// See the accompanying file LICENSE or https://www.apache.org/licenses/LICENSE-2.0.html
+//
+import QtQuick 2.5
+import QtQuick.Controls 1.4
+import QtQuick.Layouts 1.3
+
+import "../../../../resources/qml/styles-uit"
+
+Item {
+ id: dialog
+ width: 480
+ height: 720
+
+ HifiConstants { id: hifi }
+
+ Rectangle {
+ id: header
+ height: 90
+ anchors {
+ top: parent.top
+ left: parent.left
+ right: parent.right
+ }
+ z: 100
+
+ gradient: Gradient {
+ GradientStop {
+ position: 0
+ color: "#2b2b2b"
+ }
+
+ GradientStop {
+ position: 1
+ color: "#1e1e1e"
+ }
+ }
+
+ RalewayBold {
+ text: "Audio Interface Statistics"
+ size: 26
+ color: "#34a2c7"
+ anchors.verticalCenter: parent.verticalCenter
+ anchors.left: parent.left
+ anchors.leftMargin: hifi.dimensions.contentMargin.x // ####### hifi is not defined
+ }
+ }
+
+ Rectangle {
+ id: main
+ anchors {
+ top: header.bottom
+ bottom: parent.bottom
+ left: parent.left
+ right: parent.right
+ }
+
+ gradient: Gradient {
+ GradientStop {
+ position: 0
+ color: "#2b2b2b"
+ }
+
+ GradientStop {
+ position: 1
+ color: "#0f212e"
+ }
+ }
+
+ Flickable {
+ id: scrollView
+ width: parent.width
+ height: parent.height
+ contentWidth: parent.width
+ contentHeight: stats.height
+
+ Stats {
+ id: stats
+ }
+ }
+ }
+}
diff --git a/scripts/developer/utilities/audio/stats.js b/scripts/developer/utilities/audio/stats.js
index 493271ac99..382e14df5f 100644
--- a/scripts/developer/utilities/audio/stats.js
+++ b/scripts/developer/utilities/audio/stats.js
@@ -9,17 +9,23 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
-var INITIAL_WIDTH = 400;
-var INITIAL_OFFSET = 50;
+if (HMD.active && !Settings.getValue("HUDUIEnabled")) {
+ var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
+ var qml = Script.resolvePath("TabletStats.qml");
+ tablet.loadQMLSource(qml);
+ Script.stop();
-// Set up the qml ui
-var qml = Script.resolvePath('stats.qml');
-var window = new OverlayWindow({
- title: 'Audio Interface Statistics',
- source: qml,
- width: 500, height: 520 // stats.qml may be too large for some screens
-});
-window.setPosition(INITIAL_OFFSET, INITIAL_OFFSET);
+} else {
+ var INITIAL_WIDTH = 400;
+ var INITIAL_OFFSET = 50;
-window.closed.connect(function() { Script.stop(); });
+ var qml = Script.resolvePath("Stats.qml");
+ var window = new OverlayWindow({
+ title: "Audio Interface Statistics",
+ source: qml,
+ width: 500, height: 520 // stats.qml may be too large for some screens
+ });
+ window.setPosition(INITIAL_OFFSET, INITIAL_OFFSET);
+ window.closed.connect(function () { Script.stop(); });
+}
diff --git a/scripts/system/audio.js b/scripts/system/audio.js
index beeb8609d8..7bc8676a2e 100644
--- a/scripts/system/audio.js
+++ b/scripts/system/audio.js
@@ -45,7 +45,8 @@ function onClicked() {
var entity = HMD.tabletID;
Entities.editEntity(entity, { textures: JSON.stringify({ "tex.close": HOME_BUTTON_TEXTURE }) });
shouldActivateButton = true;
- tablet.gotoMenuScreen("Audio");
+ shouldActivateButton = true;
+ tablet.loadQMLSource("../Audio.qml");
onAudioScreen = true;
}
}
diff --git a/scripts/system/controllers/controllerScripts.js b/scripts/system/controllers/controllerScripts.js
new file mode 100644
index 0000000000..df11a1e5be
--- /dev/null
+++ b/scripts/system/controllers/controllerScripts.js
@@ -0,0 +1,41 @@
+"use strict";
+
+// controllerScripts.js
+//
+// Created by David Rowe on 15 Mar 2017.
+// Copyright 2017 High Fidelity, Inc.
+//
+// Distributed under the Apache License, Version 2.0.
+// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+var CONTOLLER_SCRIPTS = [
+ "squeezeHands.js",
+ "controllerDisplayManager.js",
+ "handControllerGrab.js",
+ "handControllerPointer.js",
+ "grab.js",
+ "teleport.js",
+ "toggleAdvancedMovementForHandControllers.js",
+];
+
+var DEBUG_MENU_ITEM = "Debug defaultScripts.js";
+
+
+function runDefaultsTogether() {
+ for (var j in CONTOLLER_SCRIPTS) {
+ Script.include(CONTOLLER_SCRIPTS[j]);
+ }
+}
+
+function runDefaultsSeparately() {
+ for (var i in CONTOLLER_SCRIPTS) {
+ Script.load(CONTOLLER_SCRIPTS[i]);
+ }
+}
+
+if (Menu.isOptionChecked(DEBUG_MENU_ITEM)) {
+ runDefaultsSeparately();
+} else {
+ runDefaultsTogether();
+}
diff --git a/scripts/system/controllers/handControllerGrab.js b/scripts/system/controllers/handControllerGrab.js
index e83e31aaa5..9a6760a37b 100644
--- a/scripts/system/controllers/handControllerGrab.js
+++ b/scripts/system/controllers/handControllerGrab.js
@@ -13,8 +13,8 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
/* global getEntityCustomData, flatten, Xform, Script, Quat, Vec3, MyAvatar, Entities, Overlays, Settings,
- Reticle, Controller, Camera, Messages, Mat4, getControllerWorldLocation, getGrabPointSphereOffset, setGrabCommunications,
- Menu, HMD, isInEditMode */
+ Reticle, Controller, Camera, Messages, Mat4, getControllerWorldLocation, getGrabPointSphereOffset,
+ setGrabCommunications, Menu, HMD, isInEditMode */
/* eslint indent: ["error", 4, { "outerIIFEBody": 0 }] */
(function() { // BEGIN LOCAL_SCOPE
@@ -71,12 +71,6 @@ var EQUIP_SPHERE_SCALE_FACTOR = 0.65;
var WEB_DISPLAY_STYLUS_DISTANCE = 0.5;
var WEB_STYLUS_LENGTH = 0.2;
var WEB_TOUCH_Y_OFFSET = 0.05; // how far forward (or back with a negative number) to slide stylus in hand
-var WEB_TOUCH_TOO_CLOSE = 0.03; // if the stylus is pushed far though the web surface, don't consider it touching
-var WEB_TOUCH_Y_TOUCH_DEADZONE_SIZE = 0.01;
-
-var FINGER_TOUCH_Y_OFFSET = -0.02;
-var FINGER_TOUCH_MIN = -0.01 - FINGER_TOUCH_Y_OFFSET;
-var FINGER_TOUCH_MAX = 0.01 - FINGER_TOUCH_Y_OFFSET;
//
// distant manipulation
@@ -137,7 +131,6 @@ var GRAB_POINT_SPHERE_ALPHA = 0.85;
//
// other constants
//
-
var RIGHT_HAND = 1;
var LEFT_HAND = 0;
@@ -214,10 +207,9 @@ var STATE_NEAR_GRABBING = 4;
var STATE_NEAR_TRIGGER = 5;
var STATE_FAR_TRIGGER = 6;
var STATE_HOLD = 7;
-var STATE_ENTITY_STYLUS_TOUCHING = 8;
-var STATE_ENTITY_LASER_TOUCHING = 9;
-var STATE_OVERLAY_STYLUS_TOUCHING = 10;
-var STATE_OVERLAY_LASER_TOUCHING = 11;
+var STATE_ENTITY_LASER_TOUCHING = 8;
+var STATE_OVERLAY_LASER_TOUCHING = 9;
+var STATE_STYLUS_TOUCHING = 10;
var CONTROLLER_STATE_MACHINE = {};
@@ -261,30 +253,30 @@ CONTROLLER_STATE_MACHINE[STATE_FAR_TRIGGER] = {
enterMethod: "farTriggerEnter",
updateMethod: "farTrigger"
};
-CONTROLLER_STATE_MACHINE[STATE_ENTITY_STYLUS_TOUCHING] = {
- name: "entityStylusTouching",
- enterMethod: "entityTouchingEnter",
- exitMethod: "entityTouchingExit",
- updateMethod: "entityTouching"
-};
CONTROLLER_STATE_MACHINE[STATE_ENTITY_LASER_TOUCHING] = {
name: "entityLaserTouching",
- enterMethod: "entityTouchingEnter",
- exitMethod: "entityTouchingExit",
- updateMethod: "entityTouching"
-};
-CONTROLLER_STATE_MACHINE[STATE_OVERLAY_STYLUS_TOUCHING] = {
- name: "overlayStylusTouching",
- enterMethod: "overlayTouchingEnter",
- exitMethod: "overlayTouchingExit",
- updateMethod: "overlayTouching"
+ enterMethod: "entityLaserTouchingEnter",
+ exitMethod: "entityLaserTouchingExit",
+ updateMethod: "entityLaserTouching"
};
CONTROLLER_STATE_MACHINE[STATE_OVERLAY_LASER_TOUCHING] = {
name: "overlayLaserTouching",
- enterMethod: "overlayTouchingEnter",
- exitMethod: "overlayTouchingExit",
- updateMethod: "overlayTouching"
+ enterMethod: "overlayLaserTouchingEnter",
+ exitMethod: "overlayLaserTouchingExit",
+ updateMethod: "overlayLaserTouching"
};
+CONTROLLER_STATE_MACHINE[STATE_STYLUS_TOUCHING] = {
+ name: "stylusTouching",
+ enterMethod: "stylusTouchingEnter",
+ exitMethod: "stylusTouchingExit",
+ updateMethod: "stylusTouching"
+};
+
+function distance2D(a, b) {
+ var dx = (a.x - b.x);
+ var dy = (a.y - b.y);
+ return Math.sqrt(dx * dx + dy * dy);
+}
function getFingerWorldLocation(hand) {
var fingerJointName = (hand === RIGHT_HAND) ? "RightHandIndex4" : "LeftHandIndex4";
@@ -295,13 +287,8 @@ function getFingerWorldLocation(hand) {
var worldFingerRotation = Quat.multiply(MyAvatar.orientation, fingerRotation);
var worldFingerPosition = Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, fingerPosition));
- // local y offset.
- var localYOffset = Vec3.multiplyQbyV(worldFingerRotation, {x: 0, y: FINGER_TOUCH_Y_OFFSET, z: 0});
-
- var offsetWorldFingerPosition = Vec3.sum(worldFingerPosition, localYOffset);
-
return {
- position: offsetWorldFingerPosition,
+ position: worldFingerPosition,
orientation: worldFingerRotation,
rotation: worldFingerRotation,
valid: true
@@ -567,6 +554,253 @@ function restore2DMode() {
}
}
+function stylusTargetHasKeyboardFocus(stylusTarget) {
+ if (stylusTarget.entityID && stylusTarget.entityID !== NULL_UUID) {
+ return Entities.keyboardFocusEntity === stylusTarget.entityID;
+ } else if (stylusTarget.overlayID && stylusTarget.overlayID !== NULL_UUID) {
+ return Overlays.keyboardFocusOverlay === stylusTarget.overlayID;
+ }
+}
+
+function setKeyboardFocusOnStylusTarget(stylusTarget) {
+ if (stylusTarget.entityID && stylusTarget.entityID !== NULL_UUID && Entities.wantsHandControllerPointerEvents(stylusTarget.entityID)) {
+ Overlays.keyboardFocusOverlay = NULL_UUID;
+ Entities.keyboardFocusEntity = stylusTarget.entityID;
+ } else if (stylusTarget.overlayID && stylusTarget.overlayID !== NULL_UUID) {
+ Overlays.keyboardFocusOverlay = stylusTarget.overlayID;
+ Entities.keyboardFocusEntity = NULL_UUID;
+ }
+}
+
+function sendHoverEnterEventToStylusTarget(hand, stylusTarget) {
+ var pointerEvent = {
+ type: "Move",
+ id: hand + 1, // 0 is reserved for hardware mouse
+ pos2D: stylusTarget.position2D,
+ pos3D: stylusTarget.position,
+ normal: stylusTarget.normal,
+ direction: Vec3.subtract(ZERO_VEC, stylusTarget.normal),
+ button: "None"
+ };
+
+ if (stylusTarget.entityID && stylusTarget.entityID !== NULL_UUID) {
+ Entities.sendHoverEnterEntity(stylusTarget.entityID, pointerEvent);
+ } else if (stylusTarget.overlayID && stylusTarget.overlayID !== NULL_UUID) {
+ Overlays.sendHoverEnterOverlay(stylusTarget.overlayID, pointerEvent);
+ }
+}
+
+function sendHoverOverEventToStylusTarget(hand, stylusTarget) {
+ var pointerEvent = {
+ type: "Move",
+ id: hand + 1, // 0 is reserved for hardware mouse
+ pos2D: stylusTarget.position2D,
+ pos3D: stylusTarget.position,
+ normal: stylusTarget.normal,
+ direction: Vec3.subtract(ZERO_VEC, stylusTarget.normal),
+ button: "None"
+ };
+
+ if (stylusTarget.entityID && stylusTarget.entityID !== NULL_UUID) {
+ Entities.sendMouseMoveOnEntity(stylusTarget.entityID, pointerEvent);
+ Entities.sendHoverOverEntity(stylusTarget.entityID, pointerEvent);
+ } else if (stylusTarget.overlayID && stylusTarget.overlayID !== NULL_UUID) {
+ Overlays.sendMouseMoveOnOverlay(stylusTarget.overlayID, pointerEvent);
+ Overlays.sendHoverOverOverlay(stylusTarget.overlayID, pointerEvent);
+ }
+}
+
+function sendTouchStartEventToStylusTarget(hand, stylusTarget) {
+ var pointerEvent = {
+ type: "Press",
+ id: hand + 1, // 0 is reserved for hardware mouse
+ pos2D: stylusTarget.position2D,
+ pos3D: stylusTarget.position,
+ normal: stylusTarget.normal,
+ direction: Vec3.subtract(ZERO_VEC, stylusTarget.normal),
+ button: "Primary",
+ isPrimaryHeld: true
+ };
+
+ if (stylusTarget.entityID && stylusTarget.entityID !== NULL_UUID) {
+ Entities.sendMousePressOnEntity(stylusTarget.entityID, pointerEvent);
+ Entities.sendClickDownOnEntity(stylusTarget.entityID, pointerEvent);
+ } else if (stylusTarget.overlayID && stylusTarget.overlayID !== NULL_UUID) {
+ Overlays.sendMousePressOnOverlay(stylusTarget.overlayID, pointerEvent);
+ }
+}
+
+function sendTouchEndEventToStylusTarget(hand, stylusTarget) {
+ var pointerEvent = {
+ type: "Release",
+ id: hand + 1, // 0 is reserved for hardware mouse
+ pos2D: stylusTarget.position2D,
+ pos3D: stylusTarget.position,
+ normal: stylusTarget.normal,
+ direction: Vec3.subtract(ZERO_VEC, stylusTarget.normal),
+ button: "Primary"
+ };
+
+ if (stylusTarget.entityID && stylusTarget.entityID !== NULL_UUID) {
+ Entities.sendMouseReleaseOnEntity(stylusTarget.entityID, pointerEvent);
+ Entities.sendClickReleaseOnEntity(stylusTarget.entityID, pointerEvent);
+ Entities.sendHoverLeaveEntity(stylusTarget.entityID, pointerEvent);
+ } else if (stylusTarget.overlayID && stylusTarget.overlayID !== NULL_UUID) {
+ Overlays.sendMouseReleaseOnOverlay(stylusTarget.overlayID, pointerEvent);
+ }
+}
+
+function sendTouchMoveEventToStylusTarget(hand, stylusTarget) {
+ var pointerEvent = {
+ type: "Move",
+ id: hand + 1, // 0 is reserved for hardware mouse
+ pos2D: stylusTarget.position2D,
+ pos3D: stylusTarget.position,
+ normal: stylusTarget.normal,
+ direction: Vec3.subtract(ZERO_VEC, stylusTarget.normal),
+ button: "Primary",
+ isPrimaryHeld: true
+ };
+
+ if (stylusTarget.entityID && stylusTarget.entityID !== NULL_UUID) {
+ Entities.sendMouseMoveOnEntity(stylusTarget.entityID, pointerEvent);
+ Entities.sendHoldingClickOnEntity(stylusTarget.entityID, pointerEvent);
+ } else if (stylusTarget.overlayID && stylusTarget.overlayID !== NULL_UUID) {
+ Overlays.sendMouseMoveOnOverlay(stylusTarget.overlayID, pointerEvent);
+ }
+}
+
+// will return undefined if entity does not exist.
+function calculateStylusTargetFromEntity(stylusTip, entityID) {
+ var props = entityPropertiesCache.getProps(entityID);
+ if (props.rotation === undefined) {
+ // if rotation is missing from props object, then this entity has probably been deleted.
+ return;
+ }
+
+ // project stylus tip onto entity plane.
+ var normal = Vec3.multiplyQbyV(props.rotation, {x: 0, y: 0, z: 1});
+ Vec3.multiplyQbyV(props.rotation, {x: 0, y: 1, z: 0});
+ var distance = Vec3.dot(Vec3.subtract(stylusTip.position, props.position), normal);
+ var position = Vec3.subtract(stylusTip.position, Vec3.multiply(normal, distance));
+
+ // generate normalized coordinates
+ var invRot = Quat.inverse(props.rotation);
+ var localPos = Vec3.multiplyQbyV(invRot, Vec3.subtract(position, props.position));
+ var invDimensions = { x: 1 / props.dimensions.x, y: 1 / props.dimensions.y, z: 1 / props.dimensions.z };
+ var normalizedPosition = Vec3.sum(Vec3.multiplyVbyV(localPos, invDimensions), props.registrationPoint);
+
+ // 2D position on entity plane in meters, relative to the bounding box upper-left hand corner.
+ var position2D = { x: normalizedPosition.x * props.dimensions.x, y: (1 - normalizedPosition.y) * props.dimensions.y }; // flip y-axis
+
+ return {
+ entityID: entityID,
+ overlayID: null,
+ distance: distance,
+ position: position,
+ position2D: position2D,
+ normal: normal,
+ normalizedPosition: normalizedPosition,
+ dimensions: props.dimensions,
+ valid: true
+ };
+}
+
+// will return undefined if overlayID does not exist.
+function calculateStylusTargetFromOverlay(stylusTip, overlayID) {
+ var overlayPosition = Overlays.getProperty(overlayID, "position");
+ if (overlayPosition === undefined) {
+ return;
+ }
+
+ // project stylusTip onto overlay plane.
+ var overlayRotation = Overlays.getProperty(overlayID, "rotation");
+ if (overlayRotation === undefined) {
+ return;
+ }
+ var normal = Vec3.multiplyQbyV(overlayRotation, {x: 0, y: 0, z: 1});
+ var distance = Vec3.dot(Vec3.subtract(stylusTip.position, overlayPosition), normal);
+ var position = Vec3.subtract(stylusTip.position, Vec3.multiply(normal, distance));
+
+ // calclulate normalized position
+ var invRot = Quat.inverse(overlayRotation);
+ var localPos = Vec3.multiplyQbyV(invRot, Vec3.subtract(position, overlayPosition));
+ var dpi = Overlays.getProperty(overlayID, "dpi");
+
+ var dimensions;
+ if (dpi) {
+ // Calculate physical dimensions for web3d overlay from resolution and dpi; "dimensions" property is used as a scale.
+ var resolution = Overlays.getProperty(overlayID, "resolution");
+ if (resolution === undefined) {
+ return;
+ }
+ resolution.z = 1; // Circumvent divide-by-zero.
+ var scale = Overlays.getProperty(overlayID, "dimensions");
+ if (scale === undefined) {
+ return;
+ }
+ scale.z = 0.01; // overlay dimensions are 2D, not 3D.
+ dimensions = Vec3.multiplyVbyV(Vec3.multiply(resolution, INCHES_TO_METERS / dpi), scale);
+ } else {
+ dimensions = Overlays.getProperty(overlayID, "dimensions");
+ if (dimensions === undefined) {
+ return;
+ }
+ if (!dimensions.z) {
+ dimensions.z = 0.01; // sometimes overlay dimensions are 2D, not 3D.
+ }
+ }
+ var invDimensions = { x: 1 / dimensions.x, y: 1 / dimensions.y, z: 1 / dimensions.z };
+ var normalizedPosition = Vec3.sum(Vec3.multiplyVbyV(localPos, invDimensions), DEFAULT_REGISTRATION_POINT);
+
+ // 2D position on overlay plane in meters, relative to the bounding box upper-left hand corner.
+ var position2D = { x: normalizedPosition.x * dimensions.x, y: (1 - normalizedPosition.y) * dimensions.y }; // flip y-axis
+
+ return {
+ entityID: null,
+ overlayID: overlayID,
+ distance: distance,
+ position: position,
+ position2D: position2D,
+ normal: normal,
+ normalizedPosition: normalizedPosition,
+ dimensions: dimensions,
+ valid: true
+ };
+}
+
+function isNearStylusTarget(stylusTargets, edgeBorder, minNormalDistance, maxNormalDistance) {
+ for (var i = 0; i < stylusTargets.length; i++) {
+ var stylusTarget = stylusTargets[i];
+
+ // check to see if the projected stylusTip is within within the 2d border
+ var borderMin = {x: -edgeBorder, y: -edgeBorder};
+ var borderMax = {x: stylusTarget.dimensions.x + edgeBorder, y: stylusTarget.dimensions.y + edgeBorder};
+ if (stylusTarget.distance >= minNormalDistance && stylusTarget.distance <= maxNormalDistance &&
+ stylusTarget.position2D.x >= borderMin.x && stylusTarget.position2D.y >= borderMin.y &&
+ stylusTarget.position2D.x <= borderMax.x && stylusTarget.position2D.y <= borderMax.y) {
+ return true;
+ }
+ }
+ return false;
+}
+
+function calculateNearestStylusTarget(stylusTargets) {
+ var nearestStylusTarget;
+
+ for (var i = 0; i < stylusTargets.length; i++) {
+ var stylusTarget = stylusTargets[i];
+
+ if ((!nearestStylusTarget || stylusTarget.distance < nearestStylusTarget.distance) &&
+ stylusTarget.normalizedPosition.x >= 0 && stylusTarget.normalizedPosition.y >= 0 &&
+ stylusTarget.normalizedPosition.x <= 1 && stylusTarget.normalizedPosition.y <= 1) {
+ nearestStylusTarget = stylusTarget;
+ }
+ }
+
+ return nearestStylusTarget;
+};
+
// EntityPropertiesCache is a helper class that contains a cache of entity properties.
// the hope is to prevent excess calls to Entity.getEntityProperties()
//
@@ -796,6 +1030,16 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp) {
}
};
+function getControllerJointIndex(hand) {
+ if (HMD.isHandControllerAvailable()) {
+ return MyAvatar.getJointIndex(hand === RIGHT_HAND ?
+ "_CONTROLLER_RIGHTHAND" :
+ "_CONTROLLER_LEFTHAND");
+ }
+
+ return MyAvatar.getJointIndex("Head");
+}
+
// global EquipHotspotBuddy instance
var equipHotspotBuddy = new EquipHotspotBuddy();
@@ -805,10 +1049,9 @@ function MyController(hand) {
this.grabPointIntersectsEntity = false;
this.stylus = null;
this.homeButtonTouched = false;
+ this.editTriggered = false;
- this.controllerJointIndex = MyAvatar.getJointIndex(this.hand === RIGHT_HAND ?
- "_CONTROLLER_RIGHTHAND" :
- "_CONTROLLER_LEFTHAND");
+ this.controllerJointIndex = getControllerJointIndex(this.hand);
// Until there is some reliable way to keep track of a "stack" of parentIDs, we'll have problems
// when more than one avatar does parenting grabs on things. This script tries to work
@@ -887,6 +1130,17 @@ function MyController(hand) {
this.tabletStabbedPos3D = null;
this.useFingerInsteadOfStylus = false;
+ this.fingerPointing = false;
+
+ // initialize stylus tip
+ var DEFAULT_STYLUS_TIP = {
+ position: {x: 0, y: 0, z: 0},
+ orientation: {x: 0, y: 0, z: 0, w: 0},
+ rotation: {x: 0, y: 0, z: 0, w: 0},
+ velocity: {x: 0, y: 0, z: 0},
+ valid: false
+ };
+ this.stylusTip = DEFAULT_STYLUS_TIP;
var _this = this;
@@ -897,11 +1151,37 @@ function MyController(hand) {
return (-1 !== suppressedIn2D.indexOf(this.state)) && isIn2DMode();
};
+ this.updateStylusTip = function() {
+ if (this.useFingerInsteadOfStylus) {
+ this.stylusTip = getFingerWorldLocation(this.hand);
+ } else {
+ this.stylusTip = getControllerWorldLocation(this.handToController(), true);
+
+ // translate tip forward according to constant.
+ var TIP_OFFSET = {x: 0, y: WEB_STYLUS_LENGTH - WEB_TOUCH_Y_OFFSET, z: 0};
+ this.stylusTip.position = Vec3.sum(this.stylusTip.position, Vec3.multiplyQbyV(this.stylusTip.orientation, TIP_OFFSET));
+ }
+
+ // compute tip velocity from hand controller motion, it is more accurate then computing it from previous positions.
+ var pose = Controller.getPoseValue(this.handToController());
+ if (pose.valid) {
+ var worldControllerPos = Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, pose.translation));
+ var worldControllerLinearVel = Vec3.multiplyQbyV(MyAvatar.orientation, pose.velocity);
+ var worldControllerAngularVel = Vec3.multiplyQbyV(MyAvatar.orientation, pose.angularVelocity);
+ var tipVelocity = Vec3.sum(worldControllerLinearVel, Vec3.cross(worldControllerAngularVel, Vec3.subtract(this.stylusTip.position, worldControllerPos)));
+ this.stylusTip.velocity = tipVelocity;
+ } else {
+ this.stylusTip.velocity = {x: 0, y: 0, z: 0};
+ }
+ };
+
this.update = function(deltaTime, timestamp) {
this.updateSmoothedTrigger();
this.maybeScaleMyAvatar();
- var DEFAULT_USE_FINGER_AS_STYLUS = false;
+ this.updateStylusTip();
+
+ var DEFAULT_USE_FINGER_AS_STYLUS = true;
var USE_FINGER_AS_STYLUS = Settings.getValue("preferAvatarFingerOverStylus");
if (USE_FINGER_AS_STYLUS === "") {
USE_FINGER_AS_STYLUS = DEFAULT_USE_FINGER_AS_STYLUS;
@@ -916,10 +1196,7 @@ function MyController(hand) {
// Most hand input is disabled, because we are interacting with the 2d hud.
// However, we still should check for collisions of the stylus with the web overlay.
-
- var controllerLocation = getControllerWorldLocation(this.handToController(), true);
- this.processStylus(controllerLocation.position);
-
+ this.processStylus();
this.turnOffVisualizations();
return;
}
@@ -949,7 +1226,7 @@ function MyController(hand) {
if ((isInEditMode() && this.grabbedThingID !== HMD.tabletID) &&
(newState !== STATE_OFF &&
newState !== STATE_SEARCHING &&
- newState !== STATE_OVERLAY_STYLUS_TOUCHING &&
+ newState !== STATE_STYLUS_TOUCHING &&
newState !== STATE_OVERLAY_LASER_TOUCHING)) {
return;
}
@@ -1084,10 +1361,6 @@ function MyController(hand) {
}
Overlays.deleteOverlay(this.stylus);
this.stylus = null;
- if (this.stylusTip) {
- Overlays.deleteOverlay(this.stylusTip);
- this.stylusTip = null;
- }
};
this.overlayLineOn = function(closePoint, farPoint, color, farParentID) {
@@ -1137,7 +1410,7 @@ function MyController(hand) {
}
var searchSphereLocation = Vec3.sum(distantPickRay.origin,
- Vec3.multiply(distantPickRay.direction, this.searchSphereDistance));
+ Vec3.multiply(distantPickRay.direction, this.searchSphereDistance));
this.searchSphereOn(searchSphereLocation, SEARCH_SPHERE_SIZE * this.searchSphereDistance,
(this.triggerSmoothedGrab() || this.secondarySqueezed()) ?
COLORS_GRAB_SEARCHING_FULL_SQUEEZE :
@@ -1291,72 +1564,185 @@ function MyController(hand) {
return _this.rawThumbValue < THUMB_ON_VALUE;
};
- this.processStylus = function(worldHandPosition) {
+ this.stealTouchFocus = function(stylusTarget) {
+ // send hover events to target
+ // record the entity or overlay we are hovering over.
+ if ((stylusTarget.entityID === this.getOtherHandController().hoverEntity) ||
+ (stylusTarget.overlayID === this.getOtherHandController().hoverOverlay)) {
+ this.getOtherHandController().relinquishTouchFocus();
+ }
+ this.requestTouchFocus(stylusTarget);
+ };
+
+ this.requestTouchFocus = function(stylusTarget) {
+
+ // send hover events to target if we can.
+ // record the entity or overlay we are hovering over.
+ if (stylusTarget.entityID && stylusTarget.entityID !== this.hoverEntity && stylusTarget.entityID !== this.getOtherHandController().hoverEntity) {
+ this.hoverEntity = stylusTarget.entityID;
+ sendHoverEnterEventToStylusTarget(this.hand, stylusTarget);
+ } else if (stylusTarget.overlayID && stylusTarget.overlayID !== this.hoverOverlay && stylusTarget.overlayID !== this.getOtherHandController().hoverOverlay) {
+ this.hoverOverlay = stylusTarget.overlayID;
+ sendHoverEnterEventToStylusTarget(this.hand, stylusTarget);
+ }
+ };
+
+ this.hasTouchFocus = function(stylusTarget) {
+ return ((stylusTarget.entityID && stylusTarget.entityID === this.hoverEntity) ||
+ (stylusTarget.overlayID && stylusTarget.overlayID === this.hoverOverlay));
+ };
+
+ this.relinquishTouchFocus = function() {
+
+ // send hover leave event.
+ var pointerEvent = { type: "Move", id: this.hand + 1 };
+ if (this.hoverEntity) {
+ Entities.sendHoverLeaveEntity(this.hoverEntity, pointerEvent);
+ this.hoverEntity = null;
+ } else if (this.hoverOverlay) {
+ Overlays.sendMouseMoveOnOverlay(this.hoverOverlay, pointerEvent);
+ Overlays.sendHoverOverOverlay(this.hoverOverlay, pointerEvent);
+ Overlays.sendHoverLeaveOverlay(this.hoverOverlay, pointerEvent);
+ this.hoverOverlay = null;
+ }
+ };
+
+ this.pointFinger = function(value) {
+ var HIFI_POINT_INDEX_MESSAGE_CHANNEL = "Hifi-Point-Index";
+ if (this.fingerPointing !== value) {
+ var message;
+ if (this.hand === RIGHT_HAND) {
+ message = { pointRightIndex: value };
+ } else {
+ message = { pointLeftIndex: value };
+ }
+ Messages.sendMessage(HIFI_POINT_INDEX_MESSAGE_CHANNEL, JSON.stringify(message), true);
+ this.fingerPointing = value;
+ }
+ };
+
+ this.processStylus = function() {
+ if (!this.stylusTip.valid) {
+ this.pointFinger(false);
+ this.hideStylus();
+ return;
+ }
- var performRayTest = false;
if (this.useFingerInsteadOfStylus) {
this.hideStylus();
- performRayTest = true;
- } else {
- var i;
+ }
- // see if the hand is near a tablet or web-entity
- var candidateEntities = Entities.findEntities(worldHandPosition, WEB_DISPLAY_STYLUS_DISTANCE);
- entityPropertiesCache.addEntities(candidateEntities);
- for (i = 0; i < candidateEntities.length; i++) {
- var props = entityPropertiesCache.getProps(candidateEntities[i]);
- if (props && (props.type == "Web" || this.isTablet(candidateEntities[i]))) {
- performRayTest = true;
- break;
+ var tipPosition = this.stylusTip.position;
+
+ var candidates = {
+ entities: [],
+ overlays: []
+ };
+
+ // build list of stylus targets, near the stylusTip
+ var stylusTargets = [];
+ var candidateEntities = Entities.findEntities(tipPosition, WEB_DISPLAY_STYLUS_DISTANCE);
+ entityPropertiesCache.addEntities(candidateEntities);
+ var i, props, stylusTarget;
+ for (i = 0; i < candidateEntities.length; i++) {
+ props = entityPropertiesCache.getProps(candidateEntities[i]);
+ if (props && (props.type === "Web" || this.isTablet(candidateEntities[i]))) {
+ stylusTarget = calculateStylusTargetFromEntity(this.stylusTip, candidateEntities[i]);
+ if (stylusTarget) {
+ stylusTargets.push(stylusTarget);
}
}
+ }
- if (!performRayTest) {
- var candidateOverlays = Overlays.findOverlays(worldHandPosition, WEB_DISPLAY_STYLUS_DISTANCE);
- for (i = 0; i < candidateOverlays.length; i++) {
- if (this.isTablet(candidateOverlays[i])) {
- performRayTest = true;
- break;
- }
- }
+ // add the tabletScreen, if it is valid
+ if (HMD.tabletScreenID && HMD.tabletScreenID !== NULL_UUID && Overlays.getProperty(HMD.tabletScreenID, "visible")) {
+ stylusTarget = calculateStylusTargetFromOverlay(this.stylusTip, HMD.tabletScreenID);
+ if (stylusTarget) {
+ stylusTargets.push(stylusTarget);
}
+ }
- if (performRayTest) {
+ // add the tablet home button.
+ if (HMD.homeButtonID && HMD.homeButtonID !== NULL_UUID && Overlays.getProperty(HMD.homeButtonID, "visible")) {
+ stylusTarget = calculateStylusTargetFromOverlay(this.stylusTip, HMD.homeButtonID);
+ if (stylusTarget) {
+ stylusTargets.push(stylusTarget);
+ }
+ }
+
+ var TABLET_MIN_HOVER_DISTANCE = 0.01;
+ var TABLET_MAX_HOVER_DISTANCE = 0.1;
+ var TABLET_MIN_TOUCH_DISTANCE = -0.05;
+ var TABLET_MAX_TOUCH_DISTANCE = TABLET_MIN_HOVER_DISTANCE;
+ var EDGE_BORDER = 0.075;
+
+ var hysteresisOffset = 0.0;
+ if (this.isNearStylusTarget) {
+ hysteresisOffset = 0.05;
+ }
+
+ this.isNearStylusTarget = isNearStylusTarget(stylusTargets, EDGE_BORDER + hysteresisOffset,
+ TABLET_MIN_TOUCH_DISTANCE - hysteresisOffset, WEB_DISPLAY_STYLUS_DISTANCE + hysteresisOffset);
+
+ if (this.isNearStylusTarget) {
+ if (!this.useFingerInsteadOfStylus) {
this.showStylus();
} else {
- this.hideStylus();
+ this.pointFinger(true);
}
+ } else {
+ this.hideStylus();
+ this.pointFinger(false);
}
- if (performRayTest) {
- var rayPickInfo = this.calcRayPickInfo(this.hand, this.useFingerInsteadOfStylus);
- var max, min;
- if (this.useFingerInsteadOfStylus) {
- max = FINGER_TOUCH_MAX;
- min = FINGER_TOUCH_MIN;
- } else {
- max = WEB_STYLUS_LENGTH / 2.0 + WEB_TOUCH_Y_OFFSET;
- min = WEB_STYLUS_LENGTH / 2.0 + WEB_TOUCH_TOO_CLOSE;
+ var nearestStylusTarget = calculateNearestStylusTarget(stylusTargets);
+
+ if (nearestStylusTarget && nearestStylusTarget.distance > TABLET_MIN_TOUCH_DISTANCE &&
+ nearestStylusTarget.distance < TABLET_MAX_HOVER_DISTANCE) {
+
+ this.requestTouchFocus(nearestStylusTarget);
+
+ if (!stylusTargetHasKeyboardFocus(nearestStylusTarget)) {
+ setKeyboardFocusOnStylusTarget(nearestStylusTarget);
}
- if (rayPickInfo.distance < max && rayPickInfo.distance > min) {
- this.handleStylusOnHomeButton(rayPickInfo);
- if (this.handleStylusOnWebEntity(rayPickInfo)) {
- return;
- }
- if (this.handleStylusOnWebOverlay(rayPickInfo)) {
- return;
- }
- } else {
- this.homeButtonTouched = false;
+ if (this.hasTouchFocus(nearestStylusTarget)) {
+ sendHoverOverEventToStylusTarget(this.hand, nearestStylusTarget);
}
+
+ // filter out presses when tip is moving away from tablet.
+ // ensure that stylus is within bounding box by checking normalizedPosition
+ if (nearestStylusTarget.valid && nearestStylusTarget.distance > TABLET_MIN_TOUCH_DISTANCE &&
+ nearestStylusTarget.distance < TABLET_MAX_TOUCH_DISTANCE && Vec3.dot(this.stylusTip.velocity, nearestStylusTarget.normal) < 0 &&
+ nearestStylusTarget.normalizedPosition.x >= 0 && nearestStylusTarget.normalizedPosition.x <= 1 &&
+ nearestStylusTarget.normalizedPosition.y >= 0 && nearestStylusTarget.normalizedPosition.y <= 1) {
+
+ var name;
+ if (nearestStylusTarget.entityID) {
+ name = entityPropertiesCache.getProps(nearestStylusTarget.entityID).name;
+ this.stylusTarget = nearestStylusTarget;
+ this.setState(STATE_STYLUS_TOUCHING, "begin touching entity '" + name + "'");
+ } else if (nearestStylusTarget.overlayID) {
+ name = Overlays.getProperty(nearestStylusTarget.overlayID, "name");
+ this.stylusTarget = nearestStylusTarget;
+ this.setState(STATE_STYLUS_TOUCHING, "begin touching overlay '" + name + "'");
+ }
+ }
+ } else {
+ this.relinquishTouchFocus();
}
+
+ this.homeButtonTouched = false;
};
this.off = function(deltaTime, timestamp) {
this.checkForUnexpectedChildren();
+ if (this.editTriggered) {
+ this.editTriggered = false;
+ }
+
if (this.triggerSmoothedReleased() && this.secondaryReleased()) {
this.waitForTriggerRelease = false;
}
@@ -1406,25 +1792,7 @@ function MyController(hand) {
this.grabPointSphereOff();
}
- this.processStylus(worldHandPosition);
- };
-
- this.handleStylusOnHomeButton = function(rayPickInfo) {
- if (rayPickInfo.overlayID) {
- var homeButton = rayPickInfo.overlayID;
- var hmdHomeButton = HMD.homeButtonID;
- if (homeButton === hmdHomeButton) {
- if (this.homeButtonTouched === false) {
- this.homeButtonTouched = true;
- Controller.triggerHapticPulse(HAPTIC_STYLUS_STRENGTH, HAPTIC_STYLUS_DURATION, this.hand);
- Messages.sendLocalMessage("home", homeButton);
- }
- } else {
- this.homeButtonTouched = false;
- }
- } else {
- this.homeButtonTouched = false;
- }
+ this.processStylus();
};
this.handleLaserOnHomeButton = function(rayPickInfo) {
@@ -1464,27 +1832,27 @@ function MyController(hand) {
// Performs ray pick test from the hand controller into the world
// @param {number} which hand to use, RIGHT_HAND or LEFT_HAND
- // @param {bool} if true use the world position/orientation of the index finger to cast the ray from.
+ // @param {object} if set, use this as as the pick ray, expects origin, direction, and length fields.
// @returns {object} returns object with two keys entityID and distance
//
- this.calcRayPickInfo = function(hand, useFingerInsteadOfController) {
+ this.calcRayPickInfo = function(hand, pickRayOverride) {
- var controllerLocation;
- if (useFingerInsteadOfController) {
- controllerLocation = getFingerWorldLocation(hand);
+ var pickRay;
+ if (pickRayOverride) {
+ pickRay = pickRayOverride;
} else {
- controllerLocation = getControllerWorldLocation(this.handToController(), true);
- }
- var worldHandPosition = controllerLocation.position;
- var worldHandRotation = controllerLocation.orientation;
+ var controllerLocation = getControllerWorldLocation(this.handToController(), true);
+ var worldHandPosition = controllerLocation.position;
+ var worldHandRotation = controllerLocation.orientation;
- var pickRay = {
- origin: PICK_WITH_HAND_RAY ? worldHandPosition : Camera.position,
- direction: PICK_WITH_HAND_RAY ? Quat.getUp(worldHandRotation) : Vec3.mix(Quat.getUp(worldHandRotation),
- Quat.getForward(Camera.orientation),
- HAND_HEAD_MIX_RATIO),
- length: PICK_MAX_DISTANCE
- };
+ pickRay = {
+ origin: PICK_WITH_HAND_RAY ? worldHandPosition : Camera.position,
+ direction: PICK_WITH_HAND_RAY ? Quat.getUp(worldHandRotation) : Vec3.mix(Quat.getUp(worldHandRotation),
+ Quat.getFront(Camera.orientation),
+ HAND_HEAD_MIX_RATIO),
+ length: PICK_MAX_DISTANCE
+ };
+ }
var result = {
entityID: null,
@@ -1843,23 +2211,21 @@ function MyController(hand) {
return aDistance - bDistance;
});
entity = grabbableEntities[0];
- name = entityPropertiesCache.getProps(entity).name;
- this.grabbedThingID = entity;
- this.grabbedIsOverlay = false;
- if (this.entityWantsTrigger(entity)) {
- if (this.triggerSmoothedGrab()) {
- this.setState(STATE_NEAR_TRIGGER, "near trigger '" + name + "'");
- return;
+ if (!isInEditMode() || entity == HMD.tabletID) { // tablet is grabbable, even when editing
+ name = entityPropertiesCache.getProps(entity).name;
+ this.grabbedThingID = entity;
+ this.grabbedIsOverlay = false;
+ if (this.entityWantsTrigger(entity)) {
+ if (this.triggerSmoothedGrab()) {
+ this.setState(STATE_NEAR_TRIGGER, "near trigger '" + name + "'");
+ return;
+ }
} else {
- // potentialNearTriggerEntity = entity;
- }
- } else {
- // If near something grabbable, grab it!
- if ((this.triggerSmoothedGrab() || this.secondarySqueezed()) && nearGrabEnabled) {
- this.setState(STATE_NEAR_GRABBING, "near grab entity '" + name + "'");
- return;
- } else {
- // potentialNearGrabEntity = entity;
+ // If near something grabbable, grab it!
+ if ((this.triggerSmoothedGrab() || this.secondarySqueezed()) && nearGrabEnabled) {
+ this.setState(STATE_NEAR_GRABBING, "near grab entity '" + name + "'");
+ return;
+ }
}
}
}
@@ -1874,6 +2240,21 @@ function MyController(hand) {
}
}
+ if (isInEditMode()) {
+ this.searchIndicatorOn(rayPickInfo.searchRay);
+ if (this.triggerSmoothedGrab()) {
+ if (!this.editTriggered && rayPickInfo.entityID) {
+ Messages.sendLocalMessage("entityToolUpdates", JSON.stringify({
+ method: "selectEntity",
+ entityID: rayPickInfo.entityID
+ }));
+ }
+ this.editTriggered = true;
+ }
+ Reticle.setVisible(false);
+ return;
+ }
+
if (rayPickInfo.entityID) {
entity = rayPickInfo.entityID;
name = entityPropertiesCache.getProps(entity).name;
@@ -1943,7 +2324,7 @@ function MyController(hand) {
return false;
};
- this.handleStylusOnWebEntity = function (rayPickInfo) {
+ this.handleLaserOnWebEntity = function (rayPickInfo) {
var pointerEvent;
if (rayPickInfo.entityID && Entities.wantsHandControllerPointerEvents(rayPickInfo.entityID)) {
@@ -1972,9 +2353,8 @@ function MyController(hand) {
if (this.hand == mostRecentSearchingHand ||
(this.hand !== mostRecentSearchingHand &&
this.getOtherHandController().state !== STATE_SEARCHING &&
- this.getOtherHandController().state !== STATE_ENTITY_STYLUS_TOUCHING &&
+ this.getOtherHandController().state !== STATE_STYLUS_TOUCHING &&
this.getOtherHandController().state !== STATE_ENTITY_LASER_TOUCHING &&
- this.getOtherHandController().state !== STATE_OVERLAY_STYLUS_TOUCHING &&
this.getOtherHandController().state !== STATE_OVERLAY_LASER_TOUCHING)) {
// most recently searching hand has priority over other hand, for the purposes of button highlighting.
@@ -1992,140 +2372,13 @@ function MyController(hand) {
Entities.sendHoverOverEntity(entity, pointerEvent);
}
- this.grabbedThingID = entity;
- this.grabbedIsOverlay = false;
- this.setState(STATE_ENTITY_STYLUS_TOUCHING, "begin touching entity '" + name + "'");
- return true;
-
- } else if (this.hoverEntity) {
- pointerEvent = {
- type: "Move",
- id: this.hand + 1
- };
- Entities.sendHoverLeaveEntity(this.hoverEntity, pointerEvent);
- this.hoverEntity = null;
- }
-
- return false;
- };
-
- this.handleStylusOnWebOverlay = function (rayPickInfo) {
- var pointerEvent;
- if (rayPickInfo.overlayID) {
- var overlay = rayPickInfo.overlayID;
- if (Overlays.keyboardFocusOverlay != overlay) {
- Entities.keyboardFocusEntity = null;
- Overlays.keyboardFocusOverlay = overlay;
-
- pointerEvent = {
- type: "Move",
- id: HARDWARE_MOUSE_ID,
- pos2D: projectOntoOverlayXYPlane(overlay, rayPickInfo.intersection),
- pos3D: rayPickInfo.intersection,
- normal: rayPickInfo.normal,
- direction: rayPickInfo.searchRay.direction,
- button: "None"
- };
-
- this.hoverOverlay = overlay;
- Overlays.sendHoverEnterOverlay(overlay, pointerEvent);
- }
-
- // Send mouse events for button highlights and tooltips.
- if (this.hand == mostRecentSearchingHand ||
- (this.hand !== mostRecentSearchingHand &&
- this.getOtherHandController().state !== STATE_SEARCHING &&
- this.getOtherHandController().state !== STATE_ENTITY_STYLUS_TOUCHING &&
- this.getOtherHandController().state !== STATE_ENTITY_LASER_TOUCHING &&
- this.getOtherHandController().state !== STATE_OVERLAY_STYLUS_TOUCHING &&
- this.getOtherHandController().state !== STATE_OVERLAY_LASER_TOUCHING)) {
-
- // most recently searching hand has priority over other hand, for the purposes of button highlighting.
- pointerEvent = {
- type: "Move",
- id: HARDWARE_MOUSE_ID,
- pos2D: projectOntoOverlayXYPlane(overlay, rayPickInfo.intersection),
- pos3D: rayPickInfo.intersection,
- normal: rayPickInfo.normal,
- direction: rayPickInfo.searchRay.direction,
- button: "None"
- };
-
- Overlays.sendMouseMoveOnOverlay(overlay, pointerEvent);
- Overlays.sendHoverOverOverlay(overlay, pointerEvent);
- }
-
- this.grabbedOverlay = overlay;
- this.setState(STATE_OVERLAY_STYLUS_TOUCHING, "begin touching overlay '" + overlay + "'");
- return true;
-
- } else if (this.hoverOverlay) {
- pointerEvent = {
- type: "Move",
- id: HARDWARE_MOUSE_ID
- };
- Overlays.sendHoverLeaveOverlay(this.hoverOverlay, pointerEvent);
- this.hoverOverlay = null;
- }
-
- return false;
- };
-
- this.handleLaserOnWebEntity = function(rayPickInfo) {
- var pointerEvent;
- if (rayPickInfo.entityID && Entities.wantsHandControllerPointerEvents(rayPickInfo.entityID)) {
- var entity = rayPickInfo.entityID;
- var props = entityPropertiesCache.getProps(entity);
- var name = props.name;
-
- if (Entities.keyboardFocusEntity != entity) {
- Overlays.keyboardFocusOverlay = 0;
- Entities.keyboardFocusEntity = entity;
-
- pointerEvent = {
- type: "Move",
- id: this.hand + 1, // 0 is reserved for hardware mouse
- pos2D: projectOntoEntityXYPlane(entity, rayPickInfo.intersection),
- pos3D: rayPickInfo.intersection,
- normal: rayPickInfo.normal,
- direction: rayPickInfo.searchRay.direction,
- button: "None"
- };
-
- this.hoverEntity = entity;
- Entities.sendHoverEnterEntity(entity, pointerEvent);
- }
-
- // send mouse events for button highlights and tooltips.
- if (this.hand == mostRecentSearchingHand ||
- (this.hand !== mostRecentSearchingHand &&
- this.getOtherHandController().state !== STATE_SEARCHING &&
- this.getOtherHandController().state !== STATE_ENTITY_STYLUS_TOUCHING &&
- this.getOtherHandController().state !== STATE_ENTITY_LASER_TOUCHING &&
- this.getOtherHandController().state !== STATE_OVERLAY_STYLUS_TOUCHING &&
- this.getOtherHandController().state !== STATE_OVERLAY_LASER_TOUCHING)) {
-
- // most recently searching hand has priority over other hand, for the purposes of button highlighting.
- pointerEvent = {
- type: "Move",
- id: this.hand + 1, // 0 is reserved for hardware mouse
- pos2D: projectOntoEntityXYPlane(entity, rayPickInfo.intersection),
- pos3D: rayPickInfo.intersection,
- normal: rayPickInfo.normal,
- direction: rayPickInfo.searchRay.direction,
- button: "None"
- };
-
- Entities.sendMouseMoveOnEntity(entity, pointerEvent);
- Entities.sendHoverOverEntity(entity, pointerEvent);
- }
-
- if (this.triggerSmoothedGrab() && (!isEditing() || this.isTablet(entity))) {
+ if (this.triggerSmoothedGrab()) {
this.grabbedThingID = entity;
this.grabbedIsOverlay = false;
this.setState(STATE_ENTITY_LASER_TOUCHING, "begin touching entity '" + name + "'");
return true;
}
+
} else if (this.hoverEntity) {
pointerEvent = {
type: "Move",
@@ -2138,13 +2391,13 @@ function MyController(hand) {
return false;
};
- this.handleLaserOnWebOverlay = function(rayPickInfo) {
+ this.handleLaserOnWebOverlay = function (rayPickInfo) {
var pointerEvent;
- var overlay;
-
if (rayPickInfo.overlayID) {
- overlay = rayPickInfo.overlayID;
-
+ var overlay = rayPickInfo.overlayID;
+ if (Overlays.getProperty(overlay, "type") != "web3d") {
+ return false;
+ }
if (Overlays.keyboardFocusOverlay != overlay) {
Entities.keyboardFocusEntity = null;
Overlays.keyboardFocusOverlay = overlay;
@@ -2167,9 +2420,8 @@ function MyController(hand) {
if (this.hand == mostRecentSearchingHand ||
(this.hand !== mostRecentSearchingHand &&
this.getOtherHandController().state !== STATE_SEARCHING &&
- this.getOtherHandController().state !== STATE_ENTITY_STYLUS_TOUCHING &&
+ this.getOtherHandController().state !== STATE_STYLUS_TOUCHING &&
this.getOtherHandController().state !== STATE_ENTITY_LASER_TOUCHING &&
- this.getOtherHandController().state !== STATE_OVERLAY_STYLUS_TOUCHING &&
this.getOtherHandController().state !== STATE_OVERLAY_LASER_TOUCHING)) {
// most recently searching hand has priority over other hand, for the purposes of button highlighting.
@@ -3094,14 +3346,9 @@ function MyController(hand) {
this.release();
};
- this.entityTouchingEnter = function() {
+ this.entityLaserTouchingEnter = function() {
// test for intersection between controller laser and web entity plane.
- var controllerLocation;
- if (this.useFingerInsteadOfStylus && this.state === STATE_ENTITY_STYLUS_TOUCHING) {
- controllerLocation = getFingerWorldLocation(this.hand);
- } else {
- controllerLocation = getControllerWorldLocation(this.handToController(), true);
- }
+ var controllerLocation = getControllerWorldLocation(this.handToController(), true);
var intersectInfo = handLaserIntersectEntity(this.grabbedThingID, controllerLocation);
if (intersectInfo) {
var pointerEvent = {
@@ -3124,26 +3371,15 @@ function MyController(hand) {
this.deadspotExpired = false;
var LASER_PRESS_TO_MOVE_DEADSPOT_ANGLE = 0.026; // radians ~ 1.2 degrees
- var STYLUS_PRESS_TO_MOVE_DEADSPOT_ANGLE = 0.314; // radians ~ 18 degrees
- var theta = this.state === STATE_ENTITY_STYLUS_TOUCHING ? STYLUS_PRESS_TO_MOVE_DEADSPOT_ANGLE : LASER_PRESS_TO_MOVE_DEADSPOT_ANGLE;
- this.deadspotRadius = Math.tan(theta) * intersectInfo.distance; // dead spot radius in meters
+ this.deadspotRadius = Math.tan(LASER_PRESS_TO_MOVE_DEADSPOT_ANGLE) * intersectInfo.distance; // dead spot radius in meters
}
- if (this.state == STATE_ENTITY_STYLUS_TOUCHING) {
- Controller.triggerHapticPulse(HAPTIC_STYLUS_STRENGTH, HAPTIC_STYLUS_DURATION, this.hand);
- } else if (this.state == STATE_ENTITY_LASER_TOUCHING) {
- Controller.triggerHapticPulse(HAPTIC_LASER_UI_STRENGTH, HAPTIC_LASER_UI_DURATION, this.hand);
- }
+ Controller.triggerHapticPulse(HAPTIC_LASER_UI_STRENGTH, HAPTIC_LASER_UI_DURATION, this.hand);
};
- this.entityTouchingExit = function() {
+ this.entityLaserTouchingExit = function() {
// test for intersection between controller laser and web entity plane.
- var controllerLocation;
- if (this.useFingerInsteadOfStylus && this.state === STATE_ENTITY_STYLUS_TOUCHING) {
- controllerLocation = getFingerWorldLocation(this.hand);
- } else {
- controllerLocation = getControllerWorldLocation(this.handToController(), true);
- }
+ var controllerLocation = getControllerWorldLocation(this.handToController(), true);
var intersectInfo = handLaserIntersectEntity(this.grabbedThingID, controllerLocation);
if (intersectInfo) {
var pointerEvent;
@@ -3172,40 +3408,22 @@ function MyController(hand) {
this.grabbedOverlay = null;
};
- this.entityTouching = function(dt) {
+ this.entityLaserTouching = function(dt) {
this.touchingEnterTimer += dt;
entityPropertiesCache.addEntity(this.grabbedThingID);
- if (this.state == STATE_ENTITY_LASER_TOUCHING && !this.triggerSmoothedGrab()) {
+ if (this.state == STATE_ENTITY_LASER_TOUCHING && !this.triggerSmoothedGrab()) { // AJT:
this.setState(STATE_OFF, "released trigger");
return;
}
// test for intersection between controller laser and web entity plane.
- var controllerLocation;
- if (this.useFingerInsteadOfStylus && this.state === STATE_ENTITY_STYLUS_TOUCHING) {
- controllerLocation = getFingerWorldLocation(this.hand);
- } else {
- controllerLocation = getControllerWorldLocation(this.handToController(), true);
- }
+ var controllerLocation = getControllerWorldLocation(this.handToController(), true);
var intersectInfo = handLaserIntersectEntity(this.grabbedThingID, controllerLocation);
if (intersectInfo) {
- var max;
- if (this.useFingerInsteadOfStylus && this.state === STATE_ENTITY_STYLUS_TOUCHING) {
- max = FINGER_TOUCH_MAX;
- } else {
- max = WEB_STYLUS_LENGTH / 2.0 + WEB_TOUCH_Y_OFFSET;
- }
-
- if (this.state == STATE_ENTITY_STYLUS_TOUCHING &&
- intersectInfo.distance > max) {
- this.setState(STATE_OFF, "pulled away from web entity");
- return;
- }
-
if (Entities.keyboardFocusEntity != this.grabbedThingID) {
Overlays.keyboardFocusOverlay = 0;
Entities.keyboardFocusEntity = this.grabbedThingID;
@@ -3242,19 +3460,14 @@ function MyController(hand) {
}
};
- this.overlayTouchingEnter = function () {
+ this.overlayLaserTouchingEnter = function () {
// Test for intersection between controller laser and Web overlay plane.
- var controllerLocation;
- if (this.useFingerInsteadOfStylus && this.state === STATE_OVERLAY_STYLUS_TOUCHING) {
- controllerLocation = getFingerWorldLocation(this.hand);
- } else {
- controllerLocation = getControllerWorldLocation(this.handToController(), true);
- }
+ var controllerLocation = getControllerWorldLocation(this.handToController(), true);
var intersectInfo = handLaserIntersectOverlay(this.grabbedOverlay, controllerLocation);
if (intersectInfo) {
var pointerEvent = {
type: "Press",
- id: HARDWARE_MOUSE_ID,
+ id: this.hand + 1,
pos2D: projectOntoOverlayXYPlane(this.grabbedOverlay, intersectInfo.point),
pos3D: intersectInfo.point,
normal: intersectInfo.normal,
@@ -3271,26 +3484,15 @@ function MyController(hand) {
this.deadspotExpired = false;
var LASER_PRESS_TO_MOVE_DEADSPOT_ANGLE = 0.026; // radians ~ 1.2 degrees
- var STYLUS_PRESS_TO_MOVE_DEADSPOT_ANGLE = 0.314; // radians ~ 18 degrees
- var theta = this.state === STATE_OVERLAY_STYLUS_TOUCHING ? STYLUS_PRESS_TO_MOVE_DEADSPOT_ANGLE : LASER_PRESS_TO_MOVE_DEADSPOT_ANGLE;
- this.deadspotRadius = Math.tan(theta) * intersectInfo.distance; // dead spot radius in meters
+ this.deadspotRadius = Math.tan(LASER_PRESS_TO_MOVE_DEADSPOT_ANGLE) * intersectInfo.distance; // dead spot radius in meters
}
- if (this.state == STATE_OVERLAY_STYLUS_TOUCHING) {
- Controller.triggerHapticPulse(HAPTIC_STYLUS_STRENGTH, HAPTIC_STYLUS_DURATION, this.hand);
- } else if (this.state == STATE_OVERLAY_LASER_TOUCHING) {
- Controller.triggerHapticPulse(HAPTIC_LASER_UI_STRENGTH, HAPTIC_LASER_UI_DURATION, this.hand);
- }
+ Controller.triggerHapticPulse(HAPTIC_LASER_UI_STRENGTH, HAPTIC_LASER_UI_DURATION, this.hand);
};
- this.overlayTouchingExit = function () {
+ this.overlayLaserTouchingExit = function () {
// Test for intersection between controller laser and Web overlay plane.
- var controllerLocation;
- if (this.useFingerInsteadOfStylus && this.state === STATE_OVERLAY_STYLUS_TOUCHING) {
- controllerLocation = getFingerWorldLocation(this.hand);
- } else {
- controllerLocation = getControllerWorldLocation(this.handToController(), true);
- }
+ var controllerLocation = getControllerWorldLocation(this.handToController(), true);
var intersectInfo = handLaserIntersectOverlay(this.grabbedOverlay, controllerLocation);
if (intersectInfo) {
var pointerEvent;
@@ -3314,7 +3516,7 @@ function MyController(hand) {
if (this.deadspotExpired) {
pointerEvent = {
type: "Release",
- id: HARDWARE_MOUSE_ID,
+ id: this.hand + 1,
pos2D: pos2D,
pos3D: pos3D,
normal: intersectInfo.normal,
@@ -3335,66 +3537,22 @@ function MyController(hand) {
this.grabbedOverlay = null;
};
- this.overlayTouching = function (dt) {
+ this.overlayLaserTouching = function (dt) {
this.touchingEnterTimer += dt;
- if (this.state == STATE_OVERLAY_STYLUS_TOUCHING && this.triggerSmoothedSqueezed()) {
- return;
- }
-
if (this.state == STATE_OVERLAY_LASER_TOUCHING && !this.triggerSmoothedGrab()) {
this.setState(STATE_OFF, "released trigger");
return;
}
// Test for intersection between controller laser and Web overlay plane.
- var controllerLocation;
- if (this.useFingerInsteadOfStylus && this.state === STATE_OVERLAY_STYLUS_TOUCHING) {
- controllerLocation = getFingerWorldLocation(this.hand);
- } else {
- controllerLocation = getControllerWorldLocation(this.handToController(), true);
- }
+ var controllerLocation = getControllerWorldLocation(this.handToController(), true);
var intersectInfo = handLaserIntersectOverlay(this.grabbedOverlay, controllerLocation);
if (intersectInfo) {
- var max, min;
- if (this.useFingerInsteadOfStylus && this.state === STATE_OVERLAY_STYLUS_TOUCHING) {
- max = FINGER_TOUCH_MAX;
- min = FINGER_TOUCH_MIN;
- } else {
- max = WEB_STYLUS_LENGTH / 2.0 + WEB_TOUCH_Y_OFFSET + WEB_TOUCH_Y_TOUCH_DEADZONE_SIZE;
- min = WEB_STYLUS_LENGTH / 2.0 + WEB_TOUCH_TOO_CLOSE;
- }
-
- if (this.state == STATE_OVERLAY_STYLUS_TOUCHING && intersectInfo.distance > max) {
- this.grabbedThingID = null;
- this.setState(STATE_OFF, "pulled away from overlay");
- return;
- }
-
var pos2D = projectOntoOverlayXYPlane(this.grabbedOverlay, intersectInfo.point);
var pos3D = intersectInfo.point;
- if (this.state == STATE_OVERLAY_STYLUS_TOUCHING &&
- !this.tabletStabbed &&
- intersectInfo.distance < min) {
- // they've stabbed the tablet, don't send events until they pull back
- this.tabletStabbed = true;
- this.tabletStabbedPos2D = pos2D;
- this.tabletStabbedPos3D = pos3D;
- return;
- }
-
- if (this.tabletStabbed) {
- var origin = {x: this.tabletStabbedPos2D.x, y: this.tabletStabbedPos2D.y, z: 0};
- var point = {x: pos2D.x, y: pos2D.y, z: 0};
- var offset = Vec3.distance(origin, point);
- var radius = 0.05;
- if (offset < radius) {
- return;
- }
- }
-
if (Overlays.keyboardFocusOverlay != this.grabbedOverlay) {
Entities.keyboardFocusEntity = null;
Overlays.keyboardFocusOverlay = this.grabbedOverlay;
@@ -3402,7 +3560,7 @@ function MyController(hand) {
var pointerEvent = {
type: "Move",
- id: HARDWARE_MOUSE_ID,
+ id: this.hand + 1,
pos2D: pos2D,
pos3D: pos3D,
normal: intersectInfo.normal,
@@ -3430,6 +3588,68 @@ function MyController(hand) {
}
};
+ this.stylusTouchingEnter = function () {
+ this.stealTouchFocus(this.stylusTarget);
+ sendTouchStartEventToStylusTarget(this.hand, this.stylusTarget);
+ Controller.triggerHapticPulse(HAPTIC_STYLUS_STRENGTH, HAPTIC_STYLUS_DURATION, this.hand);
+
+ this.touchingEnterTimer = 0;
+ this.touchingEnterStylusTarget = this.stylusTarget;
+ this.deadspotExpired = false;
+
+ var TOUCH_PRESS_TO_MOVE_DEADSPOT = 0.0381;
+ this.deadspotRadius = TOUCH_PRESS_TO_MOVE_DEADSPOT;
+ };
+
+ this.stylusTouchingExit = function () {
+
+ if (this.stylusTarget === undefined) {
+ return;
+ }
+
+ // special case to handle home button.
+ if (this.stylusTarget.overlayID === HMD.homeButtonID) {
+ Messages.sendLocalMessage("home", this.stylusTarget.overlayID);
+ }
+
+ // send press event
+ if (this.deadspotExpired) {
+ sendTouchEndEventToStylusTarget(this.hand, this.stylusTarget);
+ } else {
+ sendTouchEndEventToStylusTarget(this.hand, this.touchingEnterStylusTarget);
+ }
+ };
+
+ this.stylusTouching = function (dt) {
+
+ this.touchingEnterTimer += dt;
+
+ if (this.stylusTarget.entityID) {
+ entityPropertiesCache.addEntity(this.stylusTarget.entityID);
+ this.stylusTarget = calculateStylusTargetFromEntity(this.stylusTip, this.stylusTarget.entityID);
+ } else if (this.stylusTarget.overlayID) {
+ this.stylusTarget = calculateStylusTargetFromOverlay(this.stylusTip, this.stylusTarget.overlayID);
+ }
+
+ var TABLET_MIN_TOUCH_DISTANCE = -0.1;
+ var TABLET_MAX_TOUCH_DISTANCE = 0.01;
+
+ if (this.stylusTarget) {
+ if (this.stylusTarget.distance > TABLET_MIN_TOUCH_DISTANCE && this.stylusTarget.distance < TABLET_MAX_TOUCH_DISTANCE) {
+ var POINTER_PRESS_TO_MOVE_DELAY = 0.33; // seconds
+ if (this.deadspotExpired || this.touchingEnterTimer > POINTER_PRESS_TO_MOVE_DELAY ||
+ distance2D(this.stylusTarget.position2D, this.touchingEnterStylusTarget.position2D) > this.deadspotRadius) {
+ sendTouchMoveEventToStylusTarget(this.hand, this.stylusTarget);
+ this.deadspotExpired = true;
+ }
+ } else {
+ this.setState(STATE_OFF, "hand moved away from touch surface");
+ }
+ } else {
+ this.setState(STATE_OFF, "touch surface was destroyed");
+ }
+ };
+
this.release = function() {
this.turnOffVisualizations();
@@ -3495,6 +3715,8 @@ function MyController(hand) {
this.cleanup = function() {
this.release();
this.grabPointSphereOff();
+ this.hideStylus();
+ this.overlayLineOff();
};
this.thisHandIsParent = function(props) {
diff --git a/scripts/system/controllers/squeezeHands.js b/scripts/system/controllers/squeezeHands.js
index 75e6249dd6..c9de473e28 100644
--- a/scripts/system/controllers/squeezeHands.js
+++ b/scripts/system/controllers/squeezeHands.js
@@ -11,6 +11,7 @@
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
+/* eslint indent: ["error", 4, { "outerIIFEBody": 0 }] */
(function() { // BEGIN LOCAL_SCOPE
@@ -25,7 +26,11 @@ var OVERLAY_RAMP_RATE = 8.0;
var animStateHandlerID;
-var isBothIndexesPointing = false;
+var leftIndexPointingOverride = 0;
+var rightIndexPointingOverride = 0;
+var leftThumbRaisedOverride = 0;
+var rightThumbRaisedOverride = 0;
+
var HIFI_POINT_INDEX_MESSAGE_CHANNEL = "Hifi-Point-Index";
var isLeftIndexPointing = false;
@@ -53,7 +58,7 @@ function init() {
"leftHandOverlayAlpha", "leftHandGraspAlpha",
"rightHandOverlayAlpha", "rightHandGraspAlpha",
"isLeftHandGrasp", "isLeftIndexPoint", "isLeftThumbRaise", "isLeftIndexPointAndThumbRaise",
- "isRightHandGrasp", "isRightIndexPoint", "isRightThumbRaise", "isRightIndexPointAndThumbRaise",
+ "isRightHandGrasp", "isRightIndexPoint", "isRightThumbRaise", "isRightIndexPointAndThumbRaise"
]
);
Messages.subscribe(HIFI_POINT_INDEX_MESSAGE_CHANNEL);
@@ -66,21 +71,23 @@ function animStateHandler(props) {
leftHandGraspAlpha: lastLeftTrigger,
rightHandOverlayAlpha: rightHandOverlayAlpha,
rightHandGraspAlpha: lastRightTrigger,
- isLeftHandGrasp: !isBothIndexesPointing && !isLeftIndexPointing && !isLeftThumbRaised,
- isLeftIndexPoint: (isBothIndexesPointing || isLeftIndexPointing) && !isLeftThumbRaised,
- isLeftThumbRaise: !isBothIndexesPointing && !isLeftIndexPointing && isLeftThumbRaised,
- isLeftIndexPointAndThumbRaise: (isBothIndexesPointing || isLeftIndexPointing) && isLeftThumbRaised,
- isRightHandGrasp: !isBothIndexesPointing && !isRightIndexPointing && !isRightThumbRaised,
- isRightIndexPoint: (isBothIndexesPointing || isRightIndexPointing) && !isRightThumbRaised,
- isRightThumbRaise: !isBothIndexesPointing && !isRightIndexPointing && isRightThumbRaised,
- isRightIndexPointAndThumbRaise: (isBothIndexesPointing || isRightIndexPointing) && isRightThumbRaised
+
+ isLeftHandGrasp: !isLeftIndexPointing && !isLeftThumbRaised,
+ isLeftIndexPoint: isLeftIndexPointing && !isLeftThumbRaised,
+ isLeftThumbRaise: !isLeftIndexPointing && isLeftThumbRaised,
+ isLeftIndexPointAndThumbRaise: isLeftIndexPointing && isLeftThumbRaised,
+
+ isRightHandGrasp: !isRightIndexPointing && !isRightThumbRaised,
+ isRightIndexPoint: isRightIndexPointing && !isRightThumbRaised,
+ isRightThumbRaise: !isRightIndexPointing && isRightThumbRaised,
+ isRightIndexPointAndThumbRaise: isRightIndexPointing && isRightThumbRaised
};
}
function update(dt) {
var leftTrigger = clamp(Controller.getValue(Controller.Standard.LT) + Controller.getValue(Controller.Standard.LeftGrip), 0, 1);
var rightTrigger = clamp(Controller.getValue(Controller.Standard.RT) + Controller.getValue(Controller.Standard.RightGrip), 0, 1);
-
+
// Average last few trigger values together for a bit of smoothing
var tau = clamp(dt / TRIGGER_SMOOTH_TIMESCALE, 0, 1);
lastLeftTrigger = lerp(leftTrigger, lastLeftTrigger, tau);
@@ -103,18 +110,61 @@ function update(dt) {
}
// Pointing index fingers and raising thumbs
- isLeftIndexPointing = leftHandPose.valid && Controller.getValue(Controller.Standard.LeftIndexPoint) === 1;
- isRightIndexPointing = rightHandPose.valid && Controller.getValue(Controller.Standard.RightIndexPoint) === 1;
- isLeftThumbRaised = leftHandPose.valid && Controller.getValue(Controller.Standard.LeftThumbUp) === 1;
- isRightThumbRaised = rightHandPose.valid && Controller.getValue(Controller.Standard.RightThumbUp) === 1;
+ isLeftIndexPointing = (leftIndexPointingOverride > 0) || (leftHandPose.valid && Controller.getValue(Controller.Standard.LeftIndexPoint) === 1);
+ isRightIndexPointing = (rightIndexPointingOverride > 0) || (rightHandPose.valid && Controller.getValue(Controller.Standard.RightIndexPoint) === 1);
+ isLeftThumbRaised = (leftThumbRaisedOverride > 0) || (leftHandPose.valid && Controller.getValue(Controller.Standard.LeftThumbUp) === 1);
+ isRightThumbRaised = (rightThumbRaisedOverride > 0) || (rightHandPose.valid && Controller.getValue(Controller.Standard.RightThumbUp) === 1);
}
function handleMessages(channel, message, sender) {
if (sender === MyAvatar.sessionUUID && channel === HIFI_POINT_INDEX_MESSAGE_CHANNEL) {
var data = JSON.parse(message);
+
if (data.pointIndex !== undefined) {
- print("pointIndex: " + data.pointIndex);
- isBothIndexesPointing = data.pointIndex;
+ if (data.pointIndex) {
+ leftIndexPointingOverride++;
+ rightIndexPointingOverride++;
+ } else {
+ leftIndexPointingOverride--;
+ rightIndexPointingOverride--;
+ }
+ }
+ if (data.pointLeftIndex !== undefined) {
+ if (data.pointLeftIndex) {
+ leftIndexPointingOverride++;
+ } else {
+ leftIndexPointingOverride--;
+ }
+ }
+ if (data.pointRightIndex !== undefined) {
+ if (data.pointRightIndex) {
+ rightIndexPointingOverride++;
+ } else {
+ rightIndexPointingOverride--;
+ }
+ }
+ if (data.raiseThumbs !== undefined) {
+ if (data.raiseThumbs) {
+ leftThumbRaisedOverride++;
+ rightThumbRaisedOverride++;
+ } else {
+ leftThumbRaisedOverride--;
+ rightThumbRaisedOverride--;
+ }
+ }
+ if (data.raiseLeftThumb !== undefined) {
+ if (data.raiseLeftThumb) {
+ leftThumbRaisedOverride++;
+ } else {
+ leftThumbRaisedOverride--;
+ }
+ }
+ if (data.raiseRightThumb !== undefined) {
+ if (data.raiseRightThumb) {
+ rightThumbRaisedOverride++;
+ } else {
+ rightThumbRaisedOverride--;
+ }
}
}
}
diff --git a/scripts/system/edit.js b/scripts/system/edit.js
index 8b02eb1550..770ebecba2 100644
--- a/scripts/system/edit.js
+++ b/scripts/system/edit.js
@@ -1,7 +1,6 @@
"use strict";
-// newEditEntities.js
-// examples
+// edit.js
//
// Created by Brad Hefta-Gaub on 10/2/14.
// Persist toolbar by HRS 6/11/15.
@@ -13,6 +12,8 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
+/* global Script, SelectionDisplay, LightOverlayManager, CameraManager, Grid, GridTool, EntityListTool, Vec3, SelectionManager, Overlays, OverlayWebWindow, UserActivityLogger, Settings, Entities, Tablet, Toolbars, Messages, Menu, Camera, progressDialog, tooltip, MyAvatar, Quat, Controller, Clipboard, HMD, UndoStack, ParticleExplorerTool */
+
(function() { // BEGIN LOCAL_SCOPE
var HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/";
@@ -111,18 +112,13 @@ selectionManager.addEventListener(function () {
const KEY_P = 80; //Key code for letter p used for Parenting hotkey.
var DEGREES_TO_RADIANS = Math.PI / 180.0;
var RADIANS_TO_DEGREES = 180.0 / Math.PI;
-var epsilon = 0.001;
var MIN_ANGULAR_SIZE = 2;
var MAX_ANGULAR_SIZE = 45;
var allowLargeModels = true;
var allowSmallModels = true;
-var SPAWN_DISTANCE = 1;
var DEFAULT_DIMENSION = 0.20;
-var DEFAULT_TEXT_DIMENSION_X = 1.0;
-var DEFAULT_TEXT_DIMENSION_Y = 1.0;
-var DEFAULT_TEXT_DIMENSION_Z = 0.01;
var DEFAULT_DIMENSIONS = {
x: DEFAULT_DIMENSION,
@@ -137,7 +133,6 @@ var MENU_EASE_ON_FOCUS = "Ease Orientation on Focus";
var MENU_SHOW_LIGHTS_AND_PARTICLES_IN_EDIT_MODE = "Show Lights and Particle Systems in Edit Mode";
var MENU_SHOW_ZONES_IN_EDIT_MODE = "Show Zones in Edit Mode";
-var SETTING_INSPECT_TOOL_ENABLED = "inspectToolEnabled";
var SETTING_AUTO_FOCUS_ON_SELECT = "autoFocusOnSelect";
var SETTING_EASE_ON_FOCUS = "cameraEaseOnFocus";
var SETTING_SHOW_LIGHTS_AND_PARTICLES_IN_EDIT_MODE = "showLightsAndParticlesInEditMode";
@@ -209,13 +204,13 @@ function hideMarketplace() {
marketplaceWindow.setURL("about:blank");
}
-function toggleMarketplace() {
- if (marketplaceWindow.visible) {
- hideMarketplace();
- } else {
- showMarketplace();
- }
-}
+// function toggleMarketplace() {
+// if (marketplaceWindow.visible) {
+// hideMarketplace();
+// } else {
+// showMarketplace();
+// }
+// }
var TOOLS_PATH = Script.resolvePath("assets/images/tools/");
@@ -228,8 +223,6 @@ var toolBar = (function () {
tablet = null;
function createNewEntity(properties) {
- Settings.setValue(EDIT_SETTING, false);
-
var dimensions = properties.dimensions ? properties.dimensions : DEFAULT_DIMENSIONS;
var position = getPositionToCreateEntity();
var entityID = null;
@@ -237,8 +230,12 @@ var toolBar = (function () {
position = grid.snapToSurface(grid.snapToGrid(position, false, dimensions), dimensions),
properties.position = position;
entityID = Entities.addEntity(properties);
+ if (properties.type == "ParticleEffect") {
+ selectParticleEntity(entityID);
+ }
} else {
- Window.notifyEditError("Can't create " + properties.type + ": " + properties.type + " would be out of bounds.");
+ Window.notifyEditError("Can't create " + properties.type + ": " +
+ properties.type + " would be out of bounds.");
}
selectionManager.clearSelections();
@@ -258,24 +255,63 @@ var toolBar = (function () {
}
}
+ var buttonHandlers = {}; // only used to tablet mode
+
function addButton(name, image, handler) {
- var imageUrl = TOOLS_PATH + image;
- var button = toolBar.addButton({
- objectName: name,
- imageURL: imageUrl,
- imageOffOut: 1,
- imageOffIn: 2,
- imageOnOut: 0,
- imageOnIn: 2,
- alpha: 0.9,
- visible: true
- });
- if (handler) {
- button.clicked.connect(function () {
- Script.setTimeout(handler, 100);
- });
+ 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 DYNAMIC_DEFAULT = false;
+
+ function handleNewModelDialogResult(result) {
+ if (result) {
+ var url = result.textInput;
+ var shapeType;
+ switch (result.comboBox) {
+ 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;
+ default:
+ shapeType = "none";
+ }
+
+ var dynamic = result.checkBox !== null ? result.checkBox : 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,
+ dynamic: dynamic,
+ gravity: dynamic ? { x: 0, y: -10, z: 0 } : { x: 0, y: 0, z: 0 }
+ });
+ }
+ }
+ }
+
+ 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);
+ break;
+ case "newEntityButtonClicked":
+ buttonHandlers[message.params.buttonName]();
+ break;
}
- return button;
}
function initialize() {
@@ -292,101 +328,54 @@ var toolBar = (function () {
}
});
-
- if (Settings.getValue("HUDUIEnabled")) {
- systemToolbar = Toolbars.getToolbar(SYSTEM_TOOLBAR);
- activeButton = systemToolbar.addButton({
- objectName: EDIT_TOGGLE_BUTTON,
- imageURL: TOOLS_PATH + "edit.svg",
- visible: true,
- alpha: 0.9,
- defaultState: 1
- });
- } else {
- tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
- activeButton = tablet.addButton({
- icon: "icons/tablet-icons/edit-i.svg",
- activeIcon: "icons/tablet-icons/edit-a.svg",
- text: "EDIT",
- sortOrder: 10
- });
- }
+ tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
+ activeButton = tablet.addButton({
+ icon: "icons/tablet-icons/edit-i.svg",
+ activeIcon: "icons/tablet-icons/edit-a.svg",
+ text: "EDIT",
+ sortOrder: 10
+ });
+ tablet.screenChanged.connect(function (type, url) {
+ if (isActive && (type !== "QML" || url !== "Edit.qml")) {
+ that.toggle();
+ }
+ });
+ tablet.fromQml.connect(fromQml);
activeButton.clicked.connect(function() {
that.toggle();
});
- toolBar = Toolbars.getToolbar(EDIT_TOOLBAR);
- toolBar.writeProperty("shown", false);
- addButton("openAssetBrowserButton","assets-01.svg",function(){
+ addButton("importEntitiesButton", "assets-01.svg", function() {
+ var importURL = null;
+ var fullPath = Window.browse("Select Model to Import", "", "*.json");
+ if (fullPath) {
+ importURL = "file:///" + fullPath;
+ }
+ if (importURL) {
+ if (!isActive && (Entities.canRez() && Entities.canRezTmp())) {
+ toolBar.toggle();
+ }
+ importSVO(importURL);
+ }
+ });
+
+ addButton("openAssetBrowserButton", "assets-01.svg", function() {
Window.showAssetServer();
- })
+ });
addButton("newModelButton", "model-01.svg", function () {
- 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_TYPES = [];
SHAPE_TYPES[SHAPE_TYPE_NONE] = "No Collision";
SHAPE_TYPES[SHAPE_TYPE_SIMPLE_HULL] = "Basic - Whole model";
SHAPE_TYPES[SHAPE_TYPE_SIMPLE_COMPOUND] = "Good - Sub-meshes";
SHAPE_TYPES[SHAPE_TYPE_STATIC_MESH] = "Exact - All polygons";
-
var SHAPE_TYPE_DEFAULT = SHAPE_TYPE_STATIC_MESH;
- var DYNAMIC_DEFAULT = false;
- var result = Window.customPrompt({
- textInput: {
- label: "Model URL"
- },
- comboBox: {
- label: "Automatic Collisions",
- index: SHAPE_TYPE_DEFAULT,
- items: SHAPE_TYPES
- },
- checkBox: {
- label: "Dynamic",
- checked: DYNAMIC_DEFAULT,
- disableForItems: [
- SHAPE_TYPE_STATIC_MESH
- ],
- checkStateOnDisable: false,
- warningOnDisable: "Models with automatic collisions set to 'Exact' cannot be dynamic"
- }
- });
- if (result) {
- var url = result.textInput;
- var shapeType;
- switch (result.comboBox) {
- 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;
- default:
- shapeType = "none";
- }
-
- var dynamic = result.checkBox !== null ? result.checkBox : 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,
- dynamic: dynamic,
- gravity: dynamic ? { x: 0, y: -10, z: 0 } : { x: 0, y: 0, z: 0 }
- });
- }
- }
+ // tablet version of new-model dialog
+ var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
+ tablet.pushOntoStack("NewModelDialog.qml");
});
addButton("newCubeButton", "cube-01.svg", function () {
@@ -508,10 +497,12 @@ var toolBar = (function () {
entityListTool.clearEntityList();
};
-
that.toggle = function () {
that.setActive(!isActive);
activeButton.editProperties({isActive: isActive});
+ if (!isActive) {
+ tablet.gotoHomeScreen();
+ }
};
that.setActive = function (active) {
@@ -541,6 +532,8 @@ var toolBar = (function () {
cameraManager.disable();
selectionDisplay.triggerMapping.disable();
} else {
+ var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
+ tablet.loadQMLSource("Edit.qml");
UserActivityLogger.enabledEdit();
entityListTool.setVisible(true);
gridTool.setVisible(true);
@@ -551,13 +544,6 @@ var toolBar = (function () {
// everybody else to think that Interface has lost focus overall. fogbugzid:558
// Window.setFocus();
}
- // Sets visibility of tool buttons, excluding the power button
- toolBar.writeProperty("shown", active);
- var visible = toolBar.readProperty("visible");
- if (active && !visible) {
- toolBar.writeProperty("shown", false);
- toolBar.writeProperty("shown", true);
- }
entityIconOverlayManager.setVisible(isActive && Menu.isOptionChecked(MENU_SHOW_LIGHTS_AND_PARTICLES_IN_EDIT_MODE));
Entities.setDrawZoneBoundaries(isActive && Menu.isOptionChecked(MENU_SHOW_ZONES_IN_EDIT_MODE));
};
@@ -688,7 +674,6 @@ var idleMouseTimerId = null;
var CLICK_TIME_THRESHOLD = 500 * 1000; // 500 ms
var CLICK_MOVE_DISTANCE_THRESHOLD = 20;
var IDLE_MOUSE_TIMEOUT = 200;
-var DEFAULT_ENTITY_DRAG_DROP_DISTANCE = 2.0;
var lastMouseMoveEvent = null;
@@ -762,11 +747,22 @@ function mouseReleaseEvent(event) {
}
}
+function wasTabletClicked(event) {
+ var rayPick = Camera.computePickRay(event.x, event.y);
+ var result = Overlays.findRayIntersection(rayPick, true, [HMD.tabletID, HMD.tabletScreenID, HMD.homeButtonID]);
+ return result.intersects;
+}
+
function mouseClickEvent(event) {
var wantDebug = false;
- var result, properties;
+ var result, properties, tabletClicked;
if (isActive && event.isLeftButton) {
result = findClickedEntity(event);
+ tabletClicked = wasTabletClicked(event);
+ if (tabletClicked) {
+ return;
+ }
+
if (result === null || result === undefined) {
if (!event.isShifted) {
selectionManager.clearSelections();
@@ -818,6 +814,12 @@ function mouseClickEvent(event) {
orientation = MyAvatar.orientation;
intersection = rayPlaneIntersection(pickRay, P, Quat.getForward(orientation));
+ if (event.isShifted) {
+ particleExplorerTool.destroyWebView();
+ }
+ if (properties.type !== "ParticleEffect") {
+ particleExplorerTool.destroyWebView();
+ }
if (!event.isShifted) {
selectionManager.setSelections([foundEntity]);
@@ -1343,11 +1345,11 @@ function getPositionToCreateEntity() {
var position = Vec3.sum(MyAvatar.position, Vec3.multiply(direction, distance));
if (Camera.mode === "entity" || Camera.mode === "independent") {
- position = Vec3.sum(Camera.position, Vec3.multiply(Quat.getForward(Camera.orientation), distance))
+ position = Vec3.sum(Camera.position, Vec3.multiply(Quat.getForward(Camera.orientation), distance));
}
position.y += 0.5;
if (position.x > HALF_TREE_SCALE || position.y > HALF_TREE_SCALE || position.z > HALF_TREE_SCALE) {
- return null
+ return null;
}
return position;
}
@@ -1361,11 +1363,11 @@ function getPositionToImportEntity() {
var position = Vec3.sum(MyAvatar.position, Vec3.multiply(direction, longest));
if (Camera.mode === "entity" || Camera.mode === "independent") {
- position = Vec3.sum(Camera.position, Vec3.multiply(Quat.getForward(Camera.orientation), longest))
+ position = Vec3.sum(Camera.position, Vec3.multiply(Quat.getForward(Camera.orientation), longest));
}
if (position.x > HALF_TREE_SCALE || position.y > HALF_TREE_SCALE || position.z > HALF_TREE_SCALE) {
- return null
+ return null;
}
return position;
@@ -1573,11 +1575,11 @@ var ServerScriptStatusMonitor = function(entityID, statusCallback) {
Entities.getServerScriptStatus(entityID, onStatusReceived);
}
}, 1000);
- };
+ }
};
self.stop = function() {
self.active = false;
- }
+ };
Entities.getServerScriptStatus(entityID, onStatusReceived);
};
@@ -1585,11 +1587,9 @@ var ServerScriptStatusMonitor = function(entityID, statusCallback) {
var PropertiesTool = function (opts) {
var that = {};
- var webView = new OverlayWebWindow({
- title: 'Entity Properties',
- source: ENTITY_PROPERTIES_URL,
- toolWindow: true
- });
+ var webView = null;
+ webView = Tablet.getTablet("com.highfidelity.interface.tablet.system");
+ webView.setVisible = function(value) {};
var visible = false;
@@ -1608,7 +1608,7 @@ var PropertiesTool = function (opts) {
function updateScriptStatus(info) {
info.type = "server_script_status";
webView.emitScriptEvent(JSON.stringify(info));
- };
+ }
function resetScriptStatus() {
updateScriptStatus({
@@ -1619,7 +1619,7 @@ var PropertiesTool = function (opts) {
});
}
- selectionManager.addEventListener(function (selectionUpdated) {
+ function updateSelections(selectionUpdated) {
var data = {
type: 'update'
};
@@ -1660,14 +1660,15 @@ var PropertiesTool = function (opts) {
}
data.selections = selections;
webView.emitScriptEvent(JSON.stringify(data));
- });
+ }
+ selectionManager.addEventListener(updateSelections);
webView.webEventReceived.connect(function (data) {
try {
data = JSON.parse(data);
}
catch(e) {
- print('Edit.js received web event that was not valid json.')
+ print('Edit.js received web event that was not valid json.');
return;
}
var i, properties, dY, diff, newPosition;
@@ -1685,15 +1686,15 @@ var PropertiesTool = function (opts) {
for (i = 0; i < selectionManager.selections.length; i++) {
Entities.editEntity(selectionManager.selections[i], properties);
}
- } else {
+ } else if (data.properties) {
if (data.properties.dynamic === false) {
// this object is leaving dynamic, so we zero its velocities
- data.properties["velocity"] = {
+ data.properties.velocity = {
x: 0,
y: 0,
z: 0
};
- data.properties["angularVelocity"] = {
+ data.properties.angularVelocity = {
x: 0,
y: 0,
z: 0
@@ -1822,6 +1823,8 @@ var PropertiesTool = function (opts) {
}
}
}
+ } else if (data.type === "propertiesPageReady") {
+ updateSelections(true);
}
});
@@ -2005,13 +2008,45 @@ var showMenuItem = propertyMenu.addMenuItem("Show in Marketplace");
var propertiesTool = new PropertiesTool();
var particleExplorerTool = new ParticleExplorerTool();
+var selectedParticleEntity = 0;
var selectedParticleEntityID = null;
+
+
+function selectParticleEntity(entityID) {
+ var properties = Entities.getEntityProperties(entityID);
+ var particleData = {
+ messageType: "particle_settings",
+ currentProperties: properties
+ };
+ particleExplorerTool.destroyWebView();
+ particleExplorerTool.createWebView();
+
+ selectedParticleEntity = entityID;
+ particleExplorerTool.setActiveParticleEntity(entityID);
+ particleExplorerTool.webView.emitScriptEvent(JSON.stringify(particleData));
+}
+
entityListTool.webView.webEventReceived.connect(function (data) {
data = JSON.parse(data);
if (data.type === 'parent') {
parentSelectedEntities();
} else if(data.type === 'unparent') {
unparentSelectedEntities();
+ } else if (data.type === "selectionUpdate") {
+ var ids = data.entityIds;
+ if (ids.length === 1) {
+ if (Entities.getEntityProperties(ids[0], "type").type === "ParticleEffect") {
+ if (JSON.stringify(selectedParticleEntity) === JSON.stringify(ids[0])) {
+ // This particle entity is already selected, so return
+ return;
+ }
+ // Destroy the old particles web view first
+ selectParticleEntity(ids[0]);
+ } else {
+ selectedParticleEntity = 0;
+ particleExplorerTool.destroyWebView();
+ }
+ }
}
});
diff --git a/scripts/system/fingerPaint.js b/scripts/system/fingerPaint.js
index 959f594212..27206ef9fa 100644
--- a/scripts/system/fingerPaint.js
+++ b/scripts/system/fingerPaint.js
@@ -13,6 +13,7 @@
button,
BUTTON_NAME = "PAINT",
isFingerPainting = false,
+ shouldPointFingers = false,
leftHand = null,
rightHand = null,
leftBrush = null,
@@ -308,9 +309,14 @@
Messages.sendMessage(HIFI_POINTER_DISABLE_MESSAGE_CHANNEL, JSON.stringify({
pointerEnabled: enabled
}), true);
- Messages.sendMessage(HIFI_POINT_INDEX_MESSAGE_CHANNEL, JSON.stringify({
- pointIndex: !enabled
- }), true);
+
+ var newShouldPointFingers = !enabled;
+ if (newShouldPointFingers !== shouldPointFingers) {
+ Messages.sendMessage(HIFI_POINT_INDEX_MESSAGE_CHANNEL, JSON.stringify({
+ pointIndex: newShouldPointFingers
+ }), true);
+ shouldPointFingers = newShouldPointFingers;
+ }
}
function enableProcessing() {
@@ -430,4 +436,4 @@
setUp();
Script.scriptEnding.connect(tearDown);
-}());
\ No newline at end of file
+}());
diff --git a/scripts/system/generalSettings.js b/scripts/system/generalSettings.js
index 0a9fc823ae..7d97f13757 100644
--- a/scripts/system/generalSettings.js
+++ b/scripts/system/generalSettings.js
@@ -18,7 +18,7 @@
var buttonName = "Settings";
var toolBar = null;
var tablet = null;
- var settings = "TabletGeneralSettings.qml"
+ var settings = "TabletGeneralPreferences.qml"
function onClicked(){
if (tablet) {
tablet.loadQMLSource(settings);
diff --git a/scripts/system/help.js b/scripts/system/help.js
index 3923b922fc..a335b2ef9c 100644
--- a/scripts/system/help.js
+++ b/scripts/system/help.js
@@ -13,8 +13,10 @@
/* globals Tablet, Script, HMD, Controller, Menu */
(function() { // BEGIN LOCAL_SCOPE
-
+
+ var HOME_BUTTON_TEXTURE = Script.resourcesPath() + "meshes/tablet-with-home-button.fbx/tablet-with-home-button.fbm/button-root.png";
var buttonName = "HELP";
+ var onHelpScreen = false;
var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
var button = tablet.addButton({
icon: "icons/tablet-icons/help-i.svg",
@@ -25,18 +27,24 @@
var enabled = false;
function onClicked() {
- if (enabled) {
- Menu.closeInfoView('InfoView_html/help.html');
- enabled = !enabled;
- button.editProperties({isActive: enabled});
+ if (onHelpScreen) {
+ tablet.gotoHomeScreen();
} else {
+ var tabletEntity = HMD.tabletID;
+ if (tabletEntity) {
+ Entities.editEntity(tabletEntity, {textures: JSON.stringify({"tex.close" : HOME_BUTTON_TEXTURE})});
+ }
Menu.triggerOption('Help...');
- enabled = !enabled;
- button.editProperties({isActive: enabled});
+ onHelpScreen = true;
}
}
+ function onScreenChanged(type, url) {
+ onHelpScreen = false;
+ }
+
button.clicked.connect(onClicked);
+ tablet.screenChanged.connect(onScreenChanged);
var POLL_RATE = 500;
var interval = Script.setInterval(function () {
@@ -48,8 +56,8 @@
}, POLL_RATE);
Script.scriptEnding.connect(function () {
- if (enabled) {
- Menu.closeInfoView('InfoView_html/help.html');
+ if (onHelpScreen) {
+ tablet.gotoHomeScreen();
}
button.clicked.disconnect(onClicked);
Script.clearInterval(interval);
diff --git a/scripts/system/html/SnapshotReview.html b/scripts/system/html/SnapshotReview.html
index d37afb180c..145cfb16a9 100644
--- a/scripts/system/html/SnapshotReview.html
+++ b/scripts/system/html/SnapshotReview.html
@@ -3,45 +3,43 @@