//
// renderWithZonesManager.js
//
// Created by Alezia Kurdis on January 28th, 2024.
// Copyright 2024 Overte e.V.
//
// This script is to manage the zone in the property renderWithZones more efficiently in the Create Application.
// It allows a global view over a specific selection with possibility to
// REPLACE, REMOVE or ADD zones on those properties more efficiently.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
let rwzmSelectedId = [];
let rwzmAllZonesList = [];
let rwzmUsedZonesList = [];
let rwzmSelectedEntitiesData = [];
let rwzmUndo = [];
let enforceLocked = false;
const RWZ_ZONE_SCAN_RADIUS = 27713; //maximal radius to cover the entire domain.
let rwzmOverlayWebWindow = null;
function renderWithZonesManager(entityIDs, highlightedID = "") {
rwzmSelectedId = entityIDs;
if (entityIDs.length === 0) {
audioFeedback.rejection();
Window.alert("You have nothing selected.");
return;
} else {
rwzmAllZonesList = [];
rwzmUsedZonesList = [];
rwzmSelectedEntitiesData = [];
rwzmAllZonesList = rwzmGetExistingZoneList();
let properties;
let i = 0;
let j = 0;
let rwzmData = {};
for (i = 0; i < entityIDs.length; i++ ){
properties = Entities.getEntityProperties(entityIDs[i], ["renderWithZones", "locked", "name", "type"]);
//Identify the unique zone used in renderWithZones properties of the entities and make the list of this in rwzmUsedZonesList
if (properties.renderWithZones.length > 0) {
for (j = 0; j < properties.renderWithZones.length; j++ ){
if (rwzmUsedZonesList.indexOf(properties.renderWithZones[j]) === -1) {
rwzmUsedZonesList.push(properties.renderWithZones[j]);
}
}
}
//Make the list of entities, with their id, renderWithZones, locked, in rwzmSelectedEntitiesData
rwzmData = {
"id": entityIDs[i],
"name": properties.name,
"type": properties.type,
"renderWithZones": properties.renderWithZones,
"locked": properties.locked
};
rwzmSelectedEntitiesData.push(rwzmData);
}
}
if (rwzmOverlayWebWindow === null) {
rwzmOverlayWebWindow = new OverlayWebWindow({
title: "RenderWithZones Manager",
source: Script.resolvePath("renderWithZonesManager.html"),
width: 1100,
height: 600
});
rwzmOverlayWebWindow.closed.connect(uiHasClosed);
rwzmOverlayWebWindow.webEventReceived.connect(webEventReceiver);
}
rwzmGenerateUI(highlightedID);
}
function uiHasClosed() {
rwzmOverlayWebWindow.closed.disconnect(uiHasClosed);
rwzmOverlayWebWindow.webEventReceived.disconnect(webEventReceiver);
rwzmOverlayWebWindow = null;
}
function rwzmGenerateUI(highlightedID) {
let canUnlock = Entities.canAdjustLocks();
let uiContent = "";
let i = 0;
let k = 0;
let zones = "";
let name = "";
let elementClass = "";
let firstClass = "";
let isLocked = "";
let selectionBox = "";
let setCheck = "";
let addAction = "";
let toHighlight = "";
let viewBtnCaption = "";
uiContent = uiContent + '
RenderWithZones Manager \n';
if (canUnlock) {
if (enforceLocked) {
setCheck = " checked";
} else {
setCheck = "";
}
}
uiContent = uiContent + ' \n';
uiContent = uiContent + ' \n';
uiContent = uiContent + ' \n';
if (rwzmUndo.length === 0) {
undoBtnCode = "";
} else {
undoBtnCode = 'Undo ';
}
uiContent = uiContent + ' Visibility Zones: ' + undoBtnCode + '
\n';
uiContent = uiContent + ' \n';
uiContent = uiContent + ' \n';
for (i = 0; i < rwzmUsedZonesList.length; i++ ) {
name = rwzmGetZoneName(rwzmUsedZonesList[i]);
elementClass = "line";
firstClass = "cells";
if (name === "") {
name = rwzmGenerateUnidentifiedZoneName(rwzmUsedZonesList[i]);
elementClass = "errorline";
}
toHighlight = rwzmUsedZonesList[i];
viewBtnCaption = "View";
if ( rwzmUsedZonesList[i] === highlightedID) {
toHighlight = "";
viewBtnCaption = "Hide";
firstClass = "highlightedCells";
if (elementClass === "line") {
elementClass = "lineInverted";
}
}
uiContent = uiContent + ' ' + rwzmGetTruncatedString(name, 30) + '
';
uiContent = uiContent + '' + viewBtnCaption + ' ';
uiContent = uiContent + 'Remove ';
uiContent = uiContent + 'Replace \n';
}
uiContent = uiContent + '
\n';
uiContent = uiContent + ' \n';
uiContent = uiContent + ' \n';
uiContent = uiContent + ' \n';
uiContent = uiContent + ' \n';
uiContent = uiContent + ' \n';
uiContent = uiContent + '
\n';
uiContent = uiContent + ' \n';
uiContent = uiContent + '
\n';
uiContent = uiContent + ' \n';
//Zone selector Add
uiContent = uiContent + ' \n';
uiContent = uiContent + '
Select the zone to add: \n';
for (i = 0; i < rwzmAllZonesList.length; i++ ) {
uiContent = uiContent + " " + rwzmAllZonesList[i].name + " \n";
}
uiContent = uiContent + '
Cancel
\n';
uiContent = uiContent + '
\n';
//Zone selector Replace
uiContent = uiContent + ' \n';
uiContent = uiContent + '
Select the replacement zone: \n';
for (i = 0; i < rwzmAllZonesList.length; i++ ) {
uiContent = uiContent + " " + rwzmAllZonesList[i].name + " \n";
}
uiContent = uiContent + '
Cancel
\n';
uiContent = uiContent + '
\n';
Script.setTimeout(function () {
rwzmOverlayWebWindow.emitScriptEvent(uiContent);
}, 300);
}
function rwzmGetZoneName(id) {
let k = 0;
let name = "";
for (k = 0; k < rwzmAllZonesList.length; k++) {
if (rwzmAllZonesList[k].id === id) {
name = rwzmAllZonesList[k].name;
break;
}
}
return name;
}
function rwzmGenerateUnidentifiedZoneName(id) {
let partialID = id.substr(1,8);
return "ZONE NOT FOUND (" + partialID +")";
}
function rwzmGetExistingZoneList() {
var center = { "x": 0, "y": 0, "z": 0 };
var existingZoneIDs = Entities.findEntitiesByType("Zone", center, RWZ_ZONE_SCAN_RADIUS);
var listExistingZones = [];
var thisZone = {};
var properties;
for (var k = 0; k < existingZoneIDs.length; k++) {
properties = Entities.getEntityProperties(existingZoneIDs[k], ["name"]);
thisZone = {
"id": existingZoneIDs[k],
"name": properties.name
};
listExistingZones.push(thisZone);
}
listExistingZones.sort(rwzmZoneSortOrder);
return listExistingZones;
}
function rwzmZoneSortOrder(a, b) {
var nameA = a.name.toUpperCase();
var nameB = b.name.toUpperCase();
if (nameA > nameB) {
return 1;
} else if (nameA < nameB) {
return -1;
}
if (a.name > b.name) {
return 1;
} else if (a.name < b.name) {
return -1;
}
return 0;
}
function rwzmRemoveZoneFromEntity(id, zoneID, forceLocked, highlightedID) {
rwzmUndo = [];
let properties = Entities.getEntityProperties(id, ["renderWithZones", "locked"]);
let newRenderWithZones = [];
let i = 0;
for (i = 0; i < properties.renderWithZones.length; i++) {
if (properties.renderWithZones[i] !== zoneID) {
newRenderWithZones.push(properties.renderWithZones[i]);
}
}
if (forceLocked && properties.locked) {
Entities.editEntity(id, {"locked": false});
Entities.editEntity(id, {"renderWithZones": newRenderWithZones, "locked": properties.locked});
} else {
Entities.editEntity(id, {"renderWithZones": newRenderWithZones});
}
rwzmUndo.push({"id": id, "renderWithZones": properties.renderWithZones});
renderWithZonesManager(rwzmSelectedId, highlightedID);
}
function rwzmAddZonesToEntities(ids, zoneID, forceLocked, highlightedID) {
rwzmUndo = [];
let k = 0;
let j = 0;
let properties;
let newRenderWithZones = [];
for (k = 0; k < ids.length; k++) {
properties = Entities.getEntityProperties(ids[k], ["renderWithZones", "locked"]);
newRenderWithZones = [];
for (j = 0; j < properties.renderWithZones.length; j++) {
if (properties.renderWithZones[j] !== zoneID) {
newRenderWithZones.push(properties.renderWithZones[j]);
}
}
newRenderWithZones.push(zoneID);
if (forceLocked && properties.locked) {
Entities.editEntity(ids[k], {"locked": false});
Entities.editEntity(ids[k], {"renderWithZones": newRenderWithZones, "locked": properties.locked});
} else {
Entities.editEntity(ids[k], {"renderWithZones": newRenderWithZones});
}
rwzmUndo.push({"id": ids[k], "renderWithZones": properties.renderWithZones});
}
renderWithZonesManager(rwzmSelectedId, highlightedID);
}
function rwzmRemoveZoneFromAllEntities(zoneID, forceLocked, highlightedID) {
rwzmUndo = [];
let k = 0;
let j = 0;
let properties;
let newRenderWithZones = [];
for (k = 0; k < rwzmSelectedId.length; k++) {
properties = Entities.getEntityProperties(rwzmSelectedId[k], ["renderWithZones", "locked"]);
newRenderWithZones = [];
for (j = 0; j < properties.renderWithZones.length; j++) {
if (properties.renderWithZones[j] !== zoneID) {
newRenderWithZones.push(properties.renderWithZones[j]);
}
}
if (forceLocked && properties.locked) {
Entities.editEntity(rwzmSelectedId[k], {"locked": false});
Entities.editEntity(rwzmSelectedId[k], {"renderWithZones": newRenderWithZones, "locked": properties.locked});
} else {
Entities.editEntity(rwzmSelectedId[k], {"renderWithZones": newRenderWithZones});
}
rwzmUndo.push({"id": rwzmSelectedId[k], "renderWithZones": properties.renderWithZones});
}
renderWithZonesManager(rwzmSelectedId, highlightedID);
}
function rwzmReplaceZoneOnAllEntities(targetZoneID, replacementZoneID, forceLocked, highlightedID) {
rwzmUndo = [];
let k = 0;
let j = 0;
let properties;
let newRenderWithZones = [];
for (k = 0; k < rwzmSelectedId.length; k++) {
properties = Entities.getEntityProperties(rwzmSelectedId[k], ["renderWithZones", "locked"]);
newRenderWithZones = [];
for (j = 0; j < properties.renderWithZones.length; j++) {
if (properties.renderWithZones[j] !== targetZoneID) {
newRenderWithZones.push(properties.renderWithZones[j]);
} else {
newRenderWithZones.push(replacementZoneID);
}
}
if (forceLocked && properties.locked) {
Entities.editEntity(rwzmSelectedId[k], {"locked": false});
Entities.editEntity(rwzmSelectedId[k], {"renderWithZones": newRenderWithZones, "locked": properties.locked});
} else {
Entities.editEntity(rwzmSelectedId[k], {"renderWithZones": newRenderWithZones});
}
rwzmUndo.push({"id": rwzmSelectedId[k], "renderWithZones": properties.renderWithZones});
}
renderWithZonesManager(rwzmSelectedId, highlightedID);
}
function rwzmGetTruncatedString(str, max) {
if (str.length > max) {
return str.substr(0, max-1) + "…";
} else {
return str;
}
}
function rwzmUndoLastAction(highlightedID) {
let k = 0;
let properties;
let locked;
for (k = 0; k < rwzmUndo.length; k++) {
locked = Entities.getEntityProperties(rwzmUndo[k].id, ["locked"]).locked;
if (locked) {
Entities.editEntity(rwzmUndo[k].id, {"locked": false});
Entities.editEntity(rwzmUndo[k].id, {"renderWithZones": rwzmUndo[k].renderWithZones, "locked": locked});
} else {
Entities.editEntity(rwzmUndo[k].id, {"renderWithZones": rwzmUndo[k].renderWithZones});
}
}
rwzmUndo = [];
renderWithZonesManager(rwzmSelectedId, highlightedID);
}
function webEventReceiver (message) {
try {
var data = JSON.parse(message);
} catch(e) {
print("renderWithZonesManager.js: Error parsing JSON");
return;
}
if (data.action === "highlight") {
enforceLocked = data.enforceLocked;
renderWithZonesManager(rwzmSelectedId, data.id);
} else if (data.action === "removeZoneFromEntity") {
enforceLocked = data.enforceLocked;
rwzmRemoveZoneFromEntity(data.id, data.zoneID, data.enforceLocked, data.highlightedID);
} else if (data.action === "addZoneToEntities") {
enforceLocked = data.enforceLocked;
rwzmAddZonesToEntities(data.ids, data.zoneID, data.enforceLocked, data.highlightedID);
} else if (data.action === "refresh") {
enforceLocked = data.enforceLocked;
renderWithZonesManager(rwzmSelectedId, data.highlightedID);
} else if (data.action === "removeZoneOnAllEntities") {
enforceLocked = data.enforceLocked;
rwzmRemoveZoneFromAllEntities(data.zoneID, data.enforceLocked, data.highlightedID);
} else if (data.action === "replaceZoneOnAllEntities") {
enforceLocked = data.enforceLocked;
rwzmReplaceZoneOnAllEntities(data.targetZoneID, data.replacementZoneID, data.enforceLocked, data.highlightedID);
} else if (data.action === "undo") {
enforceLocked = data.enforceLocked;
rwzmUndoLastAction(data.highlightedID);
}
}