community-apps/applications/nyx-ui/nyx.js
2021-10-09 15:04:01 -04:00

361 lines
No EOL
12 KiB
JavaScript

'use strict';
//
// nyx.js
//
// Created by Kalila L. on Oct 6 2020.
// Copyright 2020 Vircadia contributors.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
Script.include('/~/system/libraries/utils.js');
var NyxSit = Script.require('./modules/sit.js');
var NyxParentSelf = Script.require('./modules/parentSelf.js');
// Consts
var SETTING_NYX_PREFIX = 'nyx/';
var NYX_SETTINGS_SETTINGS = 'Nyx Settings'; // lol
var NYX_UI_CHANNEL = 'nyx-ui';
var nyxSettings = null;
///////////////// BEGIN ENTITY MENU OVERLAY
var enableEntityWebMenu = true;
var entityWebMenuOverlay;
var registeredEntityMenus = {};
var lastTriggeredEntityInfo = {};
var lastTriggeredPointerLocation = null;
// Consts
var MENU_WEB_OVERLAY_SCALE = {
x: 400,
y: 500
};
var BOOTSTRAP_MENU_WEB_OVERLAY_TITLE = 'Entity Menu';
var BOOTSTRAP_MENU_WEB_OVERLAY_SCALE = {
x: 1,
y: 1
};
var BOOTSTRAP_MENU_WEB_OVERLAY_POSITION = {
x: 1,
y: 1
};
var BOOTSTRAP_MENU_WEB_OVERLAY_SOURCE;
var BOOTSTRAP_MENU_WEB_OVERLAY_DPI = 7;
///////////////// ENTITY MENU OVERLAY ---> MAIN FUNCTIONALITY
function registerWithEntityMenu(messageData) {
registeredEntityMenus[messageData.entityID] = { 'actions': messageData.actions };
var dataToSend = {
registeredEntityMenus: registeredEntityMenus
};
sendToWeb('script-to-web-registered-entity-menus', dataToSend);
}
function deregisterWithEntityMenu(messageData) {
delete registeredEntityMenus[messageData.entityID];
var dataToSend = {
registeredEntityMenus: registeredEntityMenus
};
sendToWeb('script-to-web-registered-entity-menus', dataToSend);
}
function toggleEntityMenu(pressedEntityID) {
if (!entityWebMenuOverlay.isVisible() && enableEntityWebMenu === true) {
var triggeredEntityProperties = Entities.getEntityProperties(pressedEntityID);
var lastEditedByName;
if (AvatarManager.getPalData([triggeredEntityProperties.lastEditedBy]).data[0]) {
lastEditedByName = AvatarManager.getPalData([triggeredEntityProperties.lastEditedBy]).data[0].sessionDisplayName
} else {
lastEditedByName = triggeredEntityProperties.lastEditedBy;
}
lastTriggeredEntityInfo = {
id: pressedEntityID,
name: triggeredEntityProperties.name,
type: triggeredEntityProperties.type,
lastEditedBy: triggeredEntityProperties.lastEditedBy,
lastEditedByName: lastEditedByName,
entityHostType: triggeredEntityProperties.entityHostType,
description: triggeredEntityProperties.description,
position: triggeredEntityProperties.position,
rotation: triggeredEntityProperties.rotation
};
sendToWeb('script-to-web-triggered-entity-info', lastTriggeredEntityInfo);
var newOverlayPosition = {};
// If in VR mode, we put the Nyx Entity menu in the center.
if (HMD.mounted) {
newOverlayPosition.x = (Overlays.width() / 2) - (MENU_WEB_OVERLAY_SCALE.x / 2);
newOverlayPosition.y = (Overlays.height() / 2) - (MENU_WEB_OVERLAY_SCALE.y / 2);
} else {
newOverlayPosition.x = (lastTriggeredPointerLocation.x - (MENU_WEB_OVERLAY_SCALE.x / 2));
newOverlayPosition.y = (lastTriggeredPointerLocation.y - (MENU_WEB_OVERLAY_SCALE.y / 2));
}
entityWebMenuOverlay.setPosition(newOverlayPosition);
entityWebMenuOverlay.setSize(MENU_WEB_OVERLAY_SCALE);
entityWebMenuOverlay.setVisible(true);
} else if (entityWebMenuOverlay.isVisible() && pressedEntityID !== entityWebMenuOverlay) {
entityWebMenuOverlay.setVisible(false);
}
}
///////////////// ENTITY MENU OVERLAY ---> IN-WORLD ENTITY MENU
function bootstrapEntityMenu() {
entityWebMenuOverlay = new OverlayWebWindow({
title: BOOTSTRAP_MENU_WEB_OVERLAY_TITLE,
source: BOOTSTRAP_MENU_WEB_OVERLAY_SOURCE,
width: BOOTSTRAP_MENU_WEB_OVERLAY_SCALE.x,
height: BOOTSTRAP_MENU_WEB_OVERLAY_SCALE.y
});
entityWebMenuOverlay.setVisible(false);
entityWebMenuOverlay.webEventReceived.connect(onOverlayWebEventReceived);
}
///////////////// ENTITY MENU OVERLAY ---> END IN-WORLD ENTITY MENU
///////////////// END ENTITY MENU OVERLAY
///////////////// BEGIN NYX MESSAGE HANDLING
function sendToWeb(command, data) {
var dataToSend = {
'command': command,
'data': data
};
entityWebMenuOverlay.emitScriptEvent(JSON.stringify(dataToSend));
}
function onOverlayWebEventReceived(event) {
var eventJSON = JSON.parse(event);
if (eventJSON.command === 'ready') {
var dataToSend = {
registeredEntityMenus: registeredEntityMenus,
lastTriggeredEntityInfo: lastTriggeredEntityInfo
};
sendToWeb('script-to-web-registered-entity-menus', dataToSend);
var settingsToSend = {
settings: nyxSettings
};
sendToWeb('script-to-web-update-settings', settingsToSend);
}
if (eventJSON.command === 'menu-item-triggered') {
var dataToSend = {
command: eventJSON.command,
entityID: eventJSON.data.triggeredEntityID,
data: eventJSON.data.data
};
Messages.sendLocalMessage(NYX_UI_CHANNEL, JSON.stringify(dataToSend));
// console.log(JSON.stringify(eventJSON));
if (eventJSON.data.data.type === 'button' && entityWebMenuOverlay.isVisible()) {
toggleEntityMenu(); // Close the menu if a menu item was pressed.
}
}
if (eventJSON.command === 'sit-on-entity-triggered') {
NyxSit.toggleSit();
}
if (eventJSON.command === 'parent-to-entity-triggered') {
NyxParentSelf.toggleParent(lastTriggeredEntityInfo.id);
}
if (eventJSON.command === 'entity-move-mode-triggered') {
if (Entities.getEntityProperties(lastTriggeredEntityInfo.id, ['grab']).grab.grabbable === false) {
Entities.editEntity(lastTriggeredEntityInfo.id, {'grab': { 'grabbable': true }});
} else {
Entities.editEntity(lastTriggeredEntityInfo.id, {'grab': { 'grabbable': false }});
}
}
if (eventJSON.command === 'close-entity-menu') {
if (entityWebMenuOverlay.isVisible()) {
toggleEntityMenu(); // Close the menu if it is active.
}
}
if (eventJSON.command === 'web-to-script-settings-changed') {
nyxSettings = eventJSON.data.settings;
Settings.setValue(SETTING_NYX_PREFIX + NYX_SETTINGS_SETTINGS, eventJSON.data.settings);
}
}
function onMessageReceived(channel, message, senderID, localOnly) {
// print('NYX UI Message received:');
// print('- channel: ' + channel);
// print('- message: ' + message);
// print('- sender: ' + senderID);
// print('- localOnly: ' + localOnly);
if (channel === NYX_UI_CHANNEL && MyAvatar.sessionUUID === senderID) {
messageData = JSON.parse(message);
if (messageData.command === 'register-with-entity-menu') {
registerWithEntityMenu(messageData);
}
if (messageData.command === 'deregister-with-entity-menu') {
deregisterWithEntityMenu(messageData);
}
}
}
///////////////// END NYX MESSAGE HANDLING
///////////////// BEGIN TRIGGER EVENT HANDLING
function processMouseEvent (event) {
if (!nyxSettings.entityMenu.selectedMouseTriggers) {
return false;
}
for (var i = 0; i < nyxSettings.entityMenu.selectedMouseTriggers.length; i++) {
var buttonToCheck = 'is' + nyxSettings.entityMenu.selectedMouseTriggers[i] + 'Held';
if (event[buttonToCheck] !== true) {
return false;
}
}
return true;
}
function onMousePressOnEntity (pressedEntityID, event) {
var currentCursorPosition = Reticle.getPosition();
lastTriggeredPointerLocation = {
x: currentCursorPosition.x,
y: currentCursorPosition.y
};
if (!entityWebMenuOverlay.isVisible()) {
NyxSit.capturePickPosition();
}
if (HMD.mounted) {
// Default trigger settings for triggering Nyx Entity when in VR.
if ((Controller.getValue(Controller.Standard.LeftGrip)
|| Controller.getValue(Controller.Standard.RightGrip))
&& (Controller.getValue(Controller.Standard.LT) // Redundant?
|| Controller.getValue(Controller.Standard.RT)))
{
toggleEntityMenu(pressedEntityID);
}
} else {
// Default if settings are not configured.
if (!nyxSettings || !nyxSettings.entityMenu.useMouseTriggers || nyxSettings.entityMenu.selectedMouseTriggers.length === 0) {
if (event.isPrimaryHeld && event.isSecondaryHeld && !isInEditMode()) {
toggleEntityMenu(pressedEntityID);
}
// If settings are configured, process the event accordingly.
} else if (processMouseEvent(event) === true) {
toggleEntityMenu(pressedEntityID);
}
}
}
///////////////// END TRIGGER EVENT HANDLING
///////////////// BEGIN NYX MENU HANDLING
var NYX_MAIN_MENU = 'Settings > Nyx';
var NYX_ENTITY_MENU_ENABLED = 'Enable Entity Menu';
var NYX_ENTITY_MENU_RESET = 'Reset Entity Menu';
function handleMenuEvent(menuItem) {
if (menuItem === NYX_ENTITY_MENU_ENABLED) {
enableEntityWebMenu = Menu.isOptionChecked(NYX_ENTITY_MENU_ENABLED);
Settings.setValue(SETTING_NYX_PREFIX + NYX_ENTITY_MENU_ENABLED, enableEntityWebMenu);
}
if (menuItem === NYX_ENTITY_MENU_RESET) {
nyxSettings = null;
Settings.setValue(SETTING_NYX_PREFIX + NYX_SETTINGS_SETTINGS, '');
}
}
function bootstrapNyxMenu() {
if (!Menu.menuExists(NYX_MAIN_MENU)) {
Menu.addMenu(NYX_MAIN_MENU);
Menu.addMenuItem({
menuName: NYX_MAIN_MENU,
menuItemName: NYX_ENTITY_MENU_ENABLED,
isCheckable: true,
isChecked: Settings.getValue(SETTING_NYX_PREFIX + NYX_ENTITY_MENU_ENABLED, true)
});
Menu.addMenuItem({
menuName: NYX_MAIN_MENU,
menuItemName: NYX_ENTITY_MENU_RESET,
isCheckable: false
});
}
enableEntityWebMenu = Settings.getValue(SETTING_NYX_PREFIX + NYX_ENTITY_MENU_ENABLED, true);
}
function unloadNyxMenu() {
Settings.setValue(SETTING_NYX_PREFIX + NYX_ENTITY_MENU_ENABLED, enableEntityWebMenu);
Menu.removeMenuItem(NYX_MAIN_MENU, NYX_ENTITY_MENU_ENABLED);
Menu.removeMenuItem(NYX_MAIN_MENU, NYX_ENTITY_MENU_RESET);
Menu.removeMenu(NYX_MAIN_MENU);
}
///////////////// END NYX MENU HANDLING
///////////////// BOOTSTRAPPING
function startup() {
Messages.messageReceived.connect(onMessageReceived);
Entities.mousePressOnEntity.connect(onMousePressOnEntity);
Menu.menuItemEvent.connect(handleMenuEvent);
nyxSettings = Settings.getValue(SETTING_NYX_PREFIX + NYX_SETTINGS_SETTINGS, '');
BOOTSTRAP_MENU_WEB_OVERLAY_SOURCE = Script.resolvePath('./index.html');
bootstrapNyxMenu();
bootstrapEntityMenu();
}
startup();
Script.scriptEnding.connect(function () {
Messages.messageReceived.disconnect(onMessageReceived);
Entities.mousePressOnEntity.disconnect(onMousePressOnEntity);
Menu.menuItemEvent.disconnect(handleMenuEvent);
entityWebMenuOverlay.webEventReceived.disconnect(onOverlayWebEventReceived);
unloadNyxMenu();
entityWebMenuOverlay = null;
});
///////////////// BOOTSTRAPPING TESTING CODE
// var messageToSend = {
// 'command': 'register-with-entity-menu',
// 'entityID': '{768542d0-e962-49e3-94fb-85651d56f5ae}',
// 'menuItems': ['This', 'Is', 'Nice']
// };
//
// Messages.sendLocalMessage(NYX_UI_CHANNEL, JSON.stringify(messageToSend));