mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-08-09 13:49:23 +02:00
Merge branch 'master' of https://github.com/highfidelity/hifi
This commit is contained in:
commit
35547a5a02
9 changed files with 294 additions and 189 deletions
|
@ -44,10 +44,16 @@ var entityListTool = EntityListTool();
|
||||||
|
|
||||||
var hasShownPropertiesTool = false;
|
var hasShownPropertiesTool = false;
|
||||||
|
|
||||||
|
var entityListVisible = false;
|
||||||
|
|
||||||
selectionManager.addEventListener(function() {
|
selectionManager.addEventListener(function() {
|
||||||
selectionDisplay.updateHandles();
|
selectionDisplay.updateHandles();
|
||||||
if (selectionManager.hasSelection() && !hasShownPropertiesTool) {
|
if (selectionManager.hasSelection() && !hasShownPropertiesTool) {
|
||||||
|
// Open properties and model list, but force selection of model list tab
|
||||||
|
propertiesTool.setVisible(false);
|
||||||
|
entityListTool.setVisible(false);
|
||||||
propertiesTool.setVisible(true);
|
propertiesTool.setVisible(true);
|
||||||
|
entityListTool.setVisible(true);
|
||||||
hasShownPropertiesTool = true;
|
hasShownPropertiesTool = true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -690,8 +696,8 @@ function setupModelMenus() {
|
||||||
print("delete exists... don't add ours");
|
print("delete exists... don't add ours");
|
||||||
}
|
}
|
||||||
|
|
||||||
Menu.addMenuItem({ menuName: "Edit", menuItemName: "Model List...", afterItem: "Models" });
|
Menu.addMenuItem({ menuName: "Edit", menuItemName: "Entity List...", shortcutKey: "CTRL+META+L", afterItem: "Models" });
|
||||||
Menu.addMenuItem({ menuName: "Edit", menuItemName: "Paste Models", shortcutKey: "CTRL+META+V", afterItem: "Model List..." });
|
Menu.addMenuItem({ menuName: "Edit", menuItemName: "Paste Models", shortcutKey: "CTRL+META+V", afterItem: "Entity List..." });
|
||||||
Menu.addMenuItem({ menuName: "Edit", menuItemName: "Allow Selecting of Large Models", shortcutKey: "CTRL+META+L",
|
Menu.addMenuItem({ menuName: "Edit", menuItemName: "Allow Selecting of Large Models", shortcutKey: "CTRL+META+L",
|
||||||
afterItem: "Paste Models", isCheckable: true, isChecked: true });
|
afterItem: "Paste Models", isCheckable: true, isChecked: true });
|
||||||
Menu.addMenuItem({ menuName: "Edit", menuItemName: "Allow Selecting of Small Models", shortcutKey: "CTRL+META+S",
|
Menu.addMenuItem({ menuName: "Edit", menuItemName: "Allow Selecting of Small Models", shortcutKey: "CTRL+META+S",
|
||||||
|
@ -703,6 +709,7 @@ function setupModelMenus() {
|
||||||
Menu.addMenuItem({ menuName: "File", menuItemName: "Export Models", shortcutKey: "CTRL+META+E", afterItem: "Models" });
|
Menu.addMenuItem({ menuName: "File", menuItemName: "Export Models", shortcutKey: "CTRL+META+E", afterItem: "Models" });
|
||||||
Menu.addMenuItem({ menuName: "File", menuItemName: "Import Models", shortcutKey: "CTRL+META+I", afterItem: "Export Models" });
|
Menu.addMenuItem({ menuName: "File", menuItemName: "Import Models", shortcutKey: "CTRL+META+I", afterItem: "Export Models" });
|
||||||
|
|
||||||
|
|
||||||
Menu.addMenuItem({ menuName: "View", menuItemName: MENU_EASE_ON_FOCUS, afterItem: MENU_INSPECT_TOOL_ENABLED,
|
Menu.addMenuItem({ menuName: "View", menuItemName: MENU_EASE_ON_FOCUS, afterItem: MENU_INSPECT_TOOL_ENABLED,
|
||||||
isCheckable: true, isChecked: Settings.getValue(SETTING_EASE_ON_FOCUS) == "true" });
|
isCheckable: true, isChecked: Settings.getValue(SETTING_EASE_ON_FOCUS) == "true" });
|
||||||
|
|
||||||
|
@ -718,7 +725,7 @@ function cleanupModelMenus() {
|
||||||
Menu.removeMenuItem("Edit", "Delete");
|
Menu.removeMenuItem("Edit", "Delete");
|
||||||
}
|
}
|
||||||
|
|
||||||
Menu.removeMenuItem("Edit", "Model List...");
|
Menu.removeMenuItem("Edit", "Entity List...");
|
||||||
Menu.removeMenuItem("Edit", "Paste Models");
|
Menu.removeMenuItem("Edit", "Paste Models");
|
||||||
Menu.removeMenuItem("Edit", "Allow Selecting of Large Models");
|
Menu.removeMenuItem("Edit", "Allow Selecting of Large Models");
|
||||||
Menu.removeMenuItem("Edit", "Allow Selecting of Small Models");
|
Menu.removeMenuItem("Edit", "Allow Selecting of Small Models");
|
||||||
|
@ -755,6 +762,28 @@ Script.update.connect(function (deltaTime) {
|
||||||
selectionDisplay.checkMove();
|
selectionDisplay.checkMove();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function deleteSelectedEntities() {
|
||||||
|
if (SelectionManager.hasSelection()) {
|
||||||
|
print(" Delete Entities");
|
||||||
|
SelectionManager.saveProperties();
|
||||||
|
var savedProperties = [];
|
||||||
|
for (var i = 0; i < selectionManager.selections.length; i++) {
|
||||||
|
var entityID = SelectionManager.selections[i];
|
||||||
|
var initialProperties = SelectionManager.savedProperties[entityID.id];
|
||||||
|
SelectionManager.savedProperties[entityID.id];
|
||||||
|
savedProperties.push({
|
||||||
|
entityID: entityID,
|
||||||
|
properties: initialProperties
|
||||||
|
});
|
||||||
|
Entities.deleteEntity(entityID);
|
||||||
|
}
|
||||||
|
SelectionManager.clearSelections();
|
||||||
|
pushCommandForSelections([], savedProperties);
|
||||||
|
} else {
|
||||||
|
print(" Delete Entity.... not holding...");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function handeMenuEvent(menuItem) {
|
function handeMenuEvent(menuItem) {
|
||||||
if (menuItem == "Allow Selecting of Small Models") {
|
if (menuItem == "Allow Selecting of Small Models") {
|
||||||
allowSmallModels = Menu.isOptionChecked("Allow Selecting of Small Models");
|
allowSmallModels = Menu.isOptionChecked("Allow Selecting of Small Models");
|
||||||
|
@ -763,57 +792,7 @@ function handeMenuEvent(menuItem) {
|
||||||
} else if (menuItem == "Allow Selecting of Lights") {
|
} else if (menuItem == "Allow Selecting of Lights") {
|
||||||
Entities.setLightsArePickable(Menu.isOptionChecked("Allow Selecting of Lights"));
|
Entities.setLightsArePickable(Menu.isOptionChecked("Allow Selecting of Lights"));
|
||||||
} else if (menuItem == "Delete") {
|
} else if (menuItem == "Delete") {
|
||||||
if (SelectionManager.hasSelection()) {
|
deleteSelectedEntities();
|
||||||
print(" Delete Entities");
|
|
||||||
SelectionManager.saveProperties();
|
|
||||||
var savedProperties = [];
|
|
||||||
for (var i = 0; i < selectionManager.selections.length; i++) {
|
|
||||||
var entityID = SelectionManager.selections[i];
|
|
||||||
var initialProperties = SelectionManager.savedProperties[entityID.id];
|
|
||||||
SelectionManager.savedProperties[entityID.id];
|
|
||||||
savedProperties.push({
|
|
||||||
entityID: entityID,
|
|
||||||
properties: initialProperties
|
|
||||||
});
|
|
||||||
Entities.deleteEntity(entityID);
|
|
||||||
}
|
|
||||||
SelectionManager.clearSelections();
|
|
||||||
pushCommandForSelections([], savedProperties);
|
|
||||||
} else {
|
|
||||||
print(" Delete Entity.... not holding...");
|
|
||||||
}
|
|
||||||
} else if (menuItem == "Model List...") {
|
|
||||||
var models = new Array();
|
|
||||||
models = Entities.findEntities(MyAvatar.position, Number.MAX_VALUE);
|
|
||||||
for (var i = 0; i < models.length; i++) {
|
|
||||||
models[i].properties = Entities.getEntityProperties(models[i]);
|
|
||||||
models[i].toString = function() {
|
|
||||||
var modelname;
|
|
||||||
if (this.properties.type == "Model") {
|
|
||||||
modelname = decodeURIComponent(
|
|
||||||
this.properties.modelURL.indexOf("/") != -1 ?
|
|
||||||
this.properties.modelURL.substring(this.properties.modelURL.lastIndexOf("/") + 1) :
|
|
||||||
this.properties.modelURL);
|
|
||||||
} else {
|
|
||||||
modelname = this.properties.id;
|
|
||||||
}
|
|
||||||
return "[" + this.properties.type + "] " + modelname;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
var form = [{label: "Model: ", options: models}];
|
|
||||||
form.push({label: "Action: ", options: ["Properties", "Delete", "Teleport"]});
|
|
||||||
form.push({ button: "Cancel" });
|
|
||||||
if (Window.form("Model List", form)) {
|
|
||||||
var selectedModel = form[0].value;
|
|
||||||
if (form[1].value == "Properties") {
|
|
||||||
editModelID = selectedModel;
|
|
||||||
entityPropertyDialogBox.openDialog(editModelID);
|
|
||||||
} else if (form[1].value == "Delete") {
|
|
||||||
Entities.deleteEntity(selectedModel);
|
|
||||||
} else if (form[1].value == "Teleport") {
|
|
||||||
MyAvatar.position = selectedModel.properties.position;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (menuItem == "Paste Models") {
|
} else if (menuItem == "Paste Models") {
|
||||||
modelImporter.paste();
|
modelImporter.paste();
|
||||||
} else if (menuItem == "Export Models") {
|
} else if (menuItem == "Export Models") {
|
||||||
|
@ -826,6 +805,10 @@ function handeMenuEvent(menuItem) {
|
||||||
}
|
}
|
||||||
} else if (menuItem == "Import Models") {
|
} else if (menuItem == "Import Models") {
|
||||||
modelImporter.doImport();
|
modelImporter.doImport();
|
||||||
|
} else if (menuItem == "Entity List...") {
|
||||||
|
if (isActive) {
|
||||||
|
entityListTool.toggleVisible();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
tooltip.show(false);
|
tooltip.show(false);
|
||||||
}
|
}
|
||||||
|
@ -842,7 +825,7 @@ Controller.keyPressEvent.connect(function(event) {
|
||||||
Controller.keyReleaseEvent.connect(function (event) {
|
Controller.keyReleaseEvent.connect(function (event) {
|
||||||
// since sometimes our menu shortcut keys don't work, trap our menu items here also and fire the appropriate menu items
|
// since sometimes our menu shortcut keys don't work, trap our menu items here also and fire the appropriate menu items
|
||||||
if (event.text == "BACKSPACE" || event.text == "DELETE") {
|
if (event.text == "BACKSPACE" || event.text == "DELETE") {
|
||||||
handeMenuEvent("Delete");
|
deleteSelectedEntities();
|
||||||
} else if (event.text == "TAB") {
|
} else if (event.text == "TAB") {
|
||||||
selectionDisplay.toggleSpaceMode();
|
selectionDisplay.toggleSpaceMode();
|
||||||
} else if (event.text == "f") {
|
} else if (event.text == "f") {
|
||||||
|
|
|
@ -1,14 +1,32 @@
|
||||||
|
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<link rel="stylesheet" type="text/css" href="style.css">
|
<link rel="stylesheet" type="text/css" href="style.css">
|
||||||
|
<script src="list.min.js"></script>
|
||||||
<script>
|
<script>
|
||||||
var entities = {};
|
var entities = {};
|
||||||
var selectedEntities = [];
|
var selectedEntities = [];
|
||||||
|
var currentSortColumn = 'type';
|
||||||
|
var currentSortOrder = 'asc';
|
||||||
|
var entityList = null;
|
||||||
|
var refreshEntityListTimer = null;
|
||||||
|
var ASC_STRING = ' ▾';
|
||||||
|
var DESC_STRING = ' ▴';
|
||||||
|
|
||||||
function loaded() {
|
function loaded() {
|
||||||
|
entityList = new List('entity-list', { valueNames: ['type', 'url']});
|
||||||
|
entityList.clear();
|
||||||
elEntityTable = document.getElementById("entity-table");
|
elEntityTable = document.getElementById("entity-table");
|
||||||
|
elEntityTableBody = document.getElementById("entity-table-body");
|
||||||
elRefresh = document.getElementById("refresh");
|
elRefresh = document.getElementById("refresh");
|
||||||
|
elDelete = document.getElementById("delete");
|
||||||
|
elTeleport = document.getElementById("teleport");
|
||||||
|
|
||||||
|
document.getElementById("entity-type").onclick = function() {
|
||||||
|
setSortColumn('type');
|
||||||
|
};
|
||||||
|
document.getElementById("entity-url").onclick = function() {
|
||||||
|
setSortColumn('url');
|
||||||
|
};
|
||||||
|
|
||||||
function onRowClicked(e) {
|
function onRowClicked(e) {
|
||||||
var id = this.dataset.entityId;
|
var id = this.dataset.entityId;
|
||||||
|
@ -20,7 +38,8 @@
|
||||||
|
|
||||||
selectedEntities = selection;
|
selectedEntities = selection;
|
||||||
|
|
||||||
entities[id].el.className = 'selected';
|
this.className = 'selected';
|
||||||
|
|
||||||
EventBridge.emitWebEvent(JSON.stringify({
|
EventBridge.emitWebEvent(JSON.stringify({
|
||||||
type: "selectionUpdate",
|
type: "selectionUpdate",
|
||||||
focus: false,
|
focus: false,
|
||||||
|
@ -29,8 +48,6 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
function onRowDoubleClicked() {
|
function onRowDoubleClicked() {
|
||||||
var id = this.dataset.entityId;
|
|
||||||
|
|
||||||
EventBridge.emitWebEvent(JSON.stringify({
|
EventBridge.emitWebEvent(JSON.stringify({
|
||||||
type: "selectionUpdate",
|
type: "selectionUpdate",
|
||||||
focus: true,
|
focus: true,
|
||||||
|
@ -40,41 +57,91 @@
|
||||||
|
|
||||||
function addEntity(id, type, url) {
|
function addEntity(id, type, url) {
|
||||||
if (entities[id] === undefined) {
|
if (entities[id] === undefined) {
|
||||||
var el = document.createElement('tr');
|
var urlParts = url.split('/');
|
||||||
el.setAttribute('id', 'entity_' + id);
|
var filename = urlParts[urlParts.length - 1];
|
||||||
el.innerHTML += "<td>" + type + "</td>";
|
|
||||||
el.innerHTML += "<td>" + url + "</td>";
|
|
||||||
el.dataset.entityId = id;
|
|
||||||
el.onclick = onRowClicked;
|
|
||||||
el.ondblclick = onRowDoubleClicked;
|
|
||||||
elEntityTable.appendChild(el);
|
|
||||||
|
|
||||||
// Add element to local dict
|
entityList.add([{ id: id, type: type, url: filename }], function(items) {
|
||||||
entities[id] = {
|
var el = items[0].elm;
|
||||||
id: id,
|
var id = items[0]._values.id;
|
||||||
name: id,
|
entities[id] = {
|
||||||
el: el,
|
id: id,
|
||||||
};
|
name: id,
|
||||||
}
|
el: el,
|
||||||
}
|
};
|
||||||
|
el.setAttribute('id', 'entity_' + id);
|
||||||
|
el.setAttribute('title', url);
|
||||||
|
el.dataset.entityId = id;
|
||||||
|
el.onclick = onRowClicked;
|
||||||
|
el.ondblclick = onRowDoubleClicked;
|
||||||
|
el.innerHTML
|
||||||
|
});
|
||||||
|
|
||||||
function removeEntity(id) {
|
if (refreshEntityListTimer) {
|
||||||
if (entities[id] !== undefined) {
|
clearTimeout(refreshEntityListTimer);
|
||||||
elEntityTable.removeChild(entities[id].el);
|
}
|
||||||
delete entities[id];
|
refreshEntityListTimer = setTimeout(refreshEntityListObject, 50);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function clearEntities() {
|
function clearEntities() {
|
||||||
for (id in entities) {
|
|
||||||
elEntityTable.removeChild(entities[id].el);
|
|
||||||
}
|
|
||||||
entities = {};
|
entities = {};
|
||||||
|
entityList.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
var elSortOrder = {
|
||||||
|
type: document.querySelector('#entity-type .sort-order'),
|
||||||
|
url: document.querySelector('#entity-url .sort-order'),
|
||||||
|
}
|
||||||
|
function setSortColumn(column) {
|
||||||
|
if (currentSortColumn == column) {
|
||||||
|
currentSortOrder = currentSortOrder == "asc" ? "desc" : "asc";
|
||||||
|
} else {
|
||||||
|
elSortOrder[currentSortColumn].style.display = 'none';
|
||||||
|
elSortOrder[column].style.display = 'inline';
|
||||||
|
currentSortColumn = column;
|
||||||
|
currentSortOrder = "asc";
|
||||||
|
}
|
||||||
|
elSortOrder[column].innerHTML = currentSortOrder == "asc" ? ASC_STRING : DESC_STRING;
|
||||||
|
entityList.sort(currentSortColumn, { order: currentSortOrder });
|
||||||
|
}
|
||||||
|
|
||||||
|
function refreshEntities() {
|
||||||
|
clearEntities();
|
||||||
|
EventBridge.emitWebEvent(JSON.stringify({ type: 'refresh' }));
|
||||||
|
}
|
||||||
|
|
||||||
|
function refreshEntityListObject() {
|
||||||
|
refreshEntityListTimer = null;
|
||||||
|
entityList.sort(currentSortColumn, { order: currentSortOrder });
|
||||||
|
entityList.search(document.getElementById("filter").value);
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateSelectedEntities(selectedEntities) {
|
||||||
|
var notFound = false;
|
||||||
|
for (var id in entities) {
|
||||||
|
entities[id].el.className = '';
|
||||||
|
}
|
||||||
|
for (var i = 0; i < selectedEntities.length; i++) {
|
||||||
|
var id = selectedEntities[i];
|
||||||
|
if (id in entities) {
|
||||||
|
var entity = entities[id];
|
||||||
|
entity.el.className = 'selected';
|
||||||
|
} else {
|
||||||
|
notFound = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return notFound;
|
||||||
}
|
}
|
||||||
|
|
||||||
elRefresh.onclick = function() {
|
elRefresh.onclick = function() {
|
||||||
clearEntities();
|
refreshEntities();
|
||||||
EventBridge.emitWebEvent(JSON.stringify({ type: 'refresh' }));
|
}
|
||||||
|
elTeleport.onclick = function() {
|
||||||
|
EventBridge.emitWebEvent(JSON.stringify({ type: 'teleport' }));
|
||||||
|
}
|
||||||
|
elDelete.onclick = function() {
|
||||||
|
EventBridge.emitWebEvent(JSON.stringify({ type: 'delete' }));
|
||||||
|
refreshEntities();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (window.EventBridge !== undefined) {
|
if (window.EventBridge !== undefined) {
|
||||||
|
@ -82,16 +149,9 @@
|
||||||
data = JSON.parse(data);
|
data = JSON.parse(data);
|
||||||
|
|
||||||
if (data.type == "selectionUpdate") {
|
if (data.type == "selectionUpdate") {
|
||||||
selectedEntities = data.selectedIDs;
|
var notFound = updateSelectedEntities(data.selectedIDs);
|
||||||
for (var id in entities) {
|
if (notFound) {
|
||||||
entities[id].el.className = '';
|
refreshEntities();
|
||||||
}
|
|
||||||
for (var i = 0; i < data.selectedIDs.length; i++) {
|
|
||||||
var id = data.selectedIDs[i];
|
|
||||||
if (id in entities) {
|
|
||||||
var entity = entities[id];
|
|
||||||
entity.el.className = 'selected';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else if (data.type == "update") {
|
} else if (data.type == "update") {
|
||||||
var newEntities = data.entities;
|
var newEntities = data.entities;
|
||||||
|
@ -99,27 +159,39 @@
|
||||||
var id = newEntities[i].id;
|
var id = newEntities[i].id;
|
||||||
addEntity(id, newEntities[i].type, newEntities[i].url);
|
addEntity(id, newEntities[i].type, newEntities[i].url);
|
||||||
}
|
}
|
||||||
|
updateSelectedEntities(data.selectedIDs);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
setTimeout(refreshEntities, 1000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
</head>
|
</head>
|
||||||
<body onload='loaded();'>
|
<body onload='loaded();'>
|
||||||
<div>
|
<div>
|
||||||
<button id="refresh">Refresh</button>
|
<input type="button" id="refresh" value="Refresh"></button>
|
||||||
|
<input type="button" id="teleport" value="Teleport"></button>
|
||||||
|
<input type="button" id="delete" style="background-color: rgb(244, 64, 64); float: right" value="Delete"></button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<table id="entity-table">
|
<div id="entity-list">
|
||||||
<thead>
|
<input type="text" class="search" id="filter" placeholder="Filter" />
|
||||||
<tr>
|
<table id="entity-table">
|
||||||
<th id="entity-type">Type</th>
|
<thead>
|
||||||
<th id="entity-url">URL</th>
|
<tr>
|
||||||
</tr>
|
<th id="entity-type" data-sort="type">Type <span class="sort-order" style="display: inline"> ▾</span></th>
|
||||||
</thead>
|
<th id="entity-url" data-sort="url">URL <span class="sort-order" style="display: none"> ▾</span></th>
|
||||||
<tbody id="entity-table-body">
|
</tr>
|
||||||
</tbody>
|
</thead>
|
||||||
</table>
|
<tbody class="list" id="entity-table-body">
|
||||||
|
<tr>
|
||||||
|
<td class="id" style="display: none">Type</td>
|
||||||
|
<td class="type">Type</td>
|
||||||
|
<td class="url"><div class='outer'><div class='inner'>URL</div></div></td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
1
examples/html/list.min.js
vendored
Normal file
1
examples/html/list.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
|
@ -5,9 +5,10 @@ body {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
|
||||||
background-color: #efefef;
|
background-color: rgb(76, 76, 76);
|
||||||
|
color: rgb(204, 204, 204);
|
||||||
font-family: Arial;
|
font-family: Arial;
|
||||||
font-size: 11.5px;
|
font-size: 11px;
|
||||||
|
|
||||||
-webkit-touch-callout: none;
|
-webkit-touch-callout: none;
|
||||||
-webkit-user-select: none;
|
-webkit-user-select: none;
|
||||||
|
@ -17,12 +18,6 @@ body {
|
||||||
user-select: none;
|
user-select: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
body.properties {
|
|
||||||
background-color: rgb(76, 76, 76);
|
|
||||||
color: rgb(204, 204, 204);
|
|
||||||
font-size: 11px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.selectable {
|
.selectable {
|
||||||
-webkit-touch-callout: text;
|
-webkit-touch-callout: text;
|
||||||
-webkit-user-select: text;
|
-webkit-user-select: text;
|
||||||
|
@ -117,12 +112,13 @@ input.coord {
|
||||||
table#entity-table {
|
table#entity-table {
|
||||||
border-collapse: collapse;
|
border-collapse: collapse;
|
||||||
font-family: Sans-Serif;
|
font-family: Sans-Serif;
|
||||||
/* font-size: 12px; */
|
font-size: 10px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
#entity-table tr {
|
#entity-table tr {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
border-bottom: 1px solid rgb(63, 63, 63)
|
||||||
}
|
}
|
||||||
|
|
||||||
#entity-table tr.selected {
|
#entity-table tr.selected {
|
||||||
|
@ -139,17 +135,22 @@ table#entity-table {
|
||||||
}
|
}
|
||||||
|
|
||||||
#entity-table td {
|
#entity-table td {
|
||||||
|
font-size: 11px;
|
||||||
border: 0px black solid;
|
border: 0px black solid;
|
||||||
word-wrap: nowrap;
|
word-wrap: nowrap;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
#entity-table td.url {
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
th#entity-type {
|
th#entity-type {
|
||||||
width: 60px;
|
width: 60px;
|
||||||
}
|
}
|
||||||
|
|
||||||
th#entity-url {
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
div.input-area {
|
div.input-area {
|
||||||
|
@ -226,3 +227,20 @@ table#properties-list {
|
||||||
col#col-label {
|
col#col-label {
|
||||||
width: 130px;
|
width: 130px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
div.outer {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
div.inner {
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
overflow: hidden;
|
||||||
|
white-space: nowrap;
|
||||||
|
position: absolute;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
td {
|
||||||
|
|
||||||
|
|
||||||
|
vertical-align: top;
|
||||||
|
}
|
||||||
|
|
|
@ -13,6 +13,10 @@ EntityListTool = function(opts) {
|
||||||
webView.setVisible(visible);
|
webView.setVisible(visible);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
that.toggleVisible = function() {
|
||||||
|
that.setVisible(!visible);
|
||||||
|
}
|
||||||
|
|
||||||
selectionManager.addEventListener(function() {
|
selectionManager.addEventListener(function() {
|
||||||
var selectedIDs = [];
|
var selectedIDs = [];
|
||||||
|
|
||||||
|
@ -24,10 +28,38 @@ EntityListTool = function(opts) {
|
||||||
type: 'selectionUpdate',
|
type: 'selectionUpdate',
|
||||||
selectedIDs: selectedIDs,
|
selectedIDs: selectedIDs,
|
||||||
};
|
};
|
||||||
|
print("Sending: " + JSON.stringify(data));
|
||||||
webView.eventBridge.emitScriptEvent(JSON.stringify(data));
|
webView.eventBridge.emitScriptEvent(JSON.stringify(data));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function sendUpdate() {
|
||||||
|
var entities = [];
|
||||||
|
var ids = Entities.findEntities(MyAvatar.position, 100);
|
||||||
|
for (var i = 0; i < ids.length; i++) {
|
||||||
|
var id = ids[i];
|
||||||
|
var properties = Entities.getEntityProperties(id);
|
||||||
|
entities.push({
|
||||||
|
id: id.id,
|
||||||
|
type: properties.type,
|
||||||
|
url: properties.type == "Model" ? properties.modelURL : "",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
var selectedIDs = [];
|
||||||
|
for (var i = 0; i < selectionManager.selections.length; i++) {
|
||||||
|
selectedIDs.push(selectionManager.selections[i].id);
|
||||||
|
}
|
||||||
|
|
||||||
|
var data = {
|
||||||
|
type: "update",
|
||||||
|
entities: entities,
|
||||||
|
selectedIDs: selectedIDs,
|
||||||
|
};
|
||||||
|
webView.eventBridge.emitScriptEvent(JSON.stringify(data));
|
||||||
|
}
|
||||||
|
|
||||||
webView.eventBridge.webEventReceived.connect(function(data) {
|
webView.eventBridge.webEventReceived.connect(function(data) {
|
||||||
|
print("Got: " + data);
|
||||||
data = JSON.parse(data);
|
data = JSON.parse(data);
|
||||||
if (data.type == "selectionUpdate") {
|
if (data.type == "selectionUpdate") {
|
||||||
var ids = data.entityIds;
|
var ids = data.entityIds;
|
||||||
|
@ -46,22 +78,13 @@ EntityListTool = function(opts) {
|
||||||
Menu.isOptionChecked(MENU_EASE_ON_FOCUS));
|
Menu.isOptionChecked(MENU_EASE_ON_FOCUS));
|
||||||
}
|
}
|
||||||
} else if (data.type == "refresh") {
|
} else if (data.type == "refresh") {
|
||||||
var entities = [];
|
sendUpdate();
|
||||||
var ids = Entities.findEntities(MyAvatar.position, 100);
|
} else if (data.type == "teleport") {
|
||||||
for (var i = 0; i < ids.length; i++) {
|
if (selectionManager.hasSelection()) {
|
||||||
var id = ids[i];
|
MyAvatar.position = selectionManager.worldPosition;
|
||||||
var properties = Entities.getEntityProperties(id);
|
|
||||||
entities.push({
|
|
||||||
id: id.id,
|
|
||||||
type: properties.type,
|
|
||||||
url: properties.type == "Model" ? properties.modelURL : "",
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
var data = {
|
} else if (data.type == "delete") {
|
||||||
type: "update",
|
deleteSelectedEntities();
|
||||||
entities: entities,
|
|
||||||
};
|
|
||||||
webView.eventBridge.emitScriptEvent(JSON.stringify(data));
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -41,19 +41,27 @@ WebWindowClass::WebWindowClass(const QString& title, const QString& url, int wid
|
||||||
|
|
||||||
_dockWidget = new QDockWidget(title, toolWindow);
|
_dockWidget = new QDockWidget(title, toolWindow);
|
||||||
_dockWidget->setFeatures(QDockWidget::DockWidgetMovable);
|
_dockWidget->setFeatures(QDockWidget::DockWidgetMovable);
|
||||||
QWebView* webView = new QWebView(_dockWidget);
|
|
||||||
webView->page()->mainFrame()->addToJavaScriptWindowObject("EventBridge", _eventBridge);
|
_webView = new QWebView(_dockWidget);
|
||||||
webView->setUrl(url);
|
_webView->setUrl(url);
|
||||||
_dockWidget->setWidget(webView);
|
addEventBridgeToWindowObject();
|
||||||
|
|
||||||
|
_dockWidget->setWidget(_webView);
|
||||||
|
|
||||||
toolWindow->addDockWidget(Qt::RightDockWidgetArea, _dockWidget);
|
toolWindow->addDockWidget(Qt::RightDockWidgetArea, _dockWidget);
|
||||||
|
|
||||||
|
connect(_webView->page()->mainFrame(), &QWebFrame::javaScriptWindowObjectCleared,
|
||||||
|
this, &WebWindowClass::addEventBridgeToWindowObject);
|
||||||
connect(this, &WebWindowClass::destroyed, _dockWidget, &QWidget::deleteLater);
|
connect(this, &WebWindowClass::destroyed, _dockWidget, &QWidget::deleteLater);
|
||||||
}
|
}
|
||||||
|
|
||||||
WebWindowClass::~WebWindowClass() {
|
WebWindowClass::~WebWindowClass() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WebWindowClass::addEventBridgeToWindowObject() {
|
||||||
|
_webView->page()->mainFrame()->addToJavaScriptWindowObject("EventBridge", _eventBridge);
|
||||||
|
}
|
||||||
|
|
||||||
void WebWindowClass::setVisible(bool visible) {
|
void WebWindowClass::setVisible(bool visible) {
|
||||||
if (visible) {
|
if (visible) {
|
||||||
QMetaObject::invokeMethod(
|
QMetaObject::invokeMethod(
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
|
|
||||||
#include <QScriptContext>
|
#include <QScriptContext>
|
||||||
#include <QScriptEngine>
|
#include <QScriptEngine>
|
||||||
|
#include <QWebView>
|
||||||
|
|
||||||
class ScriptEventBridge : public QObject {
|
class ScriptEventBridge : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
@ -42,9 +43,11 @@ public:
|
||||||
public slots:
|
public slots:
|
||||||
void setVisible(bool visible);
|
void setVisible(bool visible);
|
||||||
ScriptEventBridge* getEventBridge() const { return _eventBridge; }
|
ScriptEventBridge* getEventBridge() const { return _eventBridge; }
|
||||||
|
void addEventBridgeToWindowObject();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QDockWidget* _dockWidget;
|
QDockWidget* _dockWidget;
|
||||||
|
QWebView* _webView;
|
||||||
ScriptEventBridge* _eventBridge;
|
ScriptEventBridge* _eventBridge;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -60,14 +60,17 @@ void PhysicsEngine::addEntityInternal(EntityItem* entity) {
|
||||||
assert(entity);
|
assert(entity);
|
||||||
void* physicsInfo = entity->getPhysicsInfo();
|
void* physicsInfo = entity->getPhysicsInfo();
|
||||||
if (!physicsInfo) {
|
if (!physicsInfo) {
|
||||||
EntityMotionState* motionState = new EntityMotionState(entity);
|
ShapeInfo shapeInfo;
|
||||||
if (addObject(motionState)) {
|
entity->computeShapeInfo(shapeInfo);
|
||||||
|
btCollisionShape* shape = _shapeManager.getShape(shapeInfo);
|
||||||
|
if (shape) {
|
||||||
|
EntityMotionState* motionState = new EntityMotionState(entity);
|
||||||
entity->setPhysicsInfo(static_cast<void*>(motionState));
|
entity->setPhysicsInfo(static_cast<void*>(motionState));
|
||||||
_entityMotionStates.insert(motionState);
|
_entityMotionStates.insert(motionState);
|
||||||
|
addObject(shapeInfo, shape, motionState);
|
||||||
} else {
|
} else {
|
||||||
// We failed to add the entity to the simulation. Probably because we couldn't create a shape for it.
|
// We failed to add the entity to the simulation. Probably because we couldn't create a shape for it.
|
||||||
//qDebug() << "failed to add entity " << entity->getEntityItemID() << " to physics engine";
|
//qDebug() << "failed to add entity " << entity->getEntityItemID() << " to physics engine";
|
||||||
delete motionState;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -244,59 +247,53 @@ void PhysicsEngine::stepSimulation() {
|
||||||
// CF_DISABLE_VISUALIZE_OBJECT = 32, //disable debug drawing
|
// CF_DISABLE_VISUALIZE_OBJECT = 32, //disable debug drawing
|
||||||
// CF_DISABLE_SPU_COLLISION_PROCESSING = 64//disable parallel/SPU processing
|
// CF_DISABLE_SPU_COLLISION_PROCESSING = 64//disable parallel/SPU processing
|
||||||
|
|
||||||
bool PhysicsEngine::addObject(ObjectMotionState* motionState) {
|
void PhysicsEngine::addObject(const ShapeInfo& shapeInfo, btCollisionShape* shape, ObjectMotionState* motionState) {
|
||||||
|
assert(shape);
|
||||||
assert(motionState);
|
assert(motionState);
|
||||||
ShapeInfo shapeInfo;
|
|
||||||
motionState->computeShapeInfo(shapeInfo);
|
btVector3 inertia(0.0f, 0.0f, 0.0f);
|
||||||
btCollisionShape* shape = _shapeManager.getShape(shapeInfo);
|
float mass = 0.0f;
|
||||||
if (shape) {
|
btRigidBody* body = NULL;
|
||||||
btVector3 inertia(0.0f, 0.0f, 0.0f);
|
switch(motionState->computeMotionType()) {
|
||||||
float mass = 0.0f;
|
case MOTION_TYPE_KINEMATIC: {
|
||||||
btRigidBody* body = NULL;
|
body = new btRigidBody(mass, motionState, shape, inertia);
|
||||||
switch(motionState->computeMotionType()) {
|
body->setCollisionFlags(btCollisionObject::CF_KINEMATIC_OBJECT);
|
||||||
case MOTION_TYPE_KINEMATIC: {
|
body->updateInertiaTensor();
|
||||||
body = new btRigidBody(mass, motionState, shape, inertia);
|
motionState->_body = body;
|
||||||
body->setCollisionFlags(btCollisionObject::CF_KINEMATIC_OBJECT);
|
motionState->addKinematicController();
|
||||||
body->updateInertiaTensor();
|
const float KINEMATIC_LINEAR_VELOCITY_THRESHOLD = 0.01f; // 1 cm/sec
|
||||||
motionState->_body = body;
|
const float KINEMATIC_ANGULAR_VELOCITY_THRESHOLD = 0.01f; // ~1 deg/sec
|
||||||
motionState->addKinematicController();
|
body->setSleepingThresholds(KINEMATIC_LINEAR_VELOCITY_THRESHOLD, KINEMATIC_ANGULAR_VELOCITY_THRESHOLD);
|
||||||
const float KINEMATIC_LINEAR_VELOCITY_THRESHOLD = 0.01f; // 1 cm/sec
|
break;
|
||||||
const float KINEMATIC_ANGULAR_VELOCITY_THRESHOLD = 0.01f; // ~1 deg/sec
|
}
|
||||||
body->setSleepingThresholds(KINEMATIC_LINEAR_VELOCITY_THRESHOLD, KINEMATIC_ANGULAR_VELOCITY_THRESHOLD);
|
case MOTION_TYPE_DYNAMIC: {
|
||||||
break;
|
mass = motionState->computeMass(shapeInfo);
|
||||||
}
|
shape->calculateLocalInertia(mass, inertia);
|
||||||
case MOTION_TYPE_DYNAMIC: {
|
body = new btRigidBody(mass, motionState, shape, inertia);
|
||||||
mass = motionState->computeMass(shapeInfo);
|
body->updateInertiaTensor();
|
||||||
shape->calculateLocalInertia(mass, inertia);
|
motionState->_body = body;
|
||||||
body = new btRigidBody(mass, motionState, shape, inertia);
|
motionState->updateObjectVelocities();
|
||||||
body->updateInertiaTensor();
|
// NOTE: Bullet will deactivate any object whose velocity is below these thresholds for longer than 2 seconds.
|
||||||
motionState->_body = body;
|
// (the 2 seconds is determined by: static btRigidBody::gDeactivationTime
|
||||||
motionState->updateObjectVelocities();
|
const float DYNAMIC_LINEAR_VELOCITY_THRESHOLD = 0.05f; // 5 cm/sec
|
||||||
// NOTE: Bullet will deactivate any object whose velocity is below these thresholds for longer than 2 seconds.
|
const float DYNAMIC_ANGULAR_VELOCITY_THRESHOLD = 0.087266f; // ~5 deg/sec
|
||||||
// (the 2 seconds is determined by: static btRigidBody::gDeactivationTime
|
body->setSleepingThresholds(DYNAMIC_LINEAR_VELOCITY_THRESHOLD, DYNAMIC_ANGULAR_VELOCITY_THRESHOLD);
|
||||||
const float DYNAMIC_LINEAR_VELOCITY_THRESHOLD = 0.05f; // 5 cm/sec
|
break;
|
||||||
const float DYNAMIC_ANGULAR_VELOCITY_THRESHOLD = 0.087266f; // ~5 deg/sec
|
}
|
||||||
body->setSleepingThresholds(DYNAMIC_LINEAR_VELOCITY_THRESHOLD, DYNAMIC_ANGULAR_VELOCITY_THRESHOLD);
|
case MOTION_TYPE_STATIC:
|
||||||
break;
|
default: {
|
||||||
}
|
body = new btRigidBody(mass, motionState, shape, inertia);
|
||||||
case MOTION_TYPE_STATIC:
|
body->setCollisionFlags(btCollisionObject::CF_STATIC_OBJECT);
|
||||||
default: {
|
body->updateInertiaTensor();
|
||||||
body = new btRigidBody(mass, motionState, shape, inertia);
|
motionState->_body = body;
|
||||||
body->setCollisionFlags(btCollisionObject::CF_STATIC_OBJECT);
|
break;
|
||||||
body->updateInertiaTensor();
|
|
||||||
motionState->_body = body;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// wtf?
|
|
||||||
body->setFlags(BT_DISABLE_WORLD_GRAVITY);
|
|
||||||
body->setRestitution(motionState->_restitution);
|
|
||||||
body->setFriction(motionState->_friction);
|
|
||||||
body->setDamping(motionState->_linearDamping, motionState->_angularDamping);
|
|
||||||
_dynamicsWorld->addRigidBody(body);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
return false;
|
body->setFlags(BT_DISABLE_WORLD_GRAVITY);
|
||||||
|
body->setRestitution(motionState->_restitution);
|
||||||
|
body->setFriction(motionState->_friction);
|
||||||
|
body->setDamping(motionState->_linearDamping, motionState->_angularDamping);
|
||||||
|
_dynamicsWorld->addRigidBody(body);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PhysicsEngine::removeObject(ObjectMotionState* motionState) {
|
bool PhysicsEngine::removeObject(ObjectMotionState* motionState) {
|
||||||
|
|
|
@ -59,7 +59,7 @@ public:
|
||||||
|
|
||||||
/// \param motionState pointer to Object's MotionState
|
/// \param motionState pointer to Object's MotionState
|
||||||
/// \return true if Object added
|
/// \return true if Object added
|
||||||
bool addObject(ObjectMotionState* motionState);
|
void addObject(const ShapeInfo& shapeInfo, btCollisionShape* shape, ObjectMotionState* motionState);
|
||||||
|
|
||||||
/// \param motionState pointer to Object's MotionState
|
/// \param motionState pointer to Object's MotionState
|
||||||
/// \return true if Object removed
|
/// \return true if Object removed
|
||||||
|
|
Loading…
Reference in a new issue