mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-04-07 01:43:32 +02:00
342 lines
12 KiB
JavaScript
342 lines
12 KiB
JavaScript
"use strict";
|
|
|
|
//
|
|
// tabletUI.js
|
|
//
|
|
// scripts/system/tablet-ui/
|
|
//
|
|
// Created by Seth Alves 2016-9-29
|
|
// Copyright 2016 High Fidelity, Inc.
|
|
// Copyright 2023 Overte e.V.
|
|
//
|
|
// Distributed under the Apache License, Version 2.0.
|
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
|
//
|
|
|
|
/* global Script, HMD, WebTablet, UIWebTablet, UserActivityLogger, Settings, Entities, Messages, Tablet, Overlays,
|
|
MyAvatar, Menu, AvatarInputs, Vec3, cleanUpOldMaterialEntities */
|
|
|
|
(function() { // BEGIN LOCAL_SCOPE
|
|
var controllerStandard = Controller.Standard;
|
|
|
|
var tabletRezzed = false;
|
|
var activeHand = null;
|
|
var DEFAULT_WIDTH = 0.4375;
|
|
var DEFAULT_DESKTOP_TABLET_SCALE = 75;
|
|
var DEFAULT_HMD_TABLET_SCALE = 60;
|
|
var preMakeTime = Date.now();
|
|
var validCheckTime = Date.now();
|
|
var debugTablet = false;
|
|
var tabletScalePercentage = DEFAULT_HMD_TABLET_SCALE;
|
|
var UIWebTablet = null;
|
|
var MSECS_PER_SEC = 1000.0;
|
|
var MUTE_MICROPHONE_MENU_ITEM = "Mute Microphone";
|
|
var gTablet = null;
|
|
|
|
Script.include("../libraries/WebTablet.js");
|
|
|
|
function cleanupMaterialEntities() {
|
|
if (Window.isPhysicsEnabled()) {
|
|
cleanUpOldMaterialEntities();
|
|
return;
|
|
}
|
|
Script.setTimeout(cleanupMaterialEntities, 100);
|
|
}
|
|
|
|
function checkTablet() {
|
|
if (gTablet === null) {
|
|
gTablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
|
|
}
|
|
}
|
|
|
|
function tabletIsValid() {
|
|
if (!UIWebTablet) {
|
|
return false;
|
|
}
|
|
if (Entities.getEntityProperties(HMD.tabletID, ["type"]).type !== "Model") {
|
|
if (debugTablet) {
|
|
print("TABLET is invalid due to frame: " + JSON.stringify(Entities.getEntityProperties(HMD.tabletID, ["type"]).type));
|
|
}
|
|
return false;
|
|
}
|
|
if (Entities.getEntityProperties(HMD.homeButtonID, ["type"]).type !== "Gizmo" ||
|
|
Entities.getEntityProperties(HMD.tabletScreenID, ["type"]).type !== "Web") {
|
|
if (debugTablet) {
|
|
print("TABLET is invalid due to other");
|
|
}
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
function getTabletScalePercentageFromSettings() {
|
|
checkTablet();
|
|
var toolbarMode = gTablet.toolbarMode;
|
|
var tabletScalePercentage = DEFAULT_HMD_TABLET_SCALE;
|
|
if (!toolbarMode) {
|
|
if (HMD.active) {
|
|
tabletScalePercentage = Settings.getValue("hmdTabletScale") || DEFAULT_HMD_TABLET_SCALE;
|
|
} else {
|
|
tabletScalePercentage = Settings.getValue("desktopTabletScale") || DEFAULT_DESKTOP_TABLET_SCALE;
|
|
}
|
|
}
|
|
return tabletScalePercentage;
|
|
}
|
|
|
|
function updateTabletWidthFromSettings(force) {
|
|
var newTabletScalePercentage = getTabletScalePercentageFromSettings();
|
|
if ((force || (newTabletScalePercentage !== tabletScalePercentage)) && UIWebTablet) {
|
|
tabletScalePercentage = newTabletScalePercentage;
|
|
UIWebTablet.setWidth(DEFAULT_WIDTH * (tabletScalePercentage / 100));
|
|
}
|
|
}
|
|
|
|
function onHmdChanged() {
|
|
updateTabletWidthFromSettings();
|
|
}
|
|
|
|
function onSensorToWorldScaleChanged(sensorScaleFactor) {
|
|
if (HMD.active) {
|
|
var newTabletScalePercentage = getTabletScalePercentageFromSettings();
|
|
resizeTablet(DEFAULT_WIDTH * (newTabletScalePercentage / 100), undefined, sensorScaleFactor);
|
|
}
|
|
}
|
|
|
|
function rezTablet() {
|
|
if (debugTablet) {
|
|
print("TABLET rezzing");
|
|
}
|
|
checkTablet()
|
|
|
|
tabletScalePercentage = getTabletScalePercentageFromSettings();
|
|
UIWebTablet = new WebTablet("hifi/tablet/TabletRoot.qml",
|
|
DEFAULT_WIDTH * (tabletScalePercentage / 100),
|
|
null, activeHand, null, false);
|
|
UIWebTablet.register();
|
|
HMD.tabletID = UIWebTablet.tabletEntityID;
|
|
HMD.homeButtonID = UIWebTablet.homeButtonID;
|
|
HMD.tabletScreenID = UIWebTablet.webOverlayID;
|
|
HMD.homeButtonHighlightID = UIWebTablet.homeButtonHighlightID;
|
|
HMD.displayModeChanged.connect(onHmdChanged);
|
|
MyAvatar.sensorToWorldScaleChanged.connect(onSensorToWorldScaleChanged);
|
|
|
|
tabletRezzed = true;
|
|
}
|
|
|
|
function showTabletUI() {
|
|
checkTablet();
|
|
|
|
if (!tabletRezzed || !tabletIsValid()) {
|
|
closeTabletUI();
|
|
rezTablet();
|
|
}
|
|
|
|
if (UIWebTablet && tabletRezzed) {
|
|
if (debugTablet) {
|
|
print("TABLET in showTabletUI, already rezzed");
|
|
}
|
|
var tabletProperties = {};
|
|
if (!HMD.tabletContextualMode) { // contextual mode forces tablet in place -> don't update attachment
|
|
UIWebTablet.calculateTabletAttachmentProperties(activeHand, true, tabletProperties);
|
|
}
|
|
tabletProperties.visible = true;
|
|
tabletProperties.ignorePickIntersection = false;
|
|
Entities.editEntity(HMD.tabletID, tabletProperties);
|
|
Entities.editEntity(HMD.homeButtonID, { "visible": true, "ignorePickIntersection": false });
|
|
Entities.editEntity(HMD.homeButtonHighlightID, { "visible": true, "ignorePickIntersection": false });
|
|
Entities.editEntity(HMD.tabletScreenID, { "visible": true, "ignorePickIntersection": false, "maxFPS": 90 });
|
|
updateTabletWidthFromSettings(true);
|
|
}
|
|
gTablet.tabletShown = true;
|
|
}
|
|
|
|
function hideTabletUI() {
|
|
checkTablet()
|
|
gTablet.tabletShown = false;
|
|
if (!UIWebTablet) {
|
|
return;
|
|
}
|
|
|
|
if (debugTablet) {
|
|
print("TABLET hide");
|
|
}
|
|
|
|
Entities.editEntity(HMD.tabletID, { "visible": false, "ignorePickIntersection": true });
|
|
Entities.editEntity(HMD.homeButtonID, { "visible": false, "ignorePickIntersection": true });
|
|
Entities.editEntity(HMD.homeButtonHighlightID, { "visible": false, "ignorePickIntersection": true });
|
|
Entities.editEntity(HMD.tabletScreenID, { "visible": false, "ignorePickIntersection": true, "maxFPS": 1 });
|
|
}
|
|
|
|
function closeTabletUI() {
|
|
checkTablet();
|
|
gTablet.tabletShown = false;
|
|
if (UIWebTablet) {
|
|
if (UIWebTablet.onClose) {
|
|
UIWebTablet.onClose();
|
|
}
|
|
|
|
if (debugTablet) {
|
|
print("TABLET close");
|
|
}
|
|
UIWebTablet.unregister();
|
|
UIWebTablet.destroy();
|
|
UIWebTablet = null;
|
|
HMD.tabletID = null;
|
|
HMD.homeButtonID = null;
|
|
HMD.homeButtonHighlightID = null;
|
|
HMD.tabletScreenID = null;
|
|
} else if (debugTablet) {
|
|
print("TABLET closeTabletUI, UIWebTablet is null");
|
|
}
|
|
tabletRezzed = false;
|
|
gTablet = null;
|
|
}
|
|
|
|
|
|
function updateShowTablet() {
|
|
var now = Date.now();
|
|
|
|
checkTablet();
|
|
|
|
// close the WebTablet if it we go into toolbar mode.
|
|
var tabletShown = gTablet.tabletShown;
|
|
var toolbarMode = gTablet.toolbarMode;
|
|
var landscape = gTablet.landscape;
|
|
|
|
if (tabletShown && toolbarMode) {
|
|
closeTabletUI();
|
|
HMD.closeTablet();
|
|
return;
|
|
}
|
|
|
|
var needInstantUpdate = UIWebTablet && UIWebTablet.getLandscape() !== landscape;
|
|
|
|
if ((now - validCheckTime > MSECS_PER_SEC) || needInstantUpdate) {
|
|
validCheckTime = now;
|
|
|
|
updateTabletWidthFromSettings();
|
|
|
|
if (UIWebTablet) {
|
|
UIWebTablet.setLandscape(landscape);
|
|
}
|
|
if (tabletRezzed && UIWebTablet && !tabletIsValid()) {
|
|
// when we switch domains, the tablet entity gets destroyed and recreated. this causes
|
|
// the overlay to be deleted, but not recreated. If the overlay is deleted for this or any
|
|
// other reason, close the tablet.
|
|
closeTabletUI();
|
|
HMD.closeTablet();
|
|
if (debugTablet) {
|
|
print("TABLET autodestroying");
|
|
}
|
|
}
|
|
}
|
|
|
|
// check for change in tablet scale.
|
|
|
|
if (HMD.showTablet && !tabletShown && !toolbarMode) {
|
|
UserActivityLogger.openedTablet(false);
|
|
showTabletUI();
|
|
} else if (!HMD.showTablet && tabletShown) {
|
|
UserActivityLogger.closedTablet();
|
|
hideTabletUI();
|
|
}
|
|
|
|
// if the tablet is an overlay, attempt to pre-create it and then hide it so that when it's
|
|
// summoned, it will appear quickly.
|
|
if (!toolbarMode) {
|
|
if (now - preMakeTime > MSECS_PER_SEC) {
|
|
preMakeTime = now;
|
|
if (!tabletIsValid()) {
|
|
closeTabletUI();
|
|
rezTablet();
|
|
tabletShown = false;
|
|
|
|
// also cause the stylus model to be loaded
|
|
var tmpStylusID = Entities.addEntity({
|
|
"type": "Model",
|
|
"name": "stylus",
|
|
"modelURL": Script.resourcesPath() + "meshes/tablet-stylus-fat.fbx",
|
|
"position": Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, {"x": 0, "y": 0.1, "z": -2})),
|
|
"dimensions": { "x": 0.01, "y": 0.01, "z": 0.2 },
|
|
"primitiveMode": "solid",
|
|
"visible": true,
|
|
"ignorePickIntersection": true,
|
|
"renderLayer": "world",
|
|
"lifetime": 3
|
|
}, "local");
|
|
Script.setTimeout(function() {
|
|
Entities.deleteEntity(tmpStylusID);
|
|
}, 300);
|
|
} else if (!tabletShown) {
|
|
hideTabletUI();
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
function handleMessage(channel, hand, senderUUID, localOnly) {
|
|
if (channel === "toggleHand") {
|
|
activeHand = JSON.parse(hand);
|
|
}
|
|
if (channel === "home") {
|
|
if (UIWebTablet) {
|
|
checkTablet();
|
|
gTablet.landscape = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
Messages.subscribe("toggleHand");
|
|
Messages.subscribe("home");
|
|
Messages.messageReceived.connect(handleMessage);
|
|
|
|
var clickMapping = Controller.newMapping('tabletToggle-click');
|
|
var wantsMenu = 0;
|
|
clickMapping.from(function () { return wantsMenu; }).to(Controller.Actions.ContextMenu);
|
|
clickMapping.from(controllerStandard.RightSecondaryThumb).peek().when(Controller.Hardware.Application.LeftHandDominant).to(function (clicked) {
|
|
if (clicked) {
|
|
//activeHudPoint2d(controllerStandard.RightHand);
|
|
Messages.sendLocalMessage("toggleHand", controllerStandard.RightHand);
|
|
}
|
|
wantsMenu = clicked;
|
|
});
|
|
|
|
clickMapping.from(controllerStandard.LeftSecondaryThumb).peek().when(Controller.Hardware.Application.RightHandDominant).to(function (clicked) {
|
|
if (clicked) {
|
|
//activeHudPoint2d(controllerStandard.LeftHand);
|
|
Messages.sendLocalMessage("toggleHand", controllerStandard.LeftHand);
|
|
}
|
|
wantsMenu = clicked;
|
|
});
|
|
|
|
clickMapping.from(controllerStandard.Start).peek().to(function (clicked) {
|
|
if (clicked) {
|
|
//activeHudPoint2dGamePad();
|
|
var noHands = -1;
|
|
Messages.sendLocalMessage("toggleHand", controllerStandard.LeftHand);
|
|
}
|
|
|
|
wantsMenu = clicked;
|
|
});
|
|
clickMapping.enable();
|
|
|
|
Script.setInterval(updateShowTablet, 100);
|
|
|
|
Script.scriptEnding.connect(function () {
|
|
|
|
// if we reload scripts in tablet mode make sure we close the currently open window, by calling gotoHomeScreen
|
|
var tabletProxy = Tablet.getTablet("com.highfidelity.interface.tablet.system");
|
|
if (tabletProxy && tabletProxy.toolbarMode) {
|
|
tabletProxy.gotoHomeScreen();
|
|
}
|
|
|
|
var tabletID = HMD.tabletID;
|
|
Entities.deleteEntity(tabletID);
|
|
HMD.tabletID = null;
|
|
HMD.homeButtonID = null;
|
|
HMD.homeButtonHighlightID = null;
|
|
HMD.tabletScreenID = null;
|
|
});
|
|
Script.setTimeout(cleanupMaterialEntities, 100);
|
|
}()); // END LOCAL_SCOPE
|