You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

317 lines
12 KiB

(function (global) {
'use strict';
/**
* Runtime property inspector with live edits.
* @constructor
*/
function InspectorPanel() {
this.el = null;
this.body = null;
this._cc = null;
this._pick = null;
this._node = null;
}
/** @param {*} pick */
InspectorPanel.prototype.setPick = function (pick) {
var self = this;
this._pick = pick;
if (pick) {
pick.onSelect(function (node) {
self._node = node;
self.render();
});
}
};
/** @param {*} cc */
InspectorPanel.prototype.bindEngine = function (cc) {
this._cc = cc;
};
InspectorPanel.prototype.mount = function () {
var root = document.createElement('div');
root.className = 'pw-panel-inner';
root.style.height = '100%';
root.style.display = 'flex';
root.style.flexDirection = 'column';
root.innerHTML =
'<div class="pw-panel-head"><span class="pw-panel-title">属性</span></div>' +
'<div class="pw-panel-body" id="pw-inspector-body"><div class="pw-muted">未选中节点</div></div>';
this.el = root;
this.body = root.querySelector('#pw-inspector-body');
return root;
};
InspectorPanel.prototype.render = function () {
var body = this.body;
var node = this._node;
var cc = this._cc;
if (!body) return;
if (!node || !node.isValid) {
body.innerHTML = '<div class="pw-muted">未选中节点</div>';
return;
}
var p = node.getPosition ? node.getPosition() : node.position;
var e = node.eulerAngles || (node.getRotation ? { x: 0, y: 0, z: 0 } : { x: 0, y: 0, z: 0 });
if (node.eulerAngles) e = node.eulerAngles;
var s = node.getScale ? node.getScale() : node.scale;
var html = [];
html.push('<div class="pw-comp-block"><h5>节点</h5><div class="pw-field-grid">');
html.push(fieldText('名称', 'name', node.name));
html.push(fieldCheck('激活', 'active', !!node.active));
html.push(fieldNum('层级', 'layer', node.layer));
html.push(fieldNum('位置 X', 'px', p.x));
html.push(fieldNum('位置 Y', 'py', p.y));
html.push(fieldNum('位置 Z', 'pz', p.z));
html.push(fieldNum('旋转 X', 'rx', e.x));
html.push(fieldNum('旋转 Y', 'ry', e.y));
html.push(fieldNum('旋转 Z', 'rz', e.z));
html.push(fieldNum('缩放 X', 'sx', s.x));
html.push(fieldNum('缩放 Y', 'sy', s.y));
html.push(fieldNum('缩放 Z', 'sz', s.z));
html.push('</div></div>');
var uit = node.getComponent && cc && node.getComponent(cc.UITransform);
if (uit) {
html.push('<div class="pw-comp-block"><h5>UITransform</h5><div class="pw-field-grid">');
html.push(fieldNum('宽度', 'uiw', uit.width));
html.push(fieldNum('高度', 'uih', uit.height));
html.push(fieldNum('锚点 X', 'uax', uit.anchorX));
html.push(fieldNum('锚点 Y', 'uay', uit.anchorY));
html.push('</div></div>');
}
if (node.components) {
for (var i = 0; i < node.components.length; i++) {
var comp = node.components[i];
if (!comp || !comp.constructor) continue;
var cname = comp.constructor.name;
if (cname === 'UITransform') continue;
html.push('<div class="pw-comp-block"><h5>' + escapeHtml(cname) + '</h5><div class="pw-field-grid">');
var keys = Object.keys(comp);
var shown = 0;
for (var k = 0; k < keys.length && shown < 24; k++) {
var key = keys[k];
if (!key || key.charAt(0) === '_' || key === 'node' || key === 'uuid') continue;
var val = comp[key];
var t = typeof val;
if (t === 'number') {
html.push(fieldNum(key, 'c' + i + '_' + key, val));
shown++;
} else if (t === 'boolean') {
html.push(fieldCheck(key, 'c' + i + '_' + key, val));
shown++;
} else if (t === 'string') {
html.push(fieldText(key, 'c' + i + '_' + key, val));
shown++;
}
}
if (!shown) html.push('<span class="pw-muted">无可编辑公开字段</span>');
html.push('</div></div>');
}
}
body.innerHTML = html.join('');
this._bindFields(node, uit);
};
InspectorPanel.prototype._bindFields = function (node, uit) {
var self = this;
var body = this.body;
var cc = this._cc;
function byFid(id) {
return body.querySelector('[data-fid="' + id.replace(/"/g, '') + '"]');
}
function num(id) {
var el = byFid(id);
return el ? parseFloat(el.value) : NaN;
}
function bind(id, apply) {
var el = byFid(id);
if (!el) return;
var run = function () {
try {
apply(el);
} catch (e) {
console.warn('[调试工作台] 设置属性失败', id, e);
}
};
el.addEventListener('change', run);
el.addEventListener('input', run);
}
function readPos() {
return node.getPosition ? node.getPosition() : node.position;
}
function writePos(x, y, z) {
if (typeof node.setPosition === 'function') {
node.setPosition(x, y, z);
return;
}
if (cc && cc.Vec3) node.position = new cc.Vec3(x, y, z);
}
function readScale() {
return node.getScale ? node.getScale() : node.scale;
}
function writeScale(x, y, z) {
if (typeof node.setScale === 'function') {
node.setScale(x, y, z);
return;
}
if (cc && cc.Vec3) node.scale = new cc.Vec3(x, y, z);
}
function writeEuler(x, y, z) {
if (typeof node.setRotationFromEuler === 'function') {
node.setRotationFromEuler(x, y, z);
return;
}
if (node.eulerAngles) {
node.eulerAngles = cc && cc.Vec3 ? new cc.Vec3(x, y, z) : { x: x, y: y, z: z };
}
}
bind('name', function (el) { node.name = el.value; });
bind('active', function (el) { node.active = !!el.checked; });
bind('layer', function () {
var v = num('layer');
if (!isNaN(v)) node.layer = v | 0;
});
bind('px', function () {
var v = num('px');
if (isNaN(v)) return;
var p = readPos();
writePos(v, p.y, p.z);
});
bind('py', function () {
var v = num('py');
if (isNaN(v)) return;
var p = readPos();
writePos(p.x, v, p.z);
});
bind('pz', function () {
var v = num('pz');
if (isNaN(v)) return;
var p = readPos();
writePos(p.x, p.y, v);
});
bind('rx', function () {
var v = num('rx');
if (isNaN(v)) return;
var e = node.eulerAngles;
writeEuler(v, e.y, e.z);
});
bind('ry', function () {
var v = num('ry');
if (isNaN(v)) return;
var e = node.eulerAngles;
writeEuler(e.x, v, e.z);
});
bind('rz', function () {
var v = num('rz');
if (isNaN(v)) return;
var e = node.eulerAngles;
writeEuler(e.x, e.y, v);
});
bind('sx', function () {
var v = num('sx');
if (isNaN(v)) return;
var s = readScale();
writeScale(v, s.y, s.z);
});
bind('sy', function () {
var v = num('sy');
if (isNaN(v)) return;
var s = readScale();
writeScale(s.x, v, s.z);
});
bind('sz', function () {
var v = num('sz');
if (isNaN(v)) return;
var s = readScale();
writeScale(s.x, s.y, v);
});
if (uit) {
bind('uiw', function () {
var w = num('uiw');
var h = num('uih');
if (isNaN(w)) return;
if (typeof uit.setContentSize === 'function') uit.setContentSize(w, isNaN(h) ? uit.height : h);
else uit.width = w;
});
bind('uih', function () {
var w = num('uiw');
var h = num('uih');
if (isNaN(h)) return;
if (typeof uit.setContentSize === 'function') uit.setContentSize(isNaN(w) ? uit.width : w, h);
else uit.height = h;
});
bind('uax', function () {
var v = num('uax');
if (isNaN(v)) return;
if (typeof uit.setAnchorPoint === 'function') uit.setAnchorPoint(v, uit.anchorY);
else uit.anchorX = v;
});
bind('uay', function () {
var v = num('uay');
if (isNaN(v)) return;
if (typeof uit.setAnchorPoint === 'function') uit.setAnchorPoint(uit.anchorX, v);
else uit.anchorY = v;
});
}
if (node.components) {
for (var i = 0; i < node.components.length; i++) {
var comp = node.components[i];
if (!comp) continue;
var keys = Object.keys(comp);
for (var k = 0; k < keys.length; k++) {
var key = keys[k];
var id = 'c' + i + '_' + key;
var el = byFid(id);
if (!el) continue;
(function (component, prop, input) {
var apply = function () {
try {
var cur = component[prop];
if (typeof cur === 'number') {
var n = parseFloat(input.value);
if (!isNaN(n)) component[prop] = n;
} else if (typeof cur === 'boolean') {
component[prop] = !!input.checked;
} else if (typeof cur === 'string') {
component[prop] = input.value;
}
} catch (err) {
console.warn('[调试工作台] 组件属性失败', prop, err);
}
};
input.addEventListener('change', apply);
input.addEventListener('input', apply);
})(comp, key, el);
}
}
}
};
function fieldText(label, id, value) {
return '<label>' + escapeHtml(label) + '</label><input class="pw-input" data-fid="' + escapeAttr(id) + '" value="' + escapeAttr(value) + '" />';
}
function fieldNum(label, id, value) {
return '<label>' + escapeHtml(label) + '</label><input class="pw-input" type="number" step="any" data-fid="' + escapeAttr(id) + '" value="' + (value != null ? value : 0) + '" />';
}
function fieldCheck(label, id, value) {
return '<label>' + escapeHtml(label) + '</label><input type="checkbox" data-fid="' + escapeAttr(id) + '" ' + (value ? 'checked' : '') + ' />';
}
function escapeHtml(s) {
return String(s).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
}
function escapeAttr(s) {
return escapeHtml(s).replace(/"/g, '&quot;');
}
global.PWInspectorPanel = InspectorPanel;
})(window);