diff --git a/interface/resources/fonts/vircadia_glyphs.ttf b/interface/resources/fonts/vircadia_glyphs.ttf index b6a8c2e7ad..7d3fe9d913 100644 Binary files a/interface/resources/fonts/vircadia_glyphs.ttf and b/interface/resources/fonts/vircadia_glyphs.ttf differ diff --git a/scripts/system/create/edit.js b/scripts/system/create/edit.js index 5c488a71ee..69e2e94818 100644 --- a/scripts/system/create/edit.js +++ b/scripts/system/create/edit.js @@ -1696,7 +1696,7 @@ function recursiveDelete(entities, childrenList, deletedIDs, entityHostType) { } function unparentSelectedEntities() { - if (SelectionManager.hasSelection()) { + if (SelectionManager.hasSelection() && SelectionManager.hasUnlockedSelection()) { var selectedEntities = selectionManager.selections; var parentCheck = false; @@ -1720,6 +1720,9 @@ function unparentSelectedEntities() { } else { Window.notify("Entity unparented"); } + //Refresh + entityListTool.sendUpdate(); + selectionManager._update(false, this); } else { audioFeedback.rejection(); if (selectedEntities.length > 1) { @@ -1730,11 +1733,11 @@ function unparentSelectedEntities() { } } else { audioFeedback.rejection(); - Window.notifyEditError("You have nothing selected to unparent"); + Window.notifyEditError("You have nothing selected or the selection has locked entities."); } } function parentSelectedEntities() { - if (SelectionManager.hasSelection()) { + if (SelectionManager.hasSelection() && SelectionManager.hasUnlockedSelection()) { var selectedEntities = selectionManager.selections; if (selectedEntities.length <= 1) { audioFeedback.rejection(); @@ -1756,17 +1759,20 @@ function parentSelectedEntities() { if (parentCheck) { audioFeedback.confirmation(); Window.notify("Entities parented"); + //Refresh + entityListTool.sendUpdate(); + selectionManager._update(false, this); } else { audioFeedback.rejection(); Window.notify("Entities are already parented to last"); } } else { audioFeedback.rejection(); - Window.notifyEditError("You have nothing selected to parent"); + Window.notifyEditError("You have nothing selected or the selection has locked entities."); } } function deleteSelectedEntities() { - if (SelectionManager.hasSelection()) { + if (SelectionManager.hasSelection() && SelectionManager.hasUnlockedSelection()) { var deletedIDs = []; SelectionManager.saveProperties(); @@ -1797,6 +1803,9 @@ function deleteSelectedEntities() { pushCommandForSelections([], savedProperties); entityListTool.deleteEntities(deletedIDs); } + } else { + audioFeedback.rejection(); + Window.notifyEditError("You have nothing selected or the selection has locked entities."); } } @@ -2963,4 +2972,22 @@ function zoneSortOrder(a, b) { return 0; } +function getParentState(id) { + var state = "NONE"; + var properties = Entities.getEntityProperties(id, ["parentID"]); + var children = Entities.getChildrenIDs(id); + if (properties.parentID !== Uuid.NULL) { + if (children.length > 0) { + state = "PARENT_CHILDREN"; + } else { + state = "CHILDREN"; + } + } else { + if (children.length > 0) { + state = "PARENT"; + } + } + return state; +} + }()); // END LOCAL_SCOPE diff --git a/scripts/system/create/entityList/entityList.js b/scripts/system/create/entityList/entityList.js index 4b8163968d..252481d44d 100644 --- a/scripts/system/create/entityList/entityList.js +++ b/scripts/system/create/entityList/entityList.js @@ -190,7 +190,7 @@ EntityListTool = function(shouldUseEditTabletApp) { PROFILE("getMultipleProperties", function () { var multipleProperties = Entities.getMultipleEntityProperties(ids, ['position', 'name', 'type', 'locked', 'visible', 'renderInfo', 'modelURL', 'materialURL', 'imageURL', 'script', 'certificateID', - 'skybox.url', 'ambientLight.url']); + 'skybox.url', 'ambientLight.url', 'created', 'lastEdited']); for (var i = 0; i < multipleProperties.length; i++) { var properties = multipleProperties[i]; @@ -203,6 +203,17 @@ EntityListTool = function(shouldUseEditTabletApp) { } else if (properties.type === "Image") { url = properties.imageURL; } + + var parentStatus = getParentState(ids[i]); + var parentState = ""; + if (parentStatus === "PARENT") { + parentState = "A"; + } else if (parentStatus === "CHILDREN") { + parentState = "C"; + } else if (parentStatus === "PARENT_CHILDREN") { + parentState = "B"; + } + entities.push({ id: ids[i], name: properties.name, @@ -222,7 +233,10 @@ EntityListTool = function(shouldUseEditTabletApp) { isBaked: entityIsBaked(properties), drawCalls: (properties.renderInfo !== undefined ? valueIfDefined(properties.renderInfo.drawCalls) : ""), - hasScript: properties.script !== "" + hasScript: properties.script !== "", + parentState: parentState, + created: formatToStringDateTime(properties.created), + lastEdited: formatToStringDateTime(properties.lastEdited) }); } } @@ -242,6 +256,22 @@ EntityListTool = function(shouldUseEditTabletApp) { }); }; + function formatToStringDateTime(timestamp) { + var d = new Date(Math.floor(timestamp/1000)); + var dateTime = d.getUTCFullYear() + "-" + zeroPad((d.getUTCMonth() + 1), 2) + "-" + zeroPad(d.getUTCDate(), 2); + dateTime = dateTime + " " + zeroPad(d.getUTCHours(), 2) + ":" + zeroPad(d.getUTCMinutes(), 2) + ":" + zeroPad(d.getUTCSeconds(), 2); + dateTime = dateTime + "." + zeroPad(d.getUTCMilliseconds(), 3); + return dateTime; + } + + function zeroPad(num, size) { + num = num.toString(); + while (num.length < size) { + num = "0" + num; + } + return num; + } + function onFileSaveChanged(filename) { Window.saveFileChanged.disconnect(onFileSaveChanged); if (filename !== "") { @@ -323,6 +353,24 @@ EntityListTool = function(shouldUseEditTabletApp) { unparentSelectedEntities(); } else if (data.type === 'hmdMultiSelectMode') { hmdMultiSelectMode = data.value; + } else if (data.type === 'selectAllInBox') { + selectAllEntitiesInCurrentSelectionBox(false); + } else if (data.type === 'selectAllTouchingBox') { + selectAllEntitiesInCurrentSelectionBox(true); + } else if (data.type === 'selectParent') { + SelectionManager.selectParent(); + } else if (data.type === 'selectTopParent') { + SelectionManager.selectTopParent(); + } else if (data.type === 'addChildrenToSelection') { + SelectionManager.addChildrenToSelection(); + } else if (data.type === 'selectFamily') { + SelectionManager.selectFamily(); + } else if (data.type === 'selectTopFamily') { + SelectionManager.selectTopFamily(); + } else if (data.type === 'teleportToEntity') { + SelectionManager.teleportToEntity(); + } else if (data.type === 'moveEntitySelectionToAvatar') { + SelectionManager.moveEntitiesSelectionToAvatar(); } }; diff --git a/scripts/system/create/entityList/html/entityList.html b/scripts/system/create/entityList/html/entityList.html index 824ca380ec..b22cd87a65 100644 --- a/scripts/system/create/entityList/html/entityList.html +++ b/scripts/system/create/entityList/html/entityList.html @@ -32,19 +32,8 @@ - - - - -
- - -
-
- - -
- + +
@@ -102,5 +91,142 @@
+
+ + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + +
+ diff --git a/scripts/system/create/entityList/html/js/entityList.js b/scripts/system/create/entityList/html/js/entityList.js index aa40d5286f..be79593511 100644 --- a/scripts/system/create/entityList/html/js/entityList.js +++ b/scripts/system/create/entityList/html/js/entityList.js @@ -47,6 +47,14 @@ const COLUMNS = { alwaysShown: true, defaultSortOrder: ASCENDING_SORT, }, + parentState: { + columnHeader: "A", + vglyph: true, + dropdownLabel: "Hierarchy", + propertyID: "parentState", + initialWidth: 0.08, + defaultSortOrder: DESCENDING_SORT, + }, name: { columnHeader: "Name", propertyID: "name", @@ -134,6 +142,20 @@ const COLUMNS = { initialWidth: 0.06, defaultSortOrder: DESCENDING_SORT, }, + created: { + columnHeader: "Created (UTC)", + dropdownLabel: "Creation Date", + propertyID: "created", + initialWidth: 0.38, + defaultSortOrder: DESCENDING_SORT, + }, + lastEdited: { + columnHeader: "Modified (UTC)", + dropdownLabel: "Modification Date", + propertyID: "lastEdited", + initialWidth: 0.38, + defaultSortOrder: DESCENDING_SORT, + }, }; const FILTER_TYPES = [ @@ -200,7 +222,10 @@ let elEntityTable, elRefresh, elToggleLocked, elToggleVisible, - elHmdMultiSelect, + elActionsMenu, + elSelectionMenu, + elMenuBackgroundOverlay, + elHmdMultiSelect, elHmdCopy, elHmdCut, elHmdPaste, @@ -210,6 +235,18 @@ let elEntityTable, elParent, elUnparent, elDelete, + elMoveEntitySelectionToAvatar, + elSelectAll, + elSelectInverse, + elSelectNone, + elSelectAllInBox, + elSelectAllTouchingBox, + elSelectParent, + elSelectTopParent, + elAddChildrenToSelection, + elSelectFamily, + elSelectTopFamily, + elTeleportToEntity, elFilterTypeMultiselectBox, elFilterTypeText, elFilterTypeOptions, @@ -252,8 +289,11 @@ function loaded() { elEntityTableScroll = document.getElementById("entity-table-scroll"); elRefresh = document.getElementById("refresh"); elToggleLocked = document.getElementById("locked"); - elToggleVisible = document.getElementById("visible"); + elToggleVisible = document.getElementById("visible"); elHmdMultiSelect = document.getElementById("hmdmultiselect"); + elActionsMenu = document.getElementById("actions"); + elSelectionMenu = document.getElementById("selection"); + elMenuBackgroundOverlay = document.getElementById("menuBackgroundOverlay"); elHmdCopy = document.getElementById("hmdcopy"); elHmdCut = document.getElementById("hmdcut"); elHmdPaste = document.getElementById("hmdpaste"); @@ -263,6 +303,18 @@ function loaded() { elParent = document.getElementById("parent"); elUnparent = document.getElementById("unparent"); elDelete = document.getElementById("delete"); + elMoveEntitySelectionToAvatar = document.getElementById("moveEntitySelectionToAvatar"); + elSelectAll = document.getElementById("selectall"); + elSelectInverse = document.getElementById("selectinverse"); + elSelectNone = document.getElementById("selectnone"); + elSelectAllInBox = document.getElementById("selectallinbox"); + elSelectAllTouchingBox = document.getElementById("selectalltouchingbox"); + elSelectParent = document.getElementById("selectparent"); + elSelectTopParent = document.getElementById("selecttopparent"); + elAddChildrenToSelection = document.getElementById("addchildrentoselection"); + elSelectFamily = document.getElementById("selectfamily"); + elSelectTopFamily = document.getElementById("selecttopfamily"); + elTeleportToEntity = document.getElementById("teleport-to-entity"); elFilterTypeMultiselectBox = document.getElementById("filter-type-multiselect-box"); elFilterTypeText = document.getElementById("filter-type-text"); elFilterTypeOptions = document.getElementById("filter-type-options"); @@ -300,32 +352,146 @@ function loaded() { } EventBridge.emitWebEvent(JSON.stringify({ type: 'hmdMultiSelectMode', value: hmdMultiSelectMode })); }; + elActionsMenu.onclick = function() { + document.getElementById("menuBackgroundOverlay").style.display = "block"; + document.getElementById("actions-menu").style.display = "block"; + }; + elSelectionMenu.onclick = function() { + document.getElementById("menuBackgroundOverlay").style.display = "block"; + document.getElementById("selection-menu").style.display = "block"; + }; + elMenuBackgroundOverlay.onclick = function() { + closeAllEntityListMenu(); + }; elHmdCopy.onclick = function() { EventBridge.emitWebEvent(JSON.stringify({ type: 'copy' })); + closeAllEntityListMenu(); }; elHmdCut.onclick = function() { EventBridge.emitWebEvent(JSON.stringify({ type: 'cut' })); + closeAllEntityListMenu(); }; elHmdPaste.onclick = function() { EventBridge.emitWebEvent(JSON.stringify({ type: 'paste' })); + closeAllEntityListMenu(); }; elHmdDuplicate.onclick = function() { EventBridge.emitWebEvent(JSON.stringify({ type: 'duplicate' })); - }; + closeAllEntityListMenu(); + }; elParent.onclick = function() { EventBridge.emitWebEvent(JSON.stringify({ type: 'parent' })); + closeAllEntityListMenu(); }; elUnparent.onclick = function() { EventBridge.emitWebEvent(JSON.stringify({ type: 'unparent' })); + closeAllEntityListMenu(); }; elUndo.onclick = function() { EventBridge.emitWebEvent(JSON.stringify({ type: 'undo' })); + closeAllEntityListMenu(); }; elRedo.onclick = function() { EventBridge.emitWebEvent(JSON.stringify({ type: 'redo' })); + closeAllEntityListMenu(); }; elDelete.onclick = function() { EventBridge.emitWebEvent(JSON.stringify({ type: 'delete' })); + closeAllEntityListMenu(); + }; + elMoveEntitySelectionToAvatar.onclick = function() { + EventBridge.emitWebEvent(JSON.stringify({ type: 'moveEntitySelectionToAvatar' })); + closeAllEntityListMenu(); + }; + elSelectAll.onclick = function() { + + let visibleEntityIDs = visibleEntities.map(visibleEntity => visibleEntity.id); + let selectionIncludesAllVisibleEntityIDs = visibleEntityIDs.every(visibleEntityID => { + return selectedEntities.includes(visibleEntityID); + }); + + let selection = []; + + if (!selectionIncludesAllVisibleEntityIDs) { + selection = visibleEntityIDs; + } + + updateSelectedEntities(selection, false); + + EventBridge.emitWebEvent(JSON.stringify({ + "type": "selectionUpdate", + "focus": false, + "entityIds": selection + })); + + closeAllEntityListMenu(); + }; + elSelectInverse.onclick = function() { + let visibleEntityIDs = visibleEntities.map(visibleEntity => visibleEntity.id); + let selectionIncludesAllVisibleEntityIDs = visibleEntityIDs.every(visibleEntityID => { + return selectedEntities.includes(visibleEntityID); + }); + + let selection = []; + + if (!selectionIncludesAllVisibleEntityIDs) { + visibleEntityIDs.forEach(function(id) { + if (!selectedEntities.includes(id)) { + selection.push(id); + } + }); + } + + updateSelectedEntities(selection, false); + + EventBridge.emitWebEvent(JSON.stringify({ + "type": "selectionUpdate", + "focus": false, + "entityIds": selection + })); + + closeAllEntityListMenu(); + }; + elSelectNone.onclick = function() { + updateSelectedEntities([], false); + EventBridge.emitWebEvent(JSON.stringify({ + "type": "selectionUpdate", + "focus": false, + "entityIds": [] + })); + closeAllEntityListMenu(); + }; + elSelectAllInBox.onclick = function() { + EventBridge.emitWebEvent(JSON.stringify({ type: 'selectAllInBox' })); + closeAllEntityListMenu(); + }; + elSelectAllTouchingBox.onclick = function() { + EventBridge.emitWebEvent(JSON.stringify({ type: 'selectAllTouchingBox' })); + closeAllEntityListMenu(); + }; + elSelectParent.onclick = function() { + EventBridge.emitWebEvent(JSON.stringify({ type: 'selectParent' })); + closeAllEntityListMenu(); + }; + elSelectTopParent.onclick = function() { + EventBridge.emitWebEvent(JSON.stringify({ type: 'selectTopParent' })); + closeAllEntityListMenu(); + }; + elAddChildrenToSelection.onclick = function() { + EventBridge.emitWebEvent(JSON.stringify({ type: 'addChildrenToSelection' })); + closeAllEntityListMenu(); + }; + elSelectFamily.onclick = function() { + EventBridge.emitWebEvent(JSON.stringify({ type: 'selectFamily' })); + closeAllEntityListMenu(); + }; + elSelectTopFamily.onclick = function() { + EventBridge.emitWebEvent(JSON.stringify({ type: 'selectTopFamily' })); + closeAllEntityListMenu(); + }; + elTeleportToEntity.onclick = function () { + EventBridge.emitWebEvent(JSON.stringify({ type: "teleportToEntity" })); + closeAllEntityListMenu(); }; elToggleSpaceMode.onclick = function() { EventBridge.emitWebEvent(JSON.stringify({ type: 'toggleSpaceMode' })); @@ -384,9 +550,12 @@ function loaded() { elTh.setAttribute("id", thID); elTh.setAttribute("columnIndex", columnIndex); elTh.setAttribute("columnID", columnID); - if (columnData.glyph) { + if (columnData.glyph || columnData.vglyph) { let elGlyph = document.createElement("span"); elGlyph.className = "glyph"; + if (columnData.vglyph) { + elGlyph.className = "vglyph"; + } elGlyph.innerHTML = columnData.columnHeader; elTh.appendChild(elGlyph); } else { @@ -686,10 +855,13 @@ function loaded() { isBaked: entity.isBaked, drawCalls: displayIfNonZero(entity.drawCalls), hasScript: entity.hasScript, + parentState: entity.parentState, + created: entity.created, + lastEdited: entity.lastEdited, elRow: null, // if this entity has a visible row element assigned to it selected: false // if this entity is selected for edit regardless of having a visible row }; - + entities.push(entityData); entitiesByID[entityData.id] = entityData; }); @@ -871,7 +1043,7 @@ function loaded() { function updateSelectedEntities(selectedIDs, autoScroll) { let notFound = false; - + // reset all currently selected entities and their rows first selectedEntities.forEach(function(id) { let entity = entitiesByID[id]; @@ -882,7 +1054,7 @@ function loaded() { } } }); - + // then reset selected entities list with newly selected entities and set them selected selectedEntities = []; selectedIDs.forEach(function(id) { @@ -945,6 +1117,8 @@ function loaded() { let elCell = elRow.childNodes[i]; if (column.data.glyph) { elCell.innerHTML = itemData[column.data.propertyID] ? column.data.columnHeader : null; + } else if (column.data.vglyph) { + elCell.innerHTML = itemData[column.data.propertyID]; } else { let value = itemData[column.data.propertyID]; if (column.data.format) { @@ -1032,6 +1206,9 @@ function loaded() { let column = columnsByID[columnID]; let visible = column.elTh.style.visibility !== "hidden"; let className = column.data.glyph ? "glyph" : ""; + if (column.data.vglyph) { + className = "vglyph"; + } className += visible ? "" : " hidden"; return className; } @@ -1381,7 +1558,7 @@ function loaded() { break; } - if (controlKey && keyCodeString === "A") { + if (controlKey && !shiftKey && !altKey && keyCodeString === "A") { let visibleEntityIDs = visibleEntities.map(visibleEntity => visibleEntity.id); let selectionIncludesAllVisibleEntityIDs = visibleEntityIDs.every(visibleEntityID => { return selectedEntities.includes(visibleEntityID); @@ -1404,6 +1581,32 @@ function loaded() { return; } + if (controlKey && !shiftKey && !altKey && keyCodeString === "I") { + let visibleEntityIDs = visibleEntities.map(visibleEntity => visibleEntity.id); + let selectionIncludesAllVisibleEntityIDs = visibleEntityIDs.every(visibleEntityID => { + return selectedEntities.includes(visibleEntityID); + }); + + let selection = []; + + if (!selectionIncludesAllVisibleEntityIDs) { + visibleEntityIDs.forEach(function(id) { + if (!selectedEntities.includes(id)) { + selection.push(id); + } + }); + } + + updateSelectedEntities(selection); + + EventBridge.emitWebEvent(JSON.stringify({ + "type": "selectionUpdate", + "focus": false, + "entityIds": selection + })); + + return; + } EventBridge.emitWebEvent(JSON.stringify({ type: 'keyUpEvent', @@ -1454,16 +1657,8 @@ function loaded() { } else if (data.type === "confirmHMDstate") { if (data.isHmd) { document.getElementById("hmdmultiselect").style.display = "inline"; - document.getElementById("hmdcopy").style.display = "inline"; - document.getElementById("hmdcut").style.display = "inline"; - document.getElementById("hmdpaste").style.display = "inline"; - document.getElementById("hmdduplicate").style.display = "inline"; } else { - document.getElementById("hmdmultiselect").style.display = "none"; - document.getElementById("hmdcopy").style.display = "none"; - document.getElementById("hmdcut").style.display = "none"; - document.getElementById("hmdpaste").style.display = "none"; - document.getElementById("hmdduplicate").style.display = "none"; + document.getElementById("hmdmultiselect").style.display = "none"; } } }); @@ -1489,4 +1684,11 @@ function loaded() { $(window).blur(function() { entityListContextMenu.close(); }); + + function closeAllEntityListMenu() { + document.getElementById("menuBackgroundOverlay").style.display = "none"; + document.getElementById("selection-menu").style.display = "none"; + document.getElementById("actions-menu").style.display = "none"; + } + } diff --git a/scripts/system/create/entityProperties/html/js/entityProperties.js b/scripts/system/create/entityProperties/html/js/entityProperties.js index 8364d5b155..f3f92a887e 100644 --- a/scripts/system/create/entityProperties/html/js/entityProperties.js +++ b/scripts/system/create/entityProperties/html/js/entityProperties.js @@ -1618,7 +1618,8 @@ const GROUPS = [ type: "vec3", vec3Type: "pyr", multiplier: DEGREES_TO_RADIANS, - decimals: 4, + decimals: 6, + step: 1, subLabels: [ "x", "y", "z" ], unit: "deg/s", propertyID: "localAngularVelocity", diff --git a/scripts/system/create/entitySelectionTool/entitySelectionTool.js b/scripts/system/create/entitySelectionTool/entitySelectionTool.js index 0250ead0a9..ffa828affe 100644 --- a/scripts/system/create/entitySelectionTool/entitySelectionTool.js +++ b/scripts/system/create/entitySelectionTool/entitySelectionTool.js @@ -19,6 +19,7 @@ const SPACE_LOCAL = "local"; const SPACE_WORLD = "world"; const HIGHLIGHT_LIST_NAME = "editHandleHighlightList"; +const MIN_DISTANCE_TO_REZ_FROM_AVATAR = 3; Script.include([ "../../libraries/controllers.js", @@ -26,7 +27,6 @@ Script.include([ "../../libraries/utils.js" ]); - function deepCopy(v) { return JSON.parse(JSON.stringify(v)); } @@ -636,6 +636,141 @@ SelectionManager = (function() { } }; + that.teleportToEntity = function() { + if (that.hasSelection()) { + var distanceFromTarget = MIN_DISTANCE_TO_REZ_FROM_AVATAR + Math.max(Math.max(that.worldDimensions.x, that.worldDimensions.y), that.worldDimensions.z); + var teleportTargetPosition = Vec3.sum(that.worldPosition, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0, z: distanceFromTarget })); + MyAvatar.goToLocation(teleportTargetPosition, false); + } else { + audioFeedback.rejection(); + Window.notifyEditError("You have nothing selected."); + } + }; + + that.moveEntitiesSelectionToAvatar = function() { + if (that.hasSelection() && that.hasUnlockedSelection()) { + that.saveProperties(); + var distanceFromTarget = MIN_DISTANCE_TO_REZ_FROM_AVATAR + Math.max(Math.max(that.worldDimensions.x, that.worldDimensions.y), that.worldDimensions.z); + var targetPosition = Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0, z: -distanceFromTarget })); + // editing a parent will cause all the children to automatically follow along, so don't + // edit any entity who has an ancestor in that.selections + var toMove = that.selections.filter(function (selection) { + if (that.selections.indexOf(that.savedProperties[selection].parentID) >= 0) { + return false; // a parent is also being moved, so don't issue an edit for this entity + } else { + return true; + } + }); + for (var i = 0; i < toMove.length; i++) { + var id = toMove[i]; + var properties = that.savedProperties[id]; + var relativePosition = Vec3.subtract(properties.position, that.worldPosition); + var newPosition = Vec3.sum(relativePosition, targetPosition); + Entities.editEntity(id, { "position": newPosition }); + } + that._update(false, this); + } else { + audioFeedback.rejection(); + Window.notifyEditError("You have nothing selected or the selection has locked entities."); + } + }; + + that.selectParent = function() { + if (that.hasSelection()) { + var currentSelection = that.selections; + that.selections = []; + for (var i = 0; i < currentSelection.length; i++) { + var properties = Entities.getEntityProperties(currentSelection[i], ['parentID']); + if (properties.parentID !== Uuid.NULL) { + that.selections.push(properties.parentID); + } + } + that._update(true, this); + } else { + audioFeedback.rejection(); + Window.notifyEditError("You have nothing selected."); + } + }; + + that.selectTopParent = function() { + if (that.hasSelection()) { + var currentSelection = that.selections; + that.selections = []; + for (var i = 0; i < currentSelection.length; i++) { + var topParentId = getTopParent(currentSelection[i]); + if (topParentId !== Uuid.NULL) { + that.selections.push(topParentId); + } + } + that._update(true, this); + } else { + audioFeedback.rejection(); + Window.notifyEditError("You have nothing selected."); + } + }; + + function getTopParent(id) { + var topParentId = Uuid.NULL; + var properties = Entities.getEntityProperties(id, ['parentID']); + if (properties.parentID === Uuid.NULL) { + topParentId = id; + } else { + topParentId = getTopParent(properties.parentID); + } + return topParentId; + } + + that.addChildrenToSelection = function() { + if (that.hasSelection()) { + for (var i = 0; i < that.selections.length; i++) { + var childrenIDs = Entities.getChildrenIDs(that.selections[i]); + var collectNewChildren; + var j; + var k = 0; + do { + collectNewChildren = Entities.getChildrenIDs(childrenIDs[k]); + if (collectNewChildren.length > 0) { + for (j = 0; j < collectNewChildren.length; j++) { + childrenIDs.push(collectNewChildren[j]); + } + } + k++; + } while (k < childrenIDs.length); + if (childrenIDs.length > 0) { + for (j = 0; j < childrenIDs.length; j++) { + that.selections.push(childrenIDs[j]); + } + } + } + that._update(true, this); + } else { + audioFeedback.rejection(); + Window.notifyEditError("You have nothing selected."); + } + }; + + that.hasUnlockedSelection = function() { + var selectionNotLocked = true; + for (var i = 0; i < that.selections.length; i++) { + var properties = Entities.getEntityProperties(that.selections[i], ['locked']); + if (properties.locked) { + selectionNotLocked = false; + break; + } + } + return selectionNotLocked; + }; + + that.selectFamily = function() { + that.selectParent(); + that.addChildrenToSelection(); + }; + + that.selectTopFamily = function() { + that.selectTopParent(); + that.addChildrenToSelection(); + }; + return that; })(); @@ -660,8 +795,10 @@ SelectionDisplay = (function() { const COLOR_HOVER = { red: 255, green: 220, blue: 82 }; const COLOR_DUPLICATOR = { red: 162, green: 0, blue: 255 }; const COLOR_ROTATE_CURRENT_RING = { red: 255, green: 99, blue: 9 }; - const COLOR_BOUNDING_EDGE = { red: 128, green: 128, blue: 128 }; - const COLOR_SCALE_CUBE = { red: 160, green: 160, blue: 160 }; + const COLOR_BOUNDING_EDGE = { red: 160, green: 160, blue: 160 }; + const COLOR_BOUNDING_EDGE_PARENT = { red: 194, green: 123, blue: 0 }; + const COLOR_BOUNDING_EDGE_CHILDREN = { red: 0, green: 168, blue: 214 }; + const COLOR_SCALE_CUBE = { red: 192, green: 192, blue: 192 }; const COLOR_DEBUG_PICK_PLANE = { red: 255, green: 255, blue: 255 }; const COLOR_DEBUG_PICK_PLANE_HIT = { red: 255, green: 165, blue: 0 }; @@ -1791,6 +1928,18 @@ SelectionDisplay = (function() { var rotationZ = Quat.multiply(rotation, localRotationZ); worldRotationZ = rotationZ; + var handleBoundingBoxColor = COLOR_BOUNDING_EDGE; + if (SelectionManager.selections.length === 1) { + var parentState = getParentState(SelectionManager.selections[0]); + if (parentState === "CHILDREN") { + handleBoundingBoxColor = COLOR_BOUNDING_EDGE_CHILDREN; + } else { + if (parentState === "PARENT" || parentState === "PARENT_CHILDREN") { + handleBoundingBoxColor = COLOR_BOUNDING_EDGE_PARENT; + } + } + } + var selectionBoxGeometry = { position: position, rotation: rotation, @@ -1912,6 +2061,7 @@ SelectionDisplay = (function() { Entities.editEntity(handleBoundingBox, { position: position, rotation: rotation, + color: handleBoundingBoxColor, dimensions: dimensions }); diff --git a/scripts/system/create/qml/NewMaterialDialog.qml b/scripts/system/create/qml/NewMaterialDialog.qml index 3cc619e176..e08ca868b6 100644 --- a/scripts/system/create/qml/NewMaterialDialog.qml +++ b/scripts/system/create/qml/NewMaterialDialog.qml @@ -55,7 +55,7 @@ Rectangle { Text { id: text1 - text: qsTr("Material URL (Optional)") + text: qsTr("Material URL (Optional)") color: "#ffffff" font.pixelSize: 12 } diff --git a/scripts/system/create/qml/NewModelDialog.qml b/scripts/system/create/qml/NewModelDialog.qml index dd4ef3c8ad..758706a79b 100644 --- a/scripts/system/create/qml/NewModelDialog.qml +++ b/scripts/system/create/qml/NewModelDialog.qml @@ -55,7 +55,7 @@ Rectangle { Text { id: text1 - text: qsTr("Model URL") + text: qsTr("Model URL (.fbx, .fst, .glb, .gltf, .obj, .gz)") color: "#ffffff" font.pixelSize: 12 } diff --git a/scripts/system/html/css/edit-style.css b/scripts/system/html/css/edit-style.css index 8a381ff4ad..1f1fb9c86a 100644 --- a/scripts/system/html/css/edit-style.css +++ b/scripts/system/html/css/edit-style.css @@ -415,6 +415,13 @@ input[type=button].glyph, button.hifi-edit-button.glyph { padding: 0; } +input[type=button].normal, button.hifi-edit-button.normal { + font-family: FiraSans-SemiBold; + font-size: 15px; + text-transform: none; + padding: 0; +} + input[type=button].vglyph, button.hifi-edit-button.vglyph { font-family: Vircadia-Glyphs; font-size: 20px; @@ -1236,7 +1243,6 @@ textarea:enabled[scrolling="true"]::-webkit-resizer { background: #2e2e2e url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAACKSURBVChTjdAxDsMgDAXQT4UYuQIzCwsSKxsSJ4YDoByDY7AwUOG2aZMQqX+xhd9gzIwxA3/k8a7LCCFgraX+Fk4UY4RSCoyxNfwgzjlyzhhjXOEvSimhtUbvB3hGUkp472m2wxUKIaD3TnOCd6jWim3bvlBrfdjJOUeolEJoZj/4PMH83bl/BXgCWSs2Z09IjgoAAAAASUVORK5CYII=) no-repeat bottom right; } - div#grid-section, body#entity-list-body { padding-bottom: 0; margin: 16px; @@ -1267,12 +1273,6 @@ div#grid-section, body#entity-list-body { border-bottom-left-radius: 0; } -#delete { - float: right; - margin-right: 0; - background-color: #ff0000; -} - #entity-list { position: relative; /* New positioning context. */ } @@ -1448,6 +1448,11 @@ input[type=button]#export { font-size: 15px; } +#entity-table-scroll .vglyph { + font-family: Vircadia-Glyphs; + font-size: 15px; +} + #entity-table { margin-top: -28px; margin-bottom: -18px; @@ -1460,7 +1465,7 @@ input[type=button]#export { background: none; } -#entity-table .glyph { +#entity-table .glyph .vglyph { margin: 0 -2px 0 -2px; vertical-align: middle; } @@ -1493,11 +1498,11 @@ input[type=button]#export { outline: none; } -#entity-table th .glyph { +#entity-table th .glyph .vglyph { position: relative; left: 4px; } -#entity-table th .glyph + .sort-order { +#entity-table th .glyph .vglyph + .sort-order { position: relative; left: 4px; } @@ -1524,7 +1529,7 @@ input[type=button]#export { #entity-table td { box-sizing: border-box; } -#entity-table td.glyph { +#entity-table td .glyph .vglyph { text-align: center; padding: 0; } @@ -1860,3 +1865,71 @@ div.multiZoneSelToolbar { padding: 0px; } +#menuBackgroundOverlay{ + background-color:transparent; + position:fixed; + width: 100%; + height: 100%; + top:0; + left:0; + right:0; + bottom:0; + display:none; +} + +div.entity-list-menu { + position: fixed; + display: none; + width: 70%; + height: 30px; + top: 42px; + left: 150px; + right: 0; + bottom: 0; + border-style: solid; + border-color: #505050; + border-width: 1px; + background-color: #c0c0c0; + z-index: 2; + cursor: pointer; +} + +div.menu-separator{ + width: 90%; + height: 2px; + background-color: #505050; + } + +button.menu-button { + font-family: FiraSans-SemiBold; + font-size: 15px; + width: 100%; + height: auto; + border-radius: 0; + padding: 6px; + text-align: left; + background-color: #c0c0c0; + border: none; +} + +button.menu-button:hover { + background-color: #00B4EF; + border: none; +} + +button.menu-button:active { + background-color: #00B4EF; + border: none; +} + +div.menu-item { + width: 100%; +} + +div.menu-item-caption { + float: left; +} + +div.menu-item-shortcut { + float: right; +}