mirror of
https://github.com/overte-org/overte.git
synced 2025-08-06 18:50:00 +02:00
add dynamic multiselect for material targets
This commit is contained in:
parent
fd245b61ab
commit
4f4ec064e4
2 changed files with 209 additions and 65 deletions
|
@ -2522,7 +2522,19 @@ var PropertiesTool = function (opts) {
|
||||||
type: 'propertyRangeReply',
|
type: 'propertyRangeReply',
|
||||||
propertyRanges: propertyRanges,
|
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() {
|
HMD.displayModeChanged.connect(function() {
|
||||||
|
|
|
@ -650,23 +650,10 @@ const GROUPS = [
|
||||||
propertyID: "materialData",
|
propertyID: "materialData",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "Select Submesh",
|
label: "Material Target",
|
||||||
type: "bool",
|
type: "dynamic-multiselect",
|
||||||
propertyID: "selectSubmesh",
|
propertyUpdate: materialTargetPropertyUpdate,
|
||||||
},
|
propertyID: "parentMaterialName",
|
||||||
{
|
|
||||||
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: "Priority",
|
label: "Priority",
|
||||||
|
@ -1588,6 +1575,8 @@ function getPropertyInputElement(propertyID) {
|
||||||
return { red: property.elNumberR.elInput, green: property.elNumberG.elInput, blue: property.elNumberB.elInput };
|
return { red: property.elNumberR.elInput, green: property.elNumberG.elInput, blue: property.elNumberB.elInput };
|
||||||
case 'icon':
|
case 'icon':
|
||||||
return property.elLabel;
|
return property.elLabel;
|
||||||
|
case 'dynamic-multiselect':
|
||||||
|
return property.elDivOptions;
|
||||||
default:
|
default:
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
@ -1710,6 +1699,10 @@ function resetProperties() {
|
||||||
property.elInput.imageLoad(property.elInput.value);
|
property.elInput.imageLoad(property.elInput.value);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case 'dynamic-multiselect': {
|
||||||
|
resetDynamicMultiselectProperty(property.elDivOptions);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let showPropertyRules = properties[propertyID].showPropertyRules;
|
let showPropertyRules = properties[propertyID].showPropertyRules;
|
||||||
|
@ -2386,7 +2379,7 @@ function createTextureProperty(property, elProperty) {
|
||||||
return elResult;
|
return elResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
function createButtonsProperty(property, elProperty, elLabel) {
|
function createButtonsProperty(property, elProperty) {
|
||||||
let elementID = property.elementID;
|
let elementID = property.elementID;
|
||||||
let propertyData = property.data;
|
let propertyData = property.data;
|
||||||
|
|
||||||
|
@ -2399,6 +2392,42 @@ function createButtonsProperty(property, elProperty, elLabel) {
|
||||||
return elProperty;
|
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");
|
||||||
|
|
||||||
|
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 = "none";
|
||||||
|
elDivOptions.parentNode.lastChild.style.display = "block";
|
||||||
|
}
|
||||||
|
|
||||||
function createTupleNumberInput(property, subLabel) {
|
function createTupleNumberInput(property, subLabel) {
|
||||||
let propertyElementID = property.elementID;
|
let propertyElementID = property.elementID;
|
||||||
let propertyData = property.data;
|
let propertyData = property.data;
|
||||||
|
@ -2522,6 +2551,10 @@ function createProperty(propertyData, propertyElementID, propertyName, propertyI
|
||||||
property.elProperty = createButtonsProperty(property, elProperty);
|
property.elProperty = createButtonsProperty(property, elProperty);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case 'dynamic-multiselect': {
|
||||||
|
property.elDivOptions = createDynamicMultiselectProperty(property, elProperty);
|
||||||
|
break;
|
||||||
|
}
|
||||||
case 'placeholder':
|
case 'placeholder':
|
||||||
case 'sub-header': {
|
case 'sub-header': {
|
||||||
break;
|
break;
|
||||||
|
@ -3058,7 +3091,7 @@ function setDropdownValue(event) {
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TEXTAREA / PARENT MATERIAL NAME FUNCTIONS
|
* TEXTAREA FUNCTIONS
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function setTextareaScrolling(element) {
|
function setTextareaScrolling(element) {
|
||||||
|
@ -3066,16 +3099,139 @@ function setTextareaScrolling(element) {
|
||||||
element.setAttribute("scrolling", isScrolling ? "true" : "false");
|
element.setAttribute("scrolling", isScrolling ? "true" : "false");
|
||||||
}
|
}
|
||||||
|
|
||||||
function showParentMaterialNameBox(number, elNumber, elString) {
|
|
||||||
if (number) {
|
/**
|
||||||
$('#property-submeshToReplace').parent().show();
|
* MATERIAL TARGET FUNCTIONS
|
||||||
$('#property-materialNameToReplace').parent().hide();
|
*/
|
||||||
elString.value = "";
|
|
||||||
} else {
|
function setMaterialTargetData(materialTargetData) {
|
||||||
$('#property-materialNameToReplace').parent().show();
|
let elDivOptions = getPropertyInputElement("parentMaterialName");
|
||||||
$('#property-submeshToReplace').parent().hide();
|
resetDynamicMultiselectProperty(elDivOptions);
|
||||||
elNumber.value = 0;
|
|
||||||
|
if (materialTargetData === undefined) {
|
||||||
|
elDivOptions.firstChild.style.display = "block";
|
||||||
|
elDivOptions.parentNode.lastChild.style.display = "none";
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -3504,6 +3660,12 @@ function loaded() {
|
||||||
property.elInput.imageLoad(property.elInput.value);
|
property.elInput.imageLoad(property.elInput.value);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case 'dynamic-multiselect': {
|
||||||
|
if (property.data.propertyUpdate) {
|
||||||
|
property.data.propertyUpdate(propertyValue);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let showPropertyRules = property.showPropertyRules;
|
let showPropertyRules = property.showPropertyRules;
|
||||||
|
@ -3517,22 +3679,6 @@ function loaded() {
|
||||||
}
|
}
|
||||||
|
|
||||||
updateVisibleSpaceModeProperties();
|
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;
|
let json = null;
|
||||||
try {
|
try {
|
||||||
|
@ -3580,6 +3726,10 @@ function loaded() {
|
||||||
hideMaterialDataSaved();
|
hideMaterialDataSaved();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (hasSelectedEntityChanged && selectedEntityProperties.type === "Material") {
|
||||||
|
EventBridge.emitWebEvent(JSON.stringify({ type: 'materialTargetRequest', entityID: selectedEntityProperties.id }));
|
||||||
|
}
|
||||||
|
|
||||||
let activeElement = document.activeElement;
|
let activeElement = document.activeElement;
|
||||||
if (doSelectElement && typeof activeElement.select !== "undefined") {
|
if (doSelectElement && typeof activeElement.select !== "undefined") {
|
||||||
activeElement.select();
|
activeElement.select();
|
||||||
|
@ -3629,6 +3779,8 @@ function loaded() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if (data.type === 'materialTargetReply') {
|
||||||
|
setMaterialTargetData(data.materialTargetData);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -3698,26 +3850,6 @@ function loaded() {
|
||||||
elDiv.insertBefore(elMaterialDataEditor, elMaterialData);
|
elDiv.insertBefore(elMaterialDataEditor, elMaterialData);
|
||||||
elDiv.insertBefore(elMaterialDataEditorStatus, 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
|
// Collapsible sections
|
||||||
let elCollapsible = document.getElementsByClassName("collapse-icon");
|
let elCollapsible = document.getElementsByClassName("collapse-icon");
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue