'use strict';
const { updateElementReadonly } = require('../utils/assets');
exports.template = /* html */`
`;
exports.style = /* css */`
.asset-animation-mask {
display: flex;
height: 100%;
flex-direction: column;
}
.asset-animation-mask[multiple-invalid] > *:not(.multiple-warn-tip) {
display: none!important;
}
.asset-animation-mask[multiple-invalid] > .multiple-warn-tip {
display: block;
}
.asset-animation-mask .multiple-warn-tip {
display: none;
text-align: center;
color: var(--color-focus-contrast-weakest);
margin-top: 8px;
}
.asset-animation-mask > .header {
margin-top: 4px;
margin-right: 4px;
display: flex;
}
.asset-animation-mask > .header ui-button {
text-align: center;
}
.asset-animation-mask > .header .import {
flex: 1;
margin-left: 10px;
}
.asset-animation-mask > .header .clear {
margin-left: 10px;
}
.asset-animation-mask > .content {
flex: 1;
margin-top: 10px;
}
.asset-animation-mask > .content .tree {
height: 100%;
}
`;
exports.$ = {
container: '.asset-animation-mask',
import: '.import',
clear: '.clear',
tree: '.tree',
};
exports.methods = {
record() {
return JSON.stringify(this.queryData);
},
async restore(record) {
record = JSON.parse(record);
if (!record || typeof record !== 'object') {
return false;
}
await this.change(record);
return true;
},
async query(uuid) {
return await Editor.Message.request('scene', 'query-animation-mask', uuid);
},
async apply() {
this.reset();
await Editor.Message.request('scene', 'apply-animation-mask', this.asset.uuid);
},
abort() {
this.reset();
},
reset() {
this.dirtyData.uuid = '';
},
async clear() {
this.queryData = await Editor.Message.request('scene', 'change-animation-mask', {
method: 'clear-nodes',
uuid: this.asset.uuid,
});
this.changed();
},
async import(uuid) {
this.queryData = await Editor.Message.request('scene', 'change-animation-mask', {
method: 'import-skeleton',
uuid: uuid,
});
this.changed();
},
async change(dump) {
this.queryData = await Editor.Message.request('scene', 'change-animation-mask', {
method: 'change-dump',
dump,
});
this.changed();
},
changed() {
this.updateInterface();
this.setDirtyData();
this.dispatch('change');
/**
* 由于编辑项中不需要区分 change 和 confirm 的情况,
* 所以可以在 change 后 snapshot
*/
this.dispatch('snapshot');
},
updateInterface() {
const convertData = this.convertData(this.queryData.joints.value);
this.flatData = convertData.flatData;
this.$.tree.tree = convertData.treeData;
updateElementReadonly.call(this, this.$.import);
updateElementReadonly.call(this, this.$.clear);
updateElementReadonly.call(this, this.$.tree);
},
setDirtyData() {
this.dirtyData.realtime = JSON.stringify(this.queryData);
if (!this.dirtyData.origin) {
this.dirtyData.origin = this.dirtyData.realtime;
}
},
isDirty() {
const isDirty = this.dirtyData.origin !== this.dirtyData.realtime;
return isDirty;
},
convertData(jointArr) {
const collator = new Intl.Collator('en', {
numeric: true,
sensitivity: 'base',
});
jointArr.sort((a, b) => {
return collator.compare(a.value.path.value, b.value.path.value);
});
const flatData = {};
for (const joint of jointArr) {
const key = joint.value.path.value;
if (!key) {
continue;
}
let childKey = key;
let parentKey = childKey.substr(0, childKey.lastIndexOf('/'));
while (parentKey) {
if (!flatData[parentKey]) {
flatData[parentKey] = { children: [childKey] };
} else {
if (!flatData[parentKey].children.includes(childKey)) {
flatData[parentKey].children.push(childKey);
}
}
childKey = parentKey;
parentKey = childKey.substr(0, childKey.lastIndexOf('/'));
}
if (!flatData[key]) {
flatData[key] = { origin: joint, children: [] };
} else {
flatData[key].origin = joint;
}
}
const treeData = [];
const keys = Object.keys(flatData);
keys.sort((a, b) => {
return collator.compare(a, b);
});
const roots = [];
for (const key of keys) {
// 一级根路径
if (key.indexOf('/') === -1) {
roots.push(key);
}
}
treeDataFromFlatData(treeData, roots);
function treeDataFromFlatData(treeArr, keys) {
if (!Array.isArray(keys)) {
return;
}
keys.forEach((key) => {
const { origin, children } = flatData[key];
const treeNode = {
detail: {
key,
name: key.substr(key.lastIndexOf('/') + 1),
disabled: true,
},
children: [],
};
if (origin) {
treeNode.detail.disabled = false;
}
treeArr.push(treeNode);
treeDataFromFlatData(treeNode.children, children);
});
}
return { flatData, treeData };
},
jointEnableChange(key, checked, loop) {
const { children, origin } = this.flatData[key];
origin.value.enabled.value = checked;
if (loop) {
children.forEach((childKey) => {
this.jointEnableChange(childKey, checked, loop);
});
}
},
};
exports.ready = function() {
const panel = this;
panel.$.import.addEventListener('change', (event) => {
Editor.Panel.__protected__.openKit('ui-kit.searcher', {
elem: event.target,
params: [
{
type: 'asset',
assetFilter: {
importer: ['gltf-scene'],
},
},
],
listeners: {
async confirm(detail) {
if (!detail) { return; }
await panel.import(detail.value);
},
},
});
});
panel.$.clear.addEventListener('change', async () => {
const result = await Editor.Dialog.warn(Editor.I18n.t('ENGINE.assets.animationMask.clearAllNodesWarn'), {
title: Editor.I18n.t('ENGINE.assets.animationMask.clearAllNodes'),
buttons: [Editor.I18n.t('ENGINE.dialog.confirm'), Editor.I18n.t('ENGINE.dialog.cancel')],
default: 0,
cancel: 1,
});
if (result.response === 0) {
await this.clear();
}
});
// Used to determine whether the material has been modified in isDirty()
panel.dirtyData = {
uuid: '',
origin: '',
realtime: '',
};
panel.$.tree.setTemplate('left', '');
panel.$.tree.setTemplateInit('left', ($left) => {
$left.$checkbox = $left.querySelector('ui-checkbox');
$left.$checkbox.addEventListener('click', async (event) => {
const key = $left.data.detail.key;
const origin = panel.flatData[key].origin;
panel.jointEnableChange(key, !origin.value.enabled.value, !event.altKey);
await panel.change(this.queryData);
});
});
panel.$.tree.setRender('left', ($left) => {
const { key, disabled } = $left.data.detail;
if (disabled) {
$left.$checkbox.setAttribute('disabled', true);
$left.$checkbox.value = true;
} else {
$left.$checkbox.removeAttribute('disabled');
}
const origin = panel.flatData[key].origin;
if (origin) {
$left.$checkbox.value = origin.value.enabled.value;
}
});
panel.$.tree.setTemplate('text', ``);
panel.$.tree.setTemplateInit('text', ($text) => {
$text.$name = $text.querySelector('.name');
});
panel.$.tree.setRender('text', ($text, data) => {
$text.$name.innerHTML = data.detail.name || data.detail.root;
});
};
exports.update = async function(assetList, metaList) {
this.assetList = assetList;
this.metaList = metaList;
this.asset = assetList[0];
this.meta = metaList[0];
if (assetList.length > 1) {
this.$.container.setAttribute('multiple-invalid', '');
return;
} else {
this.$.container.removeAttribute('multiple-invalid');
}
if (this.dirtyData.uuid !== this.asset.uuid) {
this.dirtyData.uuid = this.asset.uuid;
this.dirtyData.origin = '';
}
this.queryData = await this.query(this.asset.uuid);
this.updateInterface();
this.setDirtyData();
};
exports.close = function() {
// Used to determine whether the material has been modified in isDirty()
this.dirtyData = {
uuid: '',
origin: '',
realtime: '',
};
};