Merge pull request #15360 from thoys/feat/create/editMultipleProperties

Case 21228: [Create App] allow editing properties of multiple entities simultaneously
This commit is contained in:
Shannon Romano 2019-04-19 13:32:59 -07:00 committed by GitHub
commit 71ca653498
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 1111 additions and 621 deletions

View file

@ -2363,41 +2363,62 @@ var PropertiesTool = function (opts) {
}
var i, properties, dY, diff, newPosition;
if (data.type === "update") {
if (selectionManager.selections.length > 1) {
for (i = 0; i < selectionManager.selections.length; i++) {
Entities.editEntity(selectionManager.selections[i], data.properties);
if (data.properties || data.propertiesMap) {
var propertiesMap = data.propertiesMap;
if (propertiesMap === undefined) {
propertiesMap = [{
entityIDs: data.ids,
properties: data.properties,
}];
}
} else if (data.properties) {
if (data.properties.dynamic === false) {
// this object is leaving dynamic, so we zero its velocities
data.properties.localVelocity = Vec3.ZERO;
data.properties.localAngularVelocity = Vec3.ZERO;
}
if (data.properties.rotation !== undefined) {
data.properties.rotation = Quat.fromVec3Degrees(data.properties.rotation);
}
if (data.properties.localRotation !== undefined) {
data.properties.localRotation = Quat.fromVec3Degrees(data.properties.localRotation);
}
if (data.properties.emitOrientation !== undefined) {
data.properties.emitOrientation = Quat.fromVec3Degrees(data.properties.emitOrientation);
}
if (data.properties.keyLight !== undefined && data.properties.keyLight.direction !== undefined) {
var currentKeyLightDirection = Vec3.toPolar(Entities.getEntityProperties(selectionManager.selections[0], ['keyLight.direction']).keyLight.direction);
if (data.properties.keyLight.direction.x === undefined) {
data.properties.keyLight.direction.x = currentKeyLightDirection.x;
var sendListUpdate = false;
propertiesMap.forEach(function(propertiesObject) {
var properties = propertiesObject.properties;
var updateEntityIDs = propertiesObject.entityIDs;
if (properties.dynamic === false) {
// this object is leaving dynamic, so we zero its velocities
properties.localVelocity = Vec3.ZERO;
properties.localAngularVelocity = Vec3.ZERO;
}
if (data.properties.keyLight.direction.y === undefined) {
data.properties.keyLight.direction.y = currentKeyLightDirection.y;
if (properties.rotation !== undefined) {
properties.rotation = Quat.fromVec3Degrees(properties.rotation);
}
data.properties.keyLight.direction = Vec3.fromPolar(data.properties.keyLight.direction.x, data.properties.keyLight.direction.y);
}
Entities.editEntity(selectionManager.selections[0], data.properties);
if (data.properties.name !== undefined || data.properties.modelURL !== undefined || data.properties.materialURL !== undefined ||
data.properties.visible !== undefined || data.properties.locked !== undefined) {
if (properties.localRotation !== undefined) {
properties.localRotation = Quat.fromVec3Degrees(properties.localRotation);
}
if (properties.emitOrientation !== undefined) {
properties.emitOrientation = Quat.fromVec3Degrees(properties.emitOrientation);
}
if (properties.keyLight !== undefined && properties.keyLight.direction !== undefined) {
var currentKeyLightDirection = Vec3.toPolar(Entities.getEntityProperties(selectionManager.selections[0], ['keyLight.direction']).keyLight.direction);
if (properties.keyLight.direction.x === undefined) {
properties.keyLight.direction.x = currentKeyLightDirection.x;
}
if (properties.keyLight.direction.y === undefined) {
properties.keyLight.direction.y = currentKeyLightDirection.y;
}
properties.keyLight.direction = Vec3.fromPolar(properties.keyLight.direction.x, properties.keyLight.direction.y);
}
updateEntityIDs.forEach(function (entityID) {
Entities.editEntity(entityID, properties);
});
if (properties.name !== undefined || properties.modelURL !== undefined || properties.materialURL !== undefined ||
properties.visible !== undefined || properties.locked !== undefined) {
sendListUpdate = true;
}
});
if (sendListUpdate) {
entityListTool.sendUpdate();
}
}
if (data.onlyUpdateEntities) {
blockPropertyUpdates = true;
} else {
@ -2407,9 +2428,9 @@ var PropertiesTool = function (opts) {
selectionManager._update(false, this);
blockPropertyUpdates = false;
} else if (data.type === 'saveUserData' || data.type === 'saveMaterialData') {
//the event bridge and json parsing handle our avatar id string differently.
var actualID = data.id.split('"')[1];
Entities.editEntity(actualID, data.properties);
data.ids.forEach(function(entityID) {
Entities.editEntity(entityID, data.properties);
});
} else if (data.type === "showMarketplace") {
showMarketplace();
} else if (data.type === "action") {

View file

@ -193,8 +193,8 @@ td {
}
td.hidden {
padding-left: 0px;
padding-right: 0px;
padding-left: 0;
padding-right: 0;
}
td.url {
@ -262,6 +262,42 @@ input[type="text"] {
width: 100%;
}
input.multi-diff:not(:focus) + span.multi-diff,
textarea.multi-diff:not(:focus) + span.multi-diff,
.draggable-number.multi-diff>input:not(:focus)+span.multi-diff,
dl>dt.multi-diff:not(:focus) + span.multi-diff {
visibility: visible;
position: absolute;
display: inline-block;
z-index: 2;
top: 7.5px;
left: 20px;
max-width: 50px;
min-width: 10px;
width: 50%;
height: 13px;
background-image: linear-gradient(transparent 0%, transparent 10%, #afafaf 10%, #afafaf 20%, transparent 20%, transparent 45%, #afafaf 45%, #afafaf 55%, transparent 55%, transparent 80%, #afafaf 80%, #afafaf 90%, transparent 90%, transparent 100%);
background-repeat: no-repeat;
pointer-events: none;
}
input.multi-diff:not(:focus)::-webkit-input-placeholder, input.multi-diff:not(:focus) {
color: transparent;
}
.draggable-number.multi-diff .text {
color: transparent;
}
.dropdown > span.multi-diff {
top: 5px;
left: 10px;
}
.text, .url, .texture, .textarea {
position: relative;
}
input[type="search"] {
height: 28px;
width: 100%;
@ -333,7 +369,7 @@ input[type=range]::-webkit-slider-thumb {
input[type=range]::-webkit-slider-thumb:hover {
background-color: white;
}
input[type=range]:focus { /*#252525*/
input[type=range]:focus {
outline: none;
}
@ -443,6 +479,21 @@ input[type=checkbox]:checked + label {
input[type=checkbox]:checked + label:hover {
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAYAAAAfSC3RAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAEySURBVDhPnZLPSsNAEMa/XVPBCE0RhNy0OarP4Av4AD6JB0GwVBA8efBBxHsgh4CQswcRoUIpiIpVAm3zZ5M4szFSbQPBH3xkJvNNZskOer2eLIriKM/ze1JOcS1UHmdZduF5ngEKjr/fN4Z6+oKerwA2gxC4HAFPEWVLsAzgZAvYt3Q6Enw6jg7uBAaTFMNwhpnKdbXCkAJdy8ROu4XrXW2HTJIErHcFDD6nC02Mom8PwymeE2gvS0ZRBBaTlsOXEmdlrfLLOI7Bakrl/zWxCT8T/904f9QW/b06qtrCUdtFCqdjYs2Q2jAPX8c2XQd7Kr/wfV8vwIPs4Ga1ixe5Xrr/YFLTYfKIvWzM6ZtwXZdX7lxXG0L+sxXHcW5t254opRzawQ0S72+dPmjTroIgOP0CQSMt5LDn1T8AAAAASUVORK5CYII=);
}
input.multi-diff[type=checkbox] + label {
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAYAAAAfSC3RAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAFbSURBVDhPY2xoaGD68+dPMSMjY9L////VgTQjAw4AlH8PxLOPHj1azWxjY1MBVNsBFBfBpwkEgNKcQGwtJyfHyALkF4IE34gqM9zU9WT4wicG4mIA1l/fGIyOL2EQeP8EZEAiC5AQBUlcMQ5ieMXIwfDo9SeG73/+gRXDAAsTI4Pd9wdgTVAgw/Tv3z8GEP7Jwctw78M3DE0goPr6BoPludVgdTAM1wgCv//9B9PIQOPNDYaAGxtRNIEw03+gYhDGBtSBNgVc3wiWR8dM//4DTQBidKD++jqD//X1YDlsGMWpMKD26jqD79V1GM5DxihOZQWGntqrawy+V9ZiOA0dw21k/f6JwerzHQbvS2swTMeGGfPz8l8BLRP9KizDwP0WHk+EwGum/3//94M8y/nmEdZAwIb//vs7g/nk6ZPHzE3NvwITrxLDfwYhIAamZpz4PcM/hslXrl6pBwAmfz5iaAlAuAAAAABJRU5ErkJggg==);
}
input.multi-diff[type=checkbox] + label:hover {
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAYAAAAfSC3RAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAFPSURBVDhPjZJBSwJBHMXfrG6rWEkl1MFDGOihDn2JIIrqc3QJunbyFhUkRieD+hYepWteuxctXiJ1Q5xmdmZ3bWZTUHezfvAu/3lv3n+HRblcTrbb7fN+v/8eBMFgFpxz13Gcu3q9bqHb7V4M5/9GhatE3cIsy0o99YBKC3jliCWbBK43gK0MoDI9otfTB/vPBC9Uwu4xMC8IzSOSBsFxIYNqMTGcAIYQAlodD3j5/IqENIc5gqt1P/SNZKhaXR0a5E/5BEcrwH1xEHrGZbiuC604DpZ81AoiPJ/WROM4e4sSt3kaaRopNrg7z1FZdSLmcU2saqrX20lTXC5/RFabFmk2m+GLnBnbWJMOThJv4SV/QRqNBjNNM9UiGeQHdDiejZSSG5TSG71zjnVivyVOKlNLlEqlx+xCds7zvU31G6Z938dvEq4QjLMH27ZPvwHFVYQr3h7uHwAAAABJRU5ErkJggg==);
}
.rgb.fstuple .color-picker.multi-diff:after {
width: 20px;
height: 20px;
content: ' ';
background: darkgray;
display: flex;
clip-path: polygon(0 0, 0 100%, 100% 100%);
}
.icon-input input {
position: relative;
@ -535,7 +586,6 @@ input[type=checkbox]:checked + label:hover {
div.section-header, hr {
display: flex;
flex-flow: row nowrap;
padding: 10px 16px;
font-family: Raleway-Regular;
font-size: 12px;
@ -731,8 +781,6 @@ span.indented {
.dropdown dl {
clear: both;
cursor: pointer;
}
.dropdown dl {
font-family: FiraSans-SemiBold;
font-size: 15px;
width: 292px;
@ -741,7 +789,10 @@ span.indented {
color: #afafaf;
background: #575757;
position: relative;
display: flex;
align-items: center;
}
.dropdown dl[dropped="true"] {
color: #404040;
background: linear-gradient(#afafaf, #afafaf);
@ -878,6 +929,8 @@ div.refresh {
div.refresh input[type="button"] {
float: right;
margin-right: -44px;
position: relative;
left: 10px;
}
.color-picker {
@ -930,6 +983,8 @@ div.refresh input[type="button"] {
position: relative;
height: 28px;
flex: 0 1 124px;
display: flex;
align-items: center;
}
.draggable-number .text {
@ -1735,3 +1790,7 @@ input[type=number].hide-spinner::-webkit-inner-spin-button {
-webkit-appearance: none;
visibility: hidden;
}
div.jsoneditor-menu a.jsoneditor-poweredBy {
display: none;
}

View file

@ -13,6 +13,7 @@ function DraggableNumber(min, max, step, decimals, dragStart, dragEnd) {
this.min = min;
this.max = max;
this.step = step !== undefined ? step : 1;
this.multiDiffModeEnabled = false;
this.decimals = decimals;
this.dragStartFunction = dragStart;
this.dragEndFunction = dragEnd;
@ -20,6 +21,7 @@ function DraggableNumber(min, max, step, decimals, dragStart, dragEnd) {
this.initialMouseEvent = null;
this.lastMouseEvent = null;
this.valueChangeFunction = null;
this.multiDiffStepFunction = null;
this.initialize();
}
@ -70,22 +72,22 @@ DraggableNumber.prototype = {
this.lastMouseEvent = event;
}
if (this.dragging && this.lastMouseEvent) {
let initialValue = this.elInput.value;
let dx = event.clientX - this.lastMouseEvent.clientX;
let changeValue = dx !== 0;
if (changeValue) {
while (dx !== 0) {
if (dx > 0) {
this.elInput.stepUp();
--dx;
} else {
this.elInput.stepDown();
++dx;
let dragDelta = event.clientX - this.lastMouseEvent.clientX;
if (dragDelta !== 0) {
if (this.multiDiffModeEnabled) {
if (this.multiDiffStepFunction) {
this.multiDiffStepFunction(dragDelta * this.step);
}
} else {
if (dragDelta > 0) {
this.elInput.stepUp(dragDelta);
} else {
this.elInput.stepDown(-dragDelta);
}
this.inputChange();
if (this.valueChangeFunction) {
this.valueChangeFunction();
}
}
this.inputChange();
if (this.valueChangeFunction) {
this.valueChangeFunction();
}
}
this.lastMouseEvent = event;
@ -106,25 +108,46 @@ DraggableNumber.prototype = {
stepUp: function() {
if (!this.isDisabled()) {
this.elInput.value = parseFloat(this.elInput.value) + this.step;
this.inputChange();
if (this.valueChangeFunction) {
this.valueChangeFunction();
if (this.multiDiffModeEnabled) {
if (this.multiDiffStepFunction) {
this.multiDiffStepFunction(this.step, true);
}
} else {
this.elInput.value = parseFloat(this.elInput.value) + this.step;
this.inputChange();
if (this.valueChangeFunction) {
this.valueChangeFunction();
}
}
}
},
stepDown: function() {
if (!this.isDisabled()) {
this.elInput.value = parseFloat(this.elInput.value) - this.step;
this.inputChange();
if (this.valueChangeFunction) {
this.valueChangeFunction();
if (this.multiDiffModeEnabled) {
if (this.multiDiffStepFunction) {
this.multiDiffStepFunction(-this.step, true);
}
} else {
this.elInput.value = parseFloat(this.elInput.value) - this.step;
this.inputChange();
if (this.valueChangeFunction) {
this.valueChangeFunction();
}
}
}
},
setValue: function(newValue) {
setValue: function(newValue, isMultiDiff) {
if (isMultiDiff !== undefined) {
this.setMultiDiff(isMultiDiff);
}
if (isNaN(newValue)) {
console.error("DraggableNumber.setValue() > " + newValue + " is not a number.");
return;
}
if (newValue !== "" && this.decimals !== undefined) {
this.elInput.value = parseFloat(newValue).toFixed(this.decimals);
} else {
@ -133,11 +156,24 @@ DraggableNumber.prototype = {
this.elText.firstChild.data = this.elInput.value;
},
setMultiDiff: function(isMultiDiff) {
this.multiDiffModeEnabled = isMultiDiff;
if (isMultiDiff) {
this.elDiv.classList.add('multi-diff');
} else {
this.elDiv.classList.remove('multi-diff');
}
},
setValueChangeFunction: function(valueChangeFunction) {
this.valueChangeFunction = valueChangeFunction.bind(this.elInput);
this.elInput.addEventListener("change", this.valueChangeFunction);
},
setMultiDiffStepFunction: function (multiDiffStepFunction) {
this.multiDiffStepFunction = multiDiffStepFunction;
},
inputChange: function() {
let value = this.elInput.value;
if (this.max !== undefined) {
@ -155,6 +191,9 @@ DraggableNumber.prototype = {
keyPress: function(event) {
if (event.keyCode === ENTER_KEY) {
if (this.valueChangeFunction) {
this.valueChangeFunction();
}
this.inputBlur();
}
},
@ -203,7 +242,10 @@ DraggableNumber.prototype = {
this.elRightArrow.className = 'right-arrow';
this.elRightArrow.innerHTML = 'D';
this.elRightArrow.addEventListener("click", this.onStepUp);
this.elMultiDiff = document.createElement('span');
this.elMultiDiff.className = 'multi-diff';
this.elInput = document.createElement('input');
this.elInput.className = "input";
this.elInput.setAttribute("type", "number");
@ -220,6 +262,7 @@ DraggableNumber.prototype = {
this.elDiv.appendChild(this.elLeftArrow);
this.elDiv.appendChild(this.elText);
this.elDiv.appendChild(this.elInput);
this.elDiv.appendChild(this.elMultiDiff);
this.elDiv.appendChild(this.elRightArrow);
}
};

File diff suppressed because it is too large Load diff

View file

@ -25,3 +25,70 @@ function disableDragDrop() {
event.preventDefault();
}, false);
}
// mergeDeep function from https://stackoverflow.com/a/34749873
/**
* Simple object check.
* @param item
* @returns {boolean}
*/
function mergeDeepIsObject(item) {
return (item && typeof item === 'object' && !Array.isArray(item));
}
/**
* Deep merge two objects.
* @param target
* @param sources
*/
function mergeDeep(target, ...sources) {
if (!sources.length) {
return target;
}
const source = sources.shift();
if (mergeDeepIsObject(target) && mergeDeepIsObject(source)) {
for (const key in source) {
if (!source.hasOwnProperty(key)) {
continue;
}
if (mergeDeepIsObject(source[key])) {
if (!target[key]) {
Object.assign(target, { [key]: {} });
}
mergeDeep(target[key], source[key]);
} else {
Object.assign(target, { [key]: source[key] });
}
}
}
return mergeDeep(target, ...sources);
}
function deepEqual(a, b) {
if (a === b) {
return true;
}
if (typeof(a) !== "object" || typeof(b) !== "object") {
return false;
}
if (Object.keys(a).length !== Object.keys(b).length) {
return false;
}
for (let property in a) {
if (!a.hasOwnProperty(property)) {
continue;
}
if (!b.hasOwnProperty(property)) {
return false;
}
if (!deepEqual(a[property], b[property])) {
return false;
}
}
return true;
}