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.
242 lines
9.6 KiB
242 lines
9.6 KiB
(function (global) {
|
|
'use strict';
|
|
var WorkbenchLayout = global.PWLayout;
|
|
if (!WorkbenchLayout) {
|
|
console.error('[调试工作台] layout-render 需先加载 layout-core');
|
|
return;
|
|
}
|
|
var PANEL_TITLES = {
|
|
hierarchy: '层级',
|
|
inspector: '属性',
|
|
assets: '资源',
|
|
perf: '性能',
|
|
console: '控制台',
|
|
};
|
|
var SPLIT_SIZE = 4;
|
|
|
|
WorkbenchLayout.prototype._renderNode = function (node) {
|
|
if (!node) return null;
|
|
if (node.type === 'split') return this._renderSplit(node);
|
|
if (node.type === 'game') return this._renderGame(node);
|
|
return this._renderTabs(node);
|
|
};
|
|
|
|
WorkbenchLayout.prototype._renderSplit = function (node) {
|
|
var self = this;
|
|
this._ensureId(node);
|
|
var wrap = document.createElement('div');
|
|
wrap.className = 'pw-split-node pw-split-dir-' + (node.dir === 'v' ? 'v' : 'h');
|
|
wrap.setAttribute('data-node-id', node.id);
|
|
this._nodeEls[node.id] = { el: wrap, node: node };
|
|
var kids = node.children || [];
|
|
var sizes = node.sizes || [];
|
|
this._normalizeSizes(sizes, kids.length);
|
|
|
|
for (var i = 0; i < kids.length; i++) {
|
|
if (i > 0) {
|
|
(function (index) {
|
|
var splitter = document.createElement('div');
|
|
splitter.className = 'pw-splitter ' + (node.dir === 'v' ? 'pw-splitter-v' : 'pw-splitter-h');
|
|
splitter.addEventListener('pointerdown', function (ev) {
|
|
self._beginSplitDrag(ev, node, wrap, index - 1);
|
|
});
|
|
wrap.appendChild(splitter);
|
|
})(i);
|
|
}
|
|
var childWrap = document.createElement('div');
|
|
childWrap.className = 'pw-split-child';
|
|
childWrap.style.flex = String(sizes[i]) + ' 1 0';
|
|
childWrap.style.minWidth = '0';
|
|
childWrap.style.minHeight = '0';
|
|
var childEl = this._renderNode(kids[i]);
|
|
if (childEl) childWrap.appendChild(childEl);
|
|
wrap.appendChild(childWrap);
|
|
}
|
|
return wrap;
|
|
};
|
|
|
|
WorkbenchLayout.prototype._normalizeSizes = function (sizes, n) {
|
|
while (sizes.length < n) sizes.push(1 / n);
|
|
sizes.length = n;
|
|
var sum = 0;
|
|
for (var i = 0; i < n; i++) sum += sizes[i] || 0;
|
|
if (sum <= 0) {
|
|
for (var j = 0; j < n; j++) sizes[j] = 1 / n;
|
|
return;
|
|
}
|
|
for (var k = 0; k < n; k++) sizes[k] = sizes[k] / sum;
|
|
};
|
|
|
|
WorkbenchLayout.prototype._beginSplitDrag = function (ev, node, wrap, leftIndex) {
|
|
ev.preventDefault();
|
|
ev.stopPropagation();
|
|
var children = [];
|
|
for (var i = 0; i < wrap.children.length; i++) {
|
|
if (wrap.children[i].classList.contains('pw-split-child')) children.push(wrap.children[i]);
|
|
}
|
|
if (leftIndex < 0 || leftIndex >= children.length - 1) return;
|
|
var a = children[leftIndex];
|
|
var b = children[leftIndex + 1];
|
|
this._splitDrag = {
|
|
node: node,
|
|
dir: node.dir,
|
|
leftIndex: leftIndex,
|
|
startPos: node.dir === 'h' ? ev.clientX : ev.clientY,
|
|
a0: node.dir === 'h' ? a.getBoundingClientRect().width : a.getBoundingClientRect().height,
|
|
b0: node.dir === 'h' ? b.getBoundingClientRect().width : b.getBoundingClientRect().height,
|
|
aEl: a,
|
|
bEl: b,
|
|
};
|
|
var prevCursor = document.body.style.cursor;
|
|
document.body.style.cursor = node.dir === 'h' ? 'col-resize' : 'row-resize';
|
|
document.body.classList.add('pw-split-dragging');
|
|
// iframe 会吞掉 pointermove;拖动期间禁用命中
|
|
this._setGameIframePassThrough(true);
|
|
var target = ev.currentTarget || ev.target;
|
|
if (target && target.setPointerCapture && ev.pointerId != null) {
|
|
try { target.setPointerCapture(ev.pointerId); } catch (e) { /* */ }
|
|
}
|
|
var self = this;
|
|
var move = function (e) { self._onSplitMove(e); };
|
|
var up = function (e) {
|
|
window.removeEventListener('pointermove', move);
|
|
window.removeEventListener('pointerup', up);
|
|
window.removeEventListener('pointercancel', up);
|
|
if (target && target.releasePointerCapture && e && e.pointerId != null) {
|
|
try { target.releasePointerCapture(e.pointerId); } catch (err) { /* */ }
|
|
}
|
|
document.body.style.cursor = prevCursor || '';
|
|
document.body.classList.remove('pw-split-dragging');
|
|
self._setGameIframePassThrough(false);
|
|
self._splitDrag = null;
|
|
self._dirty = true;
|
|
self._save();
|
|
self._syncGameHostGeom();
|
|
self._notifyViewResize();
|
|
};
|
|
window.addEventListener('pointermove', move);
|
|
window.addEventListener('pointerup', up);
|
|
window.addEventListener('pointercancel', up);
|
|
};
|
|
|
|
/** @param {boolean} on */
|
|
WorkbenchLayout.prototype._setGameIframePassThrough = function (on) {
|
|
var iframe = document.getElementById('pw-game-iframe');
|
|
if (iframe) iframe.style.pointerEvents = on ? 'none' : '';
|
|
var host = this.gameHost;
|
|
if (host) host.classList.toggle('pw-iframe-passthrough', !!on);
|
|
};
|
|
|
|
WorkbenchLayout.prototype._onSplitMove = function (ev) {
|
|
var d = this._splitDrag;
|
|
if (!d) return;
|
|
var delta = (d.dir === 'h' ? ev.clientX : ev.clientY) - d.startPos;
|
|
var total = d.a0 + d.b0;
|
|
if (total <= 1) return;
|
|
var a1 = Math.max(80, Math.min(total - 80, d.a0 + delta));
|
|
var b1 = total - a1;
|
|
var ra = a1 / total;
|
|
var rb = b1 / total;
|
|
var baseA = d.node.sizes[d.leftIndex];
|
|
var baseB = d.node.sizes[d.leftIndex + 1];
|
|
var pair = baseA + baseB;
|
|
d.node.sizes[d.leftIndex] = pair * ra;
|
|
d.node.sizes[d.leftIndex + 1] = pair * rb;
|
|
d.aEl.style.flex = d.node.sizes[d.leftIndex] + ' 1 0';
|
|
d.bEl.style.flex = d.node.sizes[d.leftIndex + 1] + ' 1 0';
|
|
this._syncGameHostGeom();
|
|
};
|
|
|
|
WorkbenchLayout.prototype._renderGame = function (node) {
|
|
this._ensureId(node);
|
|
var leaf = document.createElement('div');
|
|
leaf.className = 'pw-leaf pw-leaf-game';
|
|
leaf.setAttribute('data-leaf-id', node.id);
|
|
leaf.setAttribute('data-node-id', node.id);
|
|
this._leafEls[node.id] = { el: leaf, node: node };
|
|
this._nodeEls[node.id] = { el: leaf, node: node };
|
|
var ph = document.createElement('div');
|
|
ph.className = 'pw-game-placeholder';
|
|
ph.setAttribute('data-game-placeholder', '1');
|
|
leaf.appendChild(ph);
|
|
this._gamePlaceholder = ph;
|
|
return leaf;
|
|
};
|
|
|
|
WorkbenchLayout.prototype._renderTabs = function (node) {
|
|
var self = this;
|
|
this._ensureId(node);
|
|
var leaf = document.createElement('div');
|
|
leaf.className = 'pw-leaf pw-leaf-tabs';
|
|
leaf.setAttribute('data-leaf-id', node.id);
|
|
leaf.setAttribute('data-node-id', node.id);
|
|
this._leafEls[node.id] = { el: leaf, node: node };
|
|
this._nodeEls[node.id] = { el: leaf, node: node };
|
|
|
|
var tabs = document.createElement('div');
|
|
tabs.className = 'pw-leaf-tabbar';
|
|
tabs.setAttribute('data-leaf-id', node.id);
|
|
|
|
var body = document.createElement('div');
|
|
body.className = 'pw-leaf-body';
|
|
body.setAttribute('data-leaf-id', node.id);
|
|
|
|
var panels = node.panels || [];
|
|
if (!panels.length) {
|
|
leaf.appendChild(tabs);
|
|
leaf.appendChild(body);
|
|
return leaf;
|
|
}
|
|
if (panels.indexOf(node.active) < 0) node.active = panels[0];
|
|
|
|
for (var i = 0; i < panels.length; i++) {
|
|
(function (pid) {
|
|
var tab = document.createElement('button');
|
|
tab.type = 'button';
|
|
tab.className = 'pw-leaf-tab' + (pid === node.active ? ' active' : '');
|
|
tab.textContent = PANEL_TITLES[pid] || pid;
|
|
tab.setAttribute('data-panel', pid);
|
|
tab.draggable = true;
|
|
tab.addEventListener('click', function (ev) {
|
|
ev.preventDefault();
|
|
if (node.active === pid) return;
|
|
node.active = pid;
|
|
// 仅切换页签内容,禁止 rebuild(会搬移/重排导致 iframe 重载)
|
|
self._activateTabLeaf(leaf, tabs, body, node);
|
|
self._save();
|
|
self._emitVisibility();
|
|
});
|
|
tab.addEventListener('dragstart', function (ev) {
|
|
self._beginDrag(pid, ev);
|
|
});
|
|
tabs.appendChild(tab);
|
|
})(panels[i]);
|
|
}
|
|
|
|
var activeEl = this._panelBodies[node.active];
|
|
if (activeEl) body.appendChild(activeEl);
|
|
|
|
leaf.appendChild(tabs);
|
|
leaf.appendChild(body);
|
|
return leaf;
|
|
};
|
|
|
|
/**
|
|
* 就地切换页签,不重建停靠树。
|
|
* @param {HTMLElement} leaf
|
|
* @param {HTMLElement} tabs
|
|
* @param {HTMLElement} body
|
|
* @param {object} node
|
|
*/
|
|
WorkbenchLayout.prototype._activateTabLeaf = function (leaf, tabs, body, node) {
|
|
var buttons = tabs.querySelectorAll('.pw-leaf-tab');
|
|
for (var i = 0; i < buttons.length; i++) {
|
|
var b = buttons[i];
|
|
b.classList.toggle('active', b.getAttribute('data-panel') === node.active);
|
|
}
|
|
while (body.firstChild) body.removeChild(body.firstChild);
|
|
var el = this._panelBodies[node.active];
|
|
if (el) body.appendChild(el);
|
|
};
|
|
|
|
})(window);
|
|
|