From 7564b6f0f5690a223ccb0a8fd6bb6d3125ea1de0 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Tue, 21 Feb 2017 10:59:36 -0800 Subject: [PATCH 1/4] More consistent highlights/toggle for toolbar buttons When the "app" for a button is visible the button should become active. Also clicking on a highlighted/active button should close the associated "app". This should be noticeable on the following tablet apps. * audio * menu * people * market * users --- scripts/system/audio.js | 48 ++++++++++++++++--- scripts/system/marketplaces/marketplaces.js | 35 ++++++++++---- scripts/system/menu.js | 28 +++++++++-- scripts/system/pal.js | 52 +++++++++++++-------- scripts/system/tablet-goto.js | 27 +++++++++-- scripts/system/tablet-users.js | 31 +++++++++--- 6 files changed, 170 insertions(+), 51 deletions(-) diff --git a/scripts/system/audio.js b/scripts/system/audio.js index c0fdb43b40..6e7e95d659 100644 --- a/scripts/system/audio.js +++ b/scripts/system/audio.js @@ -16,19 +16,51 @@ var TABLET_BUTTON_NAME = "AUDIO"; var HOME_BUTTON_TEXTURE = "http://hifi-content.s3.amazonaws.com/alan/dev/tablet-with-home-button.fbx/tablet-with-home-button.fbm/button-root.png"; +var MUTE_ICONS = { + icon: "icons/tablet-icons/mic-mute-i.svg", + activeIcon: "icons/tablet-icons/mic-mute-a.svg" +}; + +var UNMUTE_ICONS = { + icon: "icons/tablet-icons/mic-unmute-i.svg", + activeIcon: "icons/tablet-icons/mic-unmute-a.svg" +}; + function onMuteToggled() { - button.editProperties({ isActive: AudioDevice.getMuted() }); + if (AudioDevice.getMuted()) { + button.editProperties(MUTE_ICONS); + } else { + button.editProperties(UNMUTE_ICONS); + } } -function onClicked(){ - var entity = HMD.tabletID; - Entities.editEntity(entity, { textures: JSON.stringify({ "tex.close": HOME_BUTTON_TEXTURE }) }); - tablet.gotoMenuScreen("Audio"); + +var shouldActivateButton = false; +var onAudioScreen = false; + +function onClicked() { + if (onAudioScreen) { + // for toolbar-mode: go back to home screen, this will close the window. + tablet.gotoHomeScreen(); + } else { + var entity = HMD.tabletID; + Entities.editEntity(entity, { textures: JSON.stringify({ "tex.close": HOME_BUTTON_TEXTURE }) }); + shouldActivateButton = true; + tablet.gotoMenuScreen("Audio"); + onAudioScreen = true; + } +} + +function onScreenChanged(type, url) { + // for toolbar mode: change button to active when window is first openend, false otherwise. + button.editProperties({isActive: shouldActivateButton}); + shouldActivateButton = false; + onAudioScreen = false; } var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); var button = tablet.addButton({ - icon: "icons/tablet-icons/mic-unmute-i.svg", - activeIcon: "icons/tablet-icons/mic-mute-a.svg", + icon: AudioDevice.getMuted() ? MUTE_ICONS.icon : UNMUTE_ICONS.icon, + activeIcon: AudioDevice.getMuted() ? MUTE_ICONS.activeIcon : UNMUTE_ICONS.activeIcon, text: TABLET_BUTTON_NAME, sortOrder: 1 }); @@ -36,10 +68,12 @@ var button = tablet.addButton({ onMuteToggled(); button.clicked.connect(onClicked); +tablet.screenChanged.connect(onScreenChanged); AudioDevice.muteToggled.connect(onMuteToggled); Script.scriptEnding.connect(function () { button.clicked.disconnect(onClicked); + tablet.screenChanged.disconnect(onScreenChanged); AudioDevice.muteToggled.disconnect(onMuteToggled); tablet.removeButton(button); }); diff --git a/scripts/system/marketplaces/marketplaces.js b/scripts/system/marketplaces/marketplaces.js index c5ce5a634b..68da7696be 100644 --- a/scripts/system/marketplaces/marketplaces.js +++ b/scripts/system/marketplaces/marketplaces.js @@ -52,10 +52,16 @@ function onMessageBoxClosed(id, button) { Window.messageBoxClosed.connect(onMessageBoxClosed); +var shouldActivateButton = false; +var onMarketplaceScreen = false; + function showMarketplace() { UserActivityLogger.openedMarketplace(); + shouldActivateButton = true; tablet.gotoWebScreen(MARKETPLACE_URL_INITIAL, MARKETPLACES_INJECT_SCRIPT_URL); + onMarketplaceScreen = true; + tablet.webEventReceived.connect(function (message) { if (message === GOTO_DIRECTORY) { @@ -98,15 +104,10 @@ function showMarketplace() { }); } -function toggleMarketplace() { - var entity = HMD.tabletID; - Entities.editEntity(entity, {textures: JSON.stringify({"tex.close": HOME_BUTTON_TEXTURE})}); - showMarketplace(); -} - var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); var marketplaceButton = tablet.addButton({ icon: "icons/tablet-icons/market-i.svg", + activeIcon: "icons/tablet-icons/market-a.svg", text: "MARKET", sortOrder: 9 }); @@ -117,16 +118,30 @@ function onCanWriteAssetsChanged() { } function onClick() { - toggleMarketplace(); + if (onMarketplaceScreen) { + // for toolbar-mode: go back to home screen, this will close the window. + tablet.gotoHomeScreen(); + } else { + var entity = HMD.tabletID; + Entities.editEntity(entity, {textures: JSON.stringify({"tex.close": HOME_BUTTON_TEXTURE})}); + showMarketplace(); + } +} + +function onScreenChanged(type, url) { + // for toolbar mode: change button to active when window is first openend, false otherwise. + marketplaceButton.editProperties({isActive: shouldActivateButton}); + shouldActivateButton = false; + onMarketplaceScreen = false; } marketplaceButton.clicked.connect(onClick); +tablet.screenChanged.connect(onScreenChanged); Entities.canWriteAssetsChanged.connect(onCanWriteAssetsChanged); Script.scriptEnding.connect(function () { - if (tablet) { - tablet.removeButton(marketplaceButton); - } + tablet.removeButton(marketplaceButton); + tablet.screenChanged.disconnect(onScreenChanged); Entities.canWriteAssetsChanged.disconnect(onCanWriteAssetsChanged); }); diff --git a/scripts/system/menu.js b/scripts/system/menu.js index 13c6ce1e0d..1d5f8bccd6 100644 --- a/scripts/system/menu.js +++ b/scripts/system/menu.js @@ -10,26 +10,46 @@ // var HOME_BUTTON_TEXTURE = "http://hifi-content.s3.amazonaws.com/alan/dev/tablet-with-home-button.fbx/tablet-with-home-button.fbm/button-root.png"; -//var HOME_BUTTON_TEXTURE = Script.resourcesPath() + "meshes/tablet-with-home-button.fbx/tablet-with-home-button.fbm/button-root.png"; +// var HOME_BUTTON_TEXTURE = Script.resourcesPath() + "meshes/tablet-with-home-button.fbx/tablet-with-home-button.fbm/button-root.png"; (function() { var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); var button = tablet.addButton({ icon: "icons/tablet-icons/menu-i.svg", + activeIcon: "icons/tablet-icons/menu-a.svg", text: "MENU", sortOrder: 3 }); + var shouldActivateButton = false; + var onMenuScreen = false; + function onClicked() { - var entity = HMD.tabletID; - Entities.editEntity(entity, {textures: JSON.stringify({"tex.close": HOME_BUTTON_TEXTURE})}); - tablet.gotoMenuScreen(); + if (onMenuScreen) { + // for toolbar-mode: go back to home screen, this will close the window. + tablet.gotoHomeScreen(); + } else { + var entity = HMD.tabletID; + Entities.editEntity(entity, {textures: JSON.stringify({"tex.close": HOME_BUTTON_TEXTURE})}); + shouldActivateButton = true; + tablet.gotoMenuScreen(); + onMenuScreen = true; + } + } + + function onScreenChanged(type, url) { + // for toolbar mode: change button to active when window is first openend, false otherwise. + button.editProperties({isActive: shouldActivateButton}); + shouldActivateButton = false; + onMenuScreen = false; } button.clicked.connect(onClicked); + tablet.screenChanged.connect(onScreenChanged); Script.scriptEnding.connect(function () { button.clicked.disconnect(onClicked); tablet.removeButton(button); + tablet.screenChanged.disconnect(onScreenChanged); }); }()); diff --git a/scripts/system/pal.js b/scripts/system/pal.js index d47544e0f0..36ecc1f084 100644 --- a/scripts/system/pal.js +++ b/scripts/system/pal.js @@ -477,23 +477,17 @@ var button; var buttonName = "PEOPLE"; var tablet = null; -function onTabletScreenChanged(type, url) { - if (type !== "QML" || url !== "../Pal.qml") { - off(); - } -} - function startup() { tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); button = tablet.addButton({ text: buttonName, icon: "icons/tablet-icons/people-i.svg", + activeIcon: "icons/tablet-icons/people-a.svg", sortOrder: 7 }); tablet.fromQml.connect(fromQml); button.clicked.connect(onTabletButtonClicked); tablet.screenChanged.connect(onTabletScreenChanged); - Users.usernameFromIDReply.connect(usernameFromIDReply); Window.domainChanged.connect(clearLocalQMLDataAndClosePAL); Window.domainConnectionRefused.connect(clearLocalQMLDataAndClosePAL); @@ -524,17 +518,39 @@ function off() { Users.requestsDomainListData = false; } +var onPalScreen = false; +var shouldActivateButton = false; + function onTabletButtonClicked() { - tablet.loadQMLSource("../Pal.qml"); - Users.requestsDomainListData = true; - populateUserList(); - isWired = true; - Script.update.connect(updateOverlays); - Controller.mousePressEvent.connect(handleMouseEvent); - Controller.mouseMoveEvent.connect(handleMouseMoveEvent); - triggerMapping.enable(); - triggerPressMapping.enable(); - audioTimer = createAudioInterval(conserveResources ? AUDIO_LEVEL_CONSERVED_UPDATE_INTERVAL_MS : AUDIO_LEVEL_UPDATE_INTERVAL_MS); + if (onPalScreen) { + // for toolbar-mode: go back to home screen, this will close the window. + tablet.gotoHomeScreen(); + } else { + shouldActivateButton = true; + tablet.loadQMLSource("../Pal.qml"); + onPalScreen = true; + Users.requestsDomainListData = true; + populateUserList(); + isWired = true; + Script.update.connect(updateOverlays); + Controller.mousePressEvent.connect(handleMouseEvent); + Controller.mouseMoveEvent.connect(handleMouseMoveEvent); + triggerMapping.enable(); + triggerPressMapping.enable(); + audioTimer = createAudioInterval(conserveResources ? AUDIO_LEVEL_CONSERVED_UPDATE_INTERVAL_MS : AUDIO_LEVEL_UPDATE_INTERVAL_MS); + } +} + +function onTabletScreenChanged(type, url) { + // for toolbar mode: change button to active when window is first openend, false otherwise. + button.editProperties({isActive: shouldActivateButton}); + shouldActivateButton = false; + onPalScreen = false; + + // disable sphere overlays when not on pal screen. + if (type !== "QML" || url !== "../Pal.qml") { + off(); + } } // @@ -621,14 +637,12 @@ function shutdown() { button.clicked.disconnect(onTabletButtonClicked); tablet.removeButton(button); tablet.screenChanged.disconnect(onTabletScreenChanged); - Users.usernameFromIDReply.disconnect(usernameFromIDReply); Window.domainChanged.disconnect(clearLocalQMLDataAndClosePAL); Window.domainConnectionRefused.disconnect(clearLocalQMLDataAndClosePAL); Messages.subscribe(CHANNEL); Messages.messageReceived.disconnect(receiveMessage); Users.avatarDisconnected.disconnect(avatarDisconnected); - off(); } diff --git a/scripts/system/tablet-goto.js b/scripts/system/tablet-goto.js index 6c3e12cd9b..eb95d9d8a3 100644 --- a/scripts/system/tablet-goto.js +++ b/scripts/system/tablet-goto.js @@ -14,10 +14,27 @@ (function() { // BEGIN LOCAL_SCOPE var gotoQmlSource = "TabletAddressDialog.qml"; var buttonName = "GOTO"; + var onGotoScreen = false; + var shouldActivateButton = false; - function onClicked(){ - tablet.loadQMLSource(gotoQmlSource); + function onClicked() { + if (onGotoScreen) { + // for toolbar-mode: go back to home screen, this will close the window. + tablet.gotoHomeScreen(); + } else { + shouldActivateButton = true; + tablet.loadQMLSource(gotoQmlSource); + onGotoScreen = true; + } } + + function onScreenChanged(type, url) { + // for toolbar mode: change button to active when window is first openend, false otherwise. + button.editProperties({isActive: shouldActivateButton}); + shouldActivateButton = false; + onGotoScreen = false; + } + var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); var button = tablet.addButton({ icon: "icons/tablet-icons/goto-i.svg", @@ -27,12 +44,12 @@ }); button.clicked.connect(onClicked); + tablet.screenChanged.connect(onScreenChanged); Script.scriptEnding.connect(function () { button.clicked.disconnect(onClicked); - if (tablet) { - tablet.removeButton(button); - } + tablet.removeButton(button); + tablet.screenChanged.disconnect(onScreenChanged); }); }()); // END LOCAL_SCOPE diff --git a/scripts/system/tablet-users.js b/scripts/system/tablet-users.js index ce50c4686d..8e89ac74b7 100644 --- a/scripts/system/tablet-users.js +++ b/scripts/system/tablet-users.js @@ -1,7 +1,7 @@ "use strict"; // -// users.js +// tablet-users.js // // Created by Faye Li on 18 Jan 2017. // Copyright 2017 High Fidelity, Inc. @@ -36,16 +36,34 @@ var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); var button = tablet.addButton({ icon: "icons/tablet-icons/users-i.svg", + activeIcon: "icons/tablet-icons/users-a.svg", text: "USERS", sortOrder: 11 }); + var onUsersScreen = false; + var shouldActivateButton = false; + function onClicked() { - var tabletEntity = HMD.tabletID; - if (tabletEntity) { - Entities.editEntity(tabletEntity, {textures: JSON.stringify({"tex.close" : HOME_BUTTON_TEXTURE})}); + if (onUsersScreen) { + // for toolbar-mode: go back to home screen, this will close the window. + tablet.gotoHomeScreen(); + } else { + var tabletEntity = HMD.tabletID; + if (tabletEntity) { + Entities.editEntity(tabletEntity, {textures: JSON.stringify({"tex.close" : HOME_BUTTON_TEXTURE})}); + } + shouldActivateButton = true; + tablet.gotoWebScreen(USERS_URL); + onUsersScreen = true; } - tablet.gotoWebScreen(USERS_URL); + } + + function onScreenChanged() { + // for toolbar mode: change button to active when window is first openend, false otherwise. + button.editProperties({isActive: shouldActivateButton}); + shouldActivateButton = false; + onUsersScreen = false; } function onWebEventReceived(event) { @@ -88,12 +106,13 @@ // update your visibility (all, friends, or none) myVisibility = event.data.visibility; GlobalServices.findableBy = myVisibility; - } + } } } button.clicked.connect(onClicked); tablet.webEventReceived.connect(onWebEventReceived); + tablet.screenChanged.connect(onScreenChanged); function cleanup() { button.clicked.disconnect(onClicked); From 4866be1f522eb56c93fbbcb705da6a864097f588 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Tue, 21 Feb 2017 16:01:46 -0800 Subject: [PATCH 2/4] More consistent tablet angle when first creating the tablet. The tablet should more constantly be placed above your hand, while facing your head. It fixes the issue where the tablet would appear almost horizontal when your hand was close to your HMD and at eye level. --- scripts/system/libraries/WebTablet.js | 28 ++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/scripts/system/libraries/WebTablet.js b/scripts/system/libraries/WebTablet.js index 74bbd788be..618b70ff20 100644 --- a/scripts/system/libraries/WebTablet.js +++ b/scripts/system/libraries/WebTablet.js @@ -49,24 +49,30 @@ function calcSpawnInfo(hand, height) { var handController = getControllerWorldLocation(hand, true); var controllerPosition = handController.position; - // compute the angle of the chord with length (height / 2) - var theta = Math.asin(height / (2 * Vec3.distance(headPos, controllerPosition))); + // base of the tablet is slightly above controller position + var TABLET_BASE_DISPLACEMENT = {x: 0, y: 0.1, z: 0}; + var tabletBase = Vec3.sum(controllerPosition, TABLET_BASE_DISPLACEMENT); - // then we can use this angle to rotate the vector between the HMD position and the center of the tablet. - // this vector, u, will become our new look at direction. - var d = Vec3.normalize(Vec3.subtract(headPos, controllerPosition)); + var d = Vec3.subtract(headPos, tabletBase); + var theta = Math.acos(d.y / Vec3.length(d)); + d.y = 0; + if (Vec3.length(d) < 0.0001) { + d = {x: 1, y: 0, z: 0}; + } else { + d = Vec3.normalize(d); + } var w = Vec3.normalize(Vec3.cross(Y_AXIS, d)); - var q = Quat.angleAxis(theta * (180 / Math.PI), w); + var ANGLE_OFFSET = 25; + var q = Quat.angleAxis(theta * (180 / Math.PI) - (90 - ANGLE_OFFSET), w); var u = Vec3.multiplyQbyV(q, d); // use u to compute a full lookAt quaternion. - var lookAtRot = Quat.lookAt(controllerPosition, Vec3.sum(controllerPosition, u), Y_AXIS); - - // adjust the tablet position by a small amount. - var yDisplacement = (height / 2) + 0.1; + var lookAtRot = Quat.lookAt(tabletBase, Vec3.sum(tabletBase, u), Y_AXIS); + var yDisplacement = (height / 2); var zDisplacement = 0.05; var tabletOffset = Vec3.multiplyQbyV(lookAtRot, {x: 0, y: yDisplacement, z: zDisplacement}); - finalPosition = Vec3.sum(controllerPosition, tabletOffset); + finalPosition = Vec3.sum(tabletBase, tabletOffset); + return { position: finalPosition, rotation: lookAtRot From 71b569a697d6fec7c73df2114c515cd55d2d0235 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Wed, 22 Feb 2017 10:22:12 -0800 Subject: [PATCH 3/4] Bug-fix for crash on tablet when going from web -> home. --- libraries/script-engine/src/TabletScriptingInterface.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/script-engine/src/TabletScriptingInterface.cpp b/libraries/script-engine/src/TabletScriptingInterface.cpp index c78ce251c8..0d4934c35a 100644 --- a/libraries/script-engine/src/TabletScriptingInterface.cpp +++ b/libraries/script-engine/src/TabletScriptingInterface.cpp @@ -366,6 +366,7 @@ void TabletProxy::gotoWebScreen(const QString& url, const QString& injectedJavaS } if (root) { + removeButtonsFromHomeScreen(); QMetaObject::invokeMethod(root, "loadSource", Q_ARG(const QVariant&, QVariant(WEB_VIEW_SOURCE_URL))); QMetaObject::invokeMethod(root, "setShown", Q_ARG(const QVariant&, QVariant(true))); QMetaObject::invokeMethod(root, "loadWebUrl", Q_ARG(const QVariant&, QVariant(url)), Q_ARG(const QVariant&, QVariant(injectedJavaScriptUrl))); From aed1d693776047ba0f6fe001cd9700e7df8aed9d Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 22 Feb 2017 14:14:10 -0800 Subject: [PATCH 4/4] don't do a haptic pulse when av's hand goes near grabbable tablet --- scripts/system/controllers/handControllerGrab.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/scripts/system/controllers/handControllerGrab.js b/scripts/system/controllers/handControllerGrab.js index 95c05c2717..ea76490b7b 100644 --- a/scripts/system/controllers/handControllerGrab.js +++ b/scripts/system/controllers/handControllerGrab.js @@ -1233,7 +1233,13 @@ function MyController(hand) { }); if (grabbableEntities.length > 0) { if (!this.grabPointIntersectsEntity) { - Controller.triggerHapticPulse(1, 20, this.hand); + // don't do haptic pulse for tablet + var nonTabletEntities = grabbableEntities.filter(function(entityID) { + return entityID != HMD.tabletID && entityID != HMD.homeButtonID; + }); + if (nonTabletEntities.length > 0) { + Controller.triggerHapticPulse(1, 20, this.hand); + } this.grabPointIntersectsEntity = true; this.grabPointSphereOn(); }