mirror of
https://github.com/overte-org/overte.git
synced 2025-04-14 14:47:19 +02:00
Merge pull request #15325 from dback2/dynamicMaterialTargetProperties
Case 20738: add dynamic multiselect for material target property
This commit is contained in:
commit
aff80dec26
3 changed files with 218 additions and 66 deletions
|
@ -2522,7 +2522,19 @@ var PropertiesTool = function (opts) {
|
|||
type: 'propertyRangeReply',
|
||||
propertyRanges: propertyRanges,
|
||||
});
|
||||
}
|
||||
} else if (data.type === "materialTargetRequest") {
|
||||
var properties = Entities.getEntityProperties(data.entityID, ["type", "parentID"]);
|
||||
var parentModel = properties.parentID !== Uuid.NULL &&
|
||||
Entities.getEntityProperties(properties.parentID, ["type"]).type === "Model";
|
||||
var parentModelData;
|
||||
if (properties.type === "Material" && parentModel) {
|
||||
parentModelData = Graphics.getModel(properties.parentID);
|
||||
}
|
||||
emitScriptEvent({
|
||||
type: 'materialTargetReply',
|
||||
materialTargetData: parentModelData,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
HMD.displayModeChanged.connect(function() {
|
||||
|
|
|
@ -861,10 +861,16 @@ span.indented {
|
|||
.multiselect-options input[type=checkbox]:checked + label {
|
||||
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACwAAAAsCAYAAAAehFoBAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAC4jAAAuIwF4pT92AAAAB3RJTUUH4goSADMveELP9QAAABl0RVh0Q29tbWVudABDcmVhdGVkIHdpdGggR0lNUFeBDhcAAAIqSURBVFjD7ZmxkqowFIb/7GwJPfT6APZib+9QC33o4QGghz70vIC9sfcBsE966bPNWlxnlQTDRWc4JUT4hpPz5SQSAAofFF/4sJiBx47v+wun04m8E+B6vVbzlJiBZ2CLIYRQQgj1EcBCCEUpRRRF4Jyrtwa+Xq+glEJKia7rkKYpGGPqbYHzPFdSyn+uMcZ6oScBZowpzvmje0jTVHVd9x7ATdMoxtjTMZxzUErV5MDn81mVZak1No7jab+wEEKlaaoNGwQBmQz4pq9H8/IeNo5jMmnRpWmKeyP8FZvN5insfwEuy1JdLpfecb7vI8uy3tb2Szelu91ONU1jtP9jjKmmabRgq6qC4zh2VrpbSsuy1FqNdPUFAK7roqoqeJ6ntXH4Mk1pn9gBoG1bbX1lWaYN2wv8KKWcc+z3+z+7LFv6MgY+Ho9PUyqlBKUUbduqe33pGKFPX0bAQgiV53nvj6WUiKIIt2K0qS/tXTMAEELguq6W6H/nOQ6Hg1V9GX1hz/NIXdckCALtB7Vta1VfxnPYcRwURUEeNSGmYaqvwVqL45gkSfIysKm+Xlo4wjAkdV3D9/1BLxmir5d7ieVySaqqMoYOw3CwEV5ufkyLcbVaIUkSq2d1xt2abjH6vo+iKKwfLA5uL58Vow19jdIPPyrGoiisGGGUBv6+GJMkwWKxGO2M+dvGQ36LEZxztd1uRz0Qt7ZFchwHY8NOelQ1NAjm/+lm4M8G/gH2zx33BSr7jAAAAABJRU5ErkJggg==');
|
||||
}
|
||||
.multiselect-options input[type=checkbox]:checked + label:hover {
|
||||
.multiselect-options input[type=checkbox]:checked + label:hover {
|
||||
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACwAAAAsCAYAAAAehFoBAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAC4jAAAuIwF4pT92AAAAB3RJTUUH4goSADMveELP9QAAABl0RVh0Q29tbWVudABDcmVhdGVkIHdpdGggR0lNUFeBDhcAAAIqSURBVFjD7ZmxkqowFIb/7GwJPfT6APZib+9QC33o4QGghz70vIC9sfcBsE966bPNWlxnlQTDRWc4JUT4hpPz5SQSAAofFF/4sJiBx47v+wun04m8E+B6vVbzlJiBZ2CLIYRQQgj1EcBCCEUpRRRF4Jyrtwa+Xq+glEJKia7rkKYpGGPqbYHzPFdSyn+uMcZ6oScBZowpzvmje0jTVHVd9x7ATdMoxtjTMZxzUErV5MDn81mVZak1No7jab+wEEKlaaoNGwQBmQz4pq9H8/IeNo5jMmnRpWmKeyP8FZvN5insfwEuy1JdLpfecb7vI8uy3tb2Szelu91ONU1jtP9jjKmmabRgq6qC4zh2VrpbSsuy1FqNdPUFAK7roqoqeJ6ntXH4Mk1pn9gBoG1bbX1lWaYN2wv8KKWcc+z3+z+7LFv6MgY+Ho9PUyqlBKUUbduqe33pGKFPX0bAQgiV53nvj6WUiKIIt2K0qS/tXTMAEELguq6W6H/nOQ6Hg1V9GX1hz/NIXdckCALtB7Vta1VfxnPYcRwURUEeNSGmYaqvwVqL45gkSfIysKm+Xlo4wjAkdV3D9/1BLxmir5d7ieVySaqqMoYOw3CwEV5ufkyLcbVaIUkSq2d1xt2abjH6vo+iKKwfLA5uL58Vow19jdIPPyrGoiisGGGUBv6+GJMkwWKxGO2M+dvGQ36LEZxztd1uRz0Qt7ZFchwHY8NOelQ1NAjm/+lm4M8G/gH2zx33BSr7jAAAAABJRU5ErkJggg==');
|
||||
}
|
||||
|
||||
.dynamic-multiselect {
|
||||
position: relative;
|
||||
top: 6px;
|
||||
padding-bottom: 6px;
|
||||
}
|
||||
|
||||
div.refresh {
|
||||
box-sizing: border-box;
|
||||
padding-right: 44px;
|
||||
|
|
|
@ -701,23 +701,10 @@ const GROUPS = [
|
|||
propertyID: "materialData",
|
||||
},
|
||||
{
|
||||
label: "Select Submesh",
|
||||
type: "bool",
|
||||
propertyID: "selectSubmesh",
|
||||
},
|
||||
{
|
||||
label: "Submesh to Replace",
|
||||
type: "number-draggable",
|
||||
min: 0,
|
||||
step: 1,
|
||||
propertyID: "submeshToReplace",
|
||||
indentedLabel: true,
|
||||
},
|
||||
{
|
||||
label: "Material to Replace",
|
||||
type: "string",
|
||||
propertyID: "materialNameToReplace",
|
||||
indentedLabel: true,
|
||||
label: "Material Target",
|
||||
type: "dynamic-multiselect",
|
||||
propertyUpdate: materialTargetPropertyUpdate,
|
||||
propertyID: "parentMaterialName",
|
||||
},
|
||||
{
|
||||
label: "Priority",
|
||||
|
@ -1639,6 +1626,8 @@ function getPropertyInputElement(propertyID) {
|
|||
return { red: property.elNumberR.elInput, green: property.elNumberG.elInput, blue: property.elNumberB.elInput };
|
||||
case 'icon':
|
||||
return property.elLabel;
|
||||
case 'dynamic-multiselect':
|
||||
return property.elDivOptions;
|
||||
default:
|
||||
return undefined;
|
||||
}
|
||||
|
@ -1761,6 +1750,10 @@ function resetProperties() {
|
|||
property.elInput.imageLoad(property.elInput.value);
|
||||
break;
|
||||
}
|
||||
case 'dynamic-multiselect': {
|
||||
resetDynamicMultiselectProperty(property.elDivOptions);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
let showPropertyRules = properties[propertyID].showPropertyRules;
|
||||
|
@ -2437,7 +2430,7 @@ function createTextureProperty(property, elProperty) {
|
|||
return elResult;
|
||||
}
|
||||
|
||||
function createButtonsProperty(property, elProperty, elLabel) {
|
||||
function createButtonsProperty(property, elProperty) {
|
||||
let elementID = property.elementID;
|
||||
let propertyData = property.data;
|
||||
|
||||
|
@ -2450,6 +2443,43 @@ function createButtonsProperty(property, elProperty, elLabel) {
|
|||
return elProperty;
|
||||
}
|
||||
|
||||
function createDynamicMultiselectProperty(property, elProperty) {
|
||||
let elementID = property.elementID;
|
||||
let propertyData = property.data;
|
||||
|
||||
elProperty.className = "dynamic-multiselect";
|
||||
|
||||
let elDivOptions = document.createElement('div');
|
||||
elDivOptions.setAttribute("id", elementID + "-options");
|
||||
elDivOptions.style = "overflow-y:scroll;max-height:160px;"
|
||||
|
||||
let elDivButtons = document.createElement('div');
|
||||
elDivButtons.setAttribute("id", elDivOptions.getAttribute("id") + "-buttons");
|
||||
|
||||
let elLabel = document.createElement('label');
|
||||
elLabel.innerText = "No Options";
|
||||
elDivOptions.appendChild(elLabel);
|
||||
|
||||
let buttons = [ { id: "selectAll", label: "Select All", className: "black", onClick: selectAllMaterialTarget },
|
||||
{ id: "clearAll", label: "Clear All", className: "black", onClick: clearAllMaterialTarget } ];
|
||||
addButtons(elDivButtons, elementID, buttons, false);
|
||||
|
||||
elProperty.appendChild(elDivOptions);
|
||||
elProperty.appendChild(elDivButtons);
|
||||
|
||||
return elDivOptions;
|
||||
}
|
||||
|
||||
function resetDynamicMultiselectProperty(elDivOptions) {
|
||||
let elInputs = elDivOptions.getElementsByTagName("input");
|
||||
while (elInputs.length > 0) {
|
||||
let elDivOption = elInputs[0].parentNode;
|
||||
elDivOption.parentNode.removeChild(elDivOption);
|
||||
}
|
||||
elDivOptions.firstChild.style.display = "block"; // show "No Options" text
|
||||
elDivOptions.parentNode.lastChild.style.display = "none"; // hide Select/Clear all buttons
|
||||
}
|
||||
|
||||
function createTupleNumberInput(property, subLabel) {
|
||||
let propertyElementID = property.elementID;
|
||||
let propertyData = property.data;
|
||||
|
@ -2573,6 +2603,10 @@ function createProperty(propertyData, propertyElementID, propertyName, propertyI
|
|||
property.elProperty = createButtonsProperty(property, elProperty);
|
||||
break;
|
||||
}
|
||||
case 'dynamic-multiselect': {
|
||||
property.elDivOptions = createDynamicMultiselectProperty(property, elProperty);
|
||||
break;
|
||||
}
|
||||
case 'placeholder':
|
||||
case 'sub-header': {
|
||||
break;
|
||||
|
@ -3109,7 +3143,7 @@ function setDropdownValue(event) {
|
|||
|
||||
|
||||
/**
|
||||
* TEXTAREA / PARENT MATERIAL NAME FUNCTIONS
|
||||
* TEXTAREA FUNCTIONS
|
||||
*/
|
||||
|
||||
function setTextareaScrolling(element) {
|
||||
|
@ -3117,16 +3151,140 @@ function setTextareaScrolling(element) {
|
|||
element.setAttribute("scrolling", isScrolling ? "true" : "false");
|
||||
}
|
||||
|
||||
function showParentMaterialNameBox(number, elNumber, elString) {
|
||||
if (number) {
|
||||
$('#property-submeshToReplace').parent().show();
|
||||
$('#property-materialNameToReplace').parent().hide();
|
||||
elString.value = "";
|
||||
} else {
|
||||
$('#property-materialNameToReplace').parent().show();
|
||||
$('#property-submeshToReplace').parent().hide();
|
||||
elNumber.value = 0;
|
||||
|
||||
/**
|
||||
* MATERIAL TARGET FUNCTIONS
|
||||
*/
|
||||
|
||||
function setMaterialTargetData(materialTargetData) {
|
||||
let elDivOptions = getPropertyInputElement("parentMaterialName");
|
||||
resetDynamicMultiselectProperty(elDivOptions);
|
||||
|
||||
if (materialTargetData === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
elDivOptions.firstChild.style.display = "none"; // hide "No Options" text
|
||||
elDivOptions.parentNode.lastChild.style.display = "block"; // show Select/Clear all buttons
|
||||
|
||||
let numMeshes = materialTargetData.numMeshes;
|
||||
for (let i = 0; i < numMeshes; ++i) {
|
||||
addMaterialTarget(elDivOptions, i, false);
|
||||
}
|
||||
|
||||
let materialNames = materialTargetData.materialNames;
|
||||
let materialNamesAdded = [];
|
||||
for (let i = 0; i < materialNames.length; ++i) {
|
||||
let materialName = materialNames[i];
|
||||
if (materialNamesAdded.indexOf(materialName) === -1) {
|
||||
addMaterialTarget(elDivOptions, materialName, true);
|
||||
materialNamesAdded.push(materialName);
|
||||
}
|
||||
}
|
||||
|
||||
materialTargetPropertyUpdate(elDivOptions.propertyValue);
|
||||
}
|
||||
|
||||
function addMaterialTarget(elDivOptions, targetID, isMaterialName) {
|
||||
let elementID = elDivOptions.getAttribute("id");
|
||||
elementID += isMaterialName ? "-material-" : "-mesh-";
|
||||
elementID += targetID;
|
||||
|
||||
let elDiv = document.createElement('div');
|
||||
elDiv.className = "materialTargetDiv";
|
||||
elDiv.onclick = onToggleMaterialTarget;
|
||||
elDivOptions.appendChild(elDiv);
|
||||
|
||||
let elInput = document.createElement('input');
|
||||
elInput.className = "materialTargetInput";
|
||||
elInput.setAttribute("type", "checkbox");
|
||||
elInput.setAttribute("id", elementID);
|
||||
elInput.setAttribute("targetID", targetID);
|
||||
elInput.setAttribute("isMaterialName", isMaterialName);
|
||||
elDiv.appendChild(elInput);
|
||||
|
||||
let elLabel = document.createElement('label');
|
||||
elLabel.setAttribute("for", elementID);
|
||||
elLabel.innerText = isMaterialName ? "Material " + targetID : "Mesh Index " + targetID;
|
||||
elDiv.appendChild(elLabel);
|
||||
|
||||
return elDiv;
|
||||
}
|
||||
|
||||
function onToggleMaterialTarget(event) {
|
||||
let elTarget = event.target;
|
||||
if (elTarget instanceof HTMLInputElement) {
|
||||
sendMaterialTargetProperty();
|
||||
}
|
||||
event.stopPropagation();
|
||||
}
|
||||
|
||||
function setAllMaterialTargetInputs(checked) {
|
||||
let elDivOptions = getPropertyInputElement("parentMaterialName");
|
||||
let elInputs = elDivOptions.getElementsByClassName("materialTargetInput");
|
||||
for (let i = 0; i < elInputs.length; ++i) {
|
||||
elInputs[i].checked = checked;
|
||||
}
|
||||
}
|
||||
|
||||
function selectAllMaterialTarget() {
|
||||
setAllMaterialTargetInputs(true);
|
||||
sendMaterialTargetProperty();
|
||||
}
|
||||
|
||||
function clearAllMaterialTarget() {
|
||||
setAllMaterialTargetInputs(false);
|
||||
sendMaterialTargetProperty();
|
||||
}
|
||||
|
||||
function sendMaterialTargetProperty() {
|
||||
let elDivOptions = getPropertyInputElement("parentMaterialName");
|
||||
let elInputs = elDivOptions.getElementsByClassName("materialTargetInput");
|
||||
|
||||
let materialTargetList = "";
|
||||
for (let i = 0; i < elInputs.length; ++i) {
|
||||
let elInput = elInputs[i];
|
||||
if (elInput.checked) {
|
||||
let targetID = elInput.getAttribute("targetID");
|
||||
if (elInput.getAttribute("isMaterialName") === "true") {
|
||||
materialTargetList += "mat::" + targetID + ",";
|
||||
} else {
|
||||
materialTargetList += targetID + ",";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (materialTargetList !== "") {
|
||||
materialTargetList = materialTargetList.substring(0, materialTargetList.length - 1);
|
||||
materialTargetList = "[" + materialTargetList + "]";
|
||||
}
|
||||
|
||||
updateProperty("parentMaterialName", materialTargetList, false);
|
||||
}
|
||||
|
||||
function materialTargetPropertyUpdate(propertyValue) {
|
||||
let elDivOptions = getPropertyInputElement("parentMaterialName");
|
||||
let elInputs = elDivOptions.getElementsByClassName("materialTargetInput");
|
||||
|
||||
if (propertyValue.charAt(0) === '[') {
|
||||
propertyValue = propertyValue.substring(1, propertyValue.length);
|
||||
}
|
||||
if (propertyValue.charAt(propertyValue.length - 1) === ']') {
|
||||
propertyValue = propertyValue.substring(0, propertyValue.length - 1);
|
||||
}
|
||||
|
||||
let materialTargets = propertyValue.split(",");
|
||||
for (let i = 0; i < elInputs.length; ++i) {
|
||||
let elInput = elInputs[i];
|
||||
let targetID = elInput.getAttribute("targetID");
|
||||
let materialTargetName = targetID;
|
||||
if (elInput.getAttribute("isMaterialName") === "true") {
|
||||
materialTargetName = "mat::" + targetID;
|
||||
}
|
||||
elInput.checked = materialTargets.indexOf(materialTargetName) >= 0;
|
||||
}
|
||||
|
||||
elDivOptions.propertyValue = propertyValue;
|
||||
}
|
||||
|
||||
|
||||
|
@ -3555,6 +3713,12 @@ function loaded() {
|
|||
property.elInput.imageLoad(property.elInput.value);
|
||||
break;
|
||||
}
|
||||
case 'dynamic-multiselect': {
|
||||
if (property.data.propertyUpdate) {
|
||||
property.data.propertyUpdate(propertyValue);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
let showPropertyRules = property.showPropertyRules;
|
||||
|
@ -3568,22 +3732,6 @@ function loaded() {
|
|||
}
|
||||
|
||||
updateVisibleSpaceModeProperties();
|
||||
|
||||
if (selectedEntityProperties.type === "Material") {
|
||||
let elParentMaterialNameString = getPropertyInputElement("materialNameToReplace");
|
||||
let elParentMaterialNameNumber = getPropertyInputElement("submeshToReplace");
|
||||
let elParentMaterialNameCheckbox = getPropertyInputElement("selectSubmesh");
|
||||
let parentMaterialName = selectedEntityProperties.parentMaterialName;
|
||||
if (parentMaterialName.startsWith(MATERIAL_PREFIX_STRING)) {
|
||||
elParentMaterialNameString.value = parentMaterialName.replace(MATERIAL_PREFIX_STRING, "");
|
||||
showParentMaterialNameBox(false, elParentMaterialNameNumber, elParentMaterialNameString);
|
||||
elParentMaterialNameCheckbox.checked = false;
|
||||
} else {
|
||||
elParentMaterialNameNumber.value = parseInt(parentMaterialName);
|
||||
showParentMaterialNameBox(true, elParentMaterialNameNumber, elParentMaterialNameString);
|
||||
elParentMaterialNameCheckbox.checked = true;
|
||||
}
|
||||
}
|
||||
|
||||
let json = null;
|
||||
try {
|
||||
|
@ -3631,6 +3779,10 @@ function loaded() {
|
|||
hideMaterialDataSaved();
|
||||
}
|
||||
|
||||
if (hasSelectedEntityChanged && selectedEntityProperties.type === "Material") {
|
||||
EventBridge.emitWebEvent(JSON.stringify({ type: 'materialTargetRequest', entityID: selectedEntityProperties.id }));
|
||||
}
|
||||
|
||||
let activeElement = document.activeElement;
|
||||
if (doSelectElement && typeof activeElement.select !== "undefined") {
|
||||
activeElement.select();
|
||||
|
@ -3680,6 +3832,8 @@ function loaded() {
|
|||
}
|
||||
}
|
||||
}
|
||||
} else if (data.type === 'materialTargetReply') {
|
||||
setMaterialTargetData(data.materialTargetData);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -3749,26 +3903,6 @@ function loaded() {
|
|||
elDiv.insertBefore(elMaterialDataEditor, elMaterialData);
|
||||
elDiv.insertBefore(elMaterialDataEditorStatus, elMaterialData);
|
||||
|
||||
// Special Property Callbacks
|
||||
let elParentMaterialNameString = getPropertyInputElement("materialNameToReplace");
|
||||
let elParentMaterialNameNumber = getPropertyInputElement("submeshToReplace");
|
||||
let elParentMaterialNameCheckbox = getPropertyInputElement("selectSubmesh");
|
||||
elParentMaterialNameString.addEventListener('change', function () {
|
||||
updateProperty("parentMaterialName", MATERIAL_PREFIX_STRING + this.value, false);
|
||||
});
|
||||
elParentMaterialNameNumber.addEventListener('change', function () {
|
||||
updateProperty("parentMaterialName", this.value, false);
|
||||
});
|
||||
elParentMaterialNameCheckbox.addEventListener('change', function () {
|
||||
if (this.checked) {
|
||||
updateProperty("parentMaterialName", elParentMaterialNameNumber.value, false);
|
||||
showParentMaterialNameBox(true, elParentMaterialNameNumber, elParentMaterialNameString);
|
||||
} else {
|
||||
updateProperty("parentMaterialName", MATERIAL_PREFIX_STRING + elParentMaterialNameString.value, false);
|
||||
showParentMaterialNameBox(false, elParentMaterialNameNumber, elParentMaterialNameString);
|
||||
}
|
||||
});
|
||||
|
||||
// Collapsible sections
|
||||
let elCollapsible = document.getElementsByClassName("collapse-icon");
|
||||
|
||||
|
|
Loading…
Reference in a new issue