@woosh/meep-engine 2.84.9 → 2.84.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +27 -13
- package/build/meep.cjs +185 -87
- package/build/meep.min.js +1 -1
- package/build/meep.module.js +185 -87
- package/editor/process/symbolic/makePositionedIconDisplaySymbol.js +2 -4
- package/editor/view/EditorView.js +48 -204
- package/editor/view/ecs/HierarchicalEntityListView.js +191 -0
- package/editor/view/ecs/HierarchicalEntityListView.module.scss +13 -0
- package/editor/view/prepareMeshLibrary.js +178 -0
- package/editor/view/v2/SplitView.js +104 -0
- package/editor/view/v2/ViewManagementSystem.js +0 -0
- package/editor/view/v2/prototypeEditor.js +127 -0
- package/package.json +1 -1
- package/src/core/cache/Cache.d.ts +2 -0
- package/src/core/cache/Cache.js +58 -8
- package/src/core/cache/Cache.spec.js +38 -0
- package/src/core/cache/CacheElement.js +6 -0
- package/src/core/cache/LoadingCache.js +35 -4
- package/src/core/cache/LoadingCache.spec.js +44 -6
- package/src/core/collection/array/arraySetSortingDiff.js +6 -6
- package/src/core/collection/table/RowFirstTable.js +364 -368
- package/src/core/geom/3d/plane/plane3_compute_ray_intersection.js +3 -1
- package/src/core/geom/3d/topology/simplify/prototypeMeshSimplification.js +7 -7
- package/src/engine/animation/curve/ecd_bind_animation_curve.js +9 -0
- package/src/engine/graphics/ecs/mesh-v2/ShadedGeometryFlags.js +8 -1
- package/src/engine/graphics/ecs/mesh-v2/aggregate/prototypeSGMesh.js +23 -19
- package/src/engine/graphics/ecs/mesh-v2/sg_hierarchy_compute_bounding_box_via_parent_entity.js +2 -2
- package/src/engine/graphics/ecs/mesh-v2/three_object_to_entity_composition.js +3 -1
- package/src/view/View.js +64 -95
- package/src/view/setElementTransform.js +20 -0
- package/src/view/setElementVisibility.js +15 -0
|
@@ -4,37 +4,26 @@
|
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
import { passThrough } from "../../src/core/function/passThrough.js";
|
|
7
|
-
import { SurfacePoint3 } from "../../src/core/geom/3d/SurfacePoint3.js";
|
|
8
|
-
import Vector2 from "../../src/core/geom/Vector2.js";
|
|
9
|
-
import Vector3 from "../../src/core/geom/Vector3.js";
|
|
10
7
|
import { ProcessState } from "../../src/core/process/ProcessState.js";
|
|
11
|
-
import { obtainTerrain } from "../../src/engine/ecs/terrain/util/obtainTerrain.js";
|
|
12
|
-
import { Transform } from "../../src/engine/ecs/transform/Transform.js";
|
|
13
|
-
import Mesh from "../../src/engine/graphics/ecs/mesh/Mesh.js";
|
|
14
|
-
import { MeshEvents } from "../../src/engine/graphics/ecs/mesh/MeshEvents.js";
|
|
15
|
-
import { make_ray_from_viewport_position } from "../../src/engine/graphics/make_ray_from_viewport_position.js";
|
|
16
8
|
import LabelView from '../../src/view/common/LabelView.js';
|
|
17
9
|
import ListView from "../../src/view/common/ListView.js";
|
|
18
10
|
import VirtualListView from '../../src/view/common/VirtualListView.js';
|
|
19
11
|
import dom from "../../src/view/DOM.js";
|
|
20
|
-
import
|
|
12
|
+
import EmptyView from "../../src/view/elements/EmptyView.js";
|
|
21
13
|
|
|
22
14
|
import SimpleWindow from '../../src/view/elements/SimpleWindow.js';
|
|
23
15
|
import View from "../../src/view/View.js";
|
|
24
|
-
import ComponentAddAction from "../actions/concrete/ComponentAddAction.js";
|
|
25
|
-
import EntityCreateAction from "../actions/concrete/EntityCreateAction.js";
|
|
26
|
-
import SelectionAddAction from "../actions/concrete/SelectionAddAction.js";
|
|
27
|
-
import SelectionClearAction from "../actions/concrete/SelectionClearAction.js";
|
|
28
16
|
import ComponentControlFactory from './ecs/ComponentControlFactory.js';
|
|
29
17
|
import EntityEditorView from './ecs/EntityEditor.js';
|
|
30
18
|
|
|
31
19
|
import EntityListView from './ecs/EntityList.js';
|
|
20
|
+
import { HierarchicalEntityListView } from "./ecs/HierarchicalEntityListView.js";
|
|
32
21
|
import GridPickCoordinateView from "./GridPickCoordinateView.js";
|
|
33
|
-
import MeshLibraryView from "./library/MeshLibraryView.js";
|
|
34
22
|
import { makeEntityDecorators } from "./makeEntityDecorators.js";
|
|
35
23
|
import ProcessView from "./process/ProcessView.js";
|
|
36
24
|
import ToolSettingsView from "./tools/ToolSettingsView.js";
|
|
37
25
|
import ToolView from './tools/ToolView.js';
|
|
26
|
+
import { SplitView } from "./v2/SplitView.js";
|
|
38
27
|
|
|
39
28
|
|
|
40
29
|
class ViewManager extends View {
|
|
@@ -51,7 +40,13 @@ class ViewManager extends View {
|
|
|
51
40
|
this.memory = {};
|
|
52
41
|
}
|
|
53
42
|
|
|
54
|
-
|
|
43
|
+
/**
|
|
44
|
+
*
|
|
45
|
+
* @param {View} view
|
|
46
|
+
* @param {string} [title]
|
|
47
|
+
* @returns {SimpleWindowView}
|
|
48
|
+
*/
|
|
49
|
+
add(view, title = "") {
|
|
55
50
|
const simpleWindow = new SimpleWindow(
|
|
56
51
|
view,
|
|
57
52
|
{
|
|
@@ -118,171 +113,11 @@ class ViewManager extends View {
|
|
|
118
113
|
}
|
|
119
114
|
|
|
120
115
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
* @param {Editor} editor
|
|
124
|
-
*/
|
|
125
|
-
function prepareMeshLibrary(editor) {
|
|
126
|
-
let resolveEngine;
|
|
127
|
-
|
|
128
|
-
const pEngine = new Promise(function (resolve, reject) {
|
|
129
|
-
resolveEngine = resolve;
|
|
130
|
-
|
|
131
|
-
});
|
|
132
|
-
|
|
133
|
-
/**
|
|
134
|
-
*
|
|
135
|
-
* @type {Promise<GraphicsEngine>}
|
|
136
|
-
*/
|
|
137
|
-
const pGraphicsEngine = pEngine.then(function (e) {
|
|
138
|
-
return e.graphics;
|
|
139
|
-
});
|
|
140
|
-
|
|
141
|
-
const pRenderer = pGraphicsEngine.then(function (graphicsEngine) {
|
|
142
|
-
return graphicsEngine.renderer;
|
|
143
|
-
});
|
|
144
|
-
|
|
145
|
-
const pAssetManager = pEngine.then(e => e.assetManager);
|
|
146
|
-
|
|
147
|
-
const meshLibraryView = new MeshLibraryView(
|
|
148
|
-
editor.meshLibrary,
|
|
149
|
-
pAssetManager,
|
|
150
|
-
pRenderer
|
|
151
|
-
);
|
|
152
|
-
|
|
153
|
-
function handleDropEvent(event) {
|
|
154
|
-
event.stopPropagation();
|
|
155
|
-
event.preventDefault();
|
|
156
|
-
|
|
157
|
-
const dataText = event.dataTransfer.getData('text/json');
|
|
158
|
-
if (dataText === "") {
|
|
159
|
-
//no data
|
|
160
|
-
return;
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
const data = JSON.parse(dataText);
|
|
164
|
-
|
|
165
|
-
const type = data.type;
|
|
166
|
-
|
|
167
|
-
if (type !== "Mesh") {
|
|
168
|
-
//wrong type
|
|
169
|
-
return;
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
const url = data.url;
|
|
173
|
-
|
|
174
|
-
const engine = editor.engine;
|
|
175
|
-
const graphics = engine.graphics;
|
|
176
|
-
|
|
177
|
-
const position = new Vector2(event.clientX, event.clientY);
|
|
178
|
-
|
|
179
|
-
graphics.viewport.positionGlobalToLocal(position, position);
|
|
180
|
-
|
|
181
|
-
const normalizedPosition = new Vector2();
|
|
182
|
-
|
|
183
|
-
//compute world position for drop
|
|
184
|
-
const ray = make_ray_from_viewport_position(engine, position);
|
|
185
|
-
|
|
186
|
-
const source = ray.origin;
|
|
187
|
-
const direction = ray.direction;
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
const entityManager = engine.entityManager;
|
|
191
|
-
const ecd = entityManager.dataset;
|
|
192
|
-
|
|
193
|
-
const terrain = obtainTerrain(ecd);
|
|
194
|
-
|
|
195
|
-
const worldPosition = new Vector3();
|
|
196
|
-
|
|
197
|
-
const mesh = new Mesh();
|
|
198
|
-
|
|
199
|
-
mesh.castShadow = true;
|
|
200
|
-
mesh.receiveShadow = true;
|
|
201
|
-
|
|
202
|
-
const transform = new Transform();
|
|
203
|
-
|
|
204
|
-
const actions = editor.actions;
|
|
205
|
-
actions.mark('New Mesh Placed from Library');
|
|
206
|
-
const entityCreateAction = new EntityCreateAction();
|
|
207
|
-
actions.do(entityCreateAction);
|
|
208
|
-
|
|
209
|
-
const sp3 = new SurfacePoint3();
|
|
210
|
-
|
|
211
|
-
const hit_found = terrain.raycastFirstSync(sp3, source.x, source.y, source.z, direction.x, direction.y, direction.z);
|
|
212
|
-
|
|
213
|
-
function handleMeshSetEvent() {
|
|
214
|
-
const bb = mesh.boundingBox;
|
|
215
|
-
|
|
216
|
-
const c0 = new Vector3(bb.x0, bb.y0, bb.z0);
|
|
217
|
-
const c1 = new Vector3(bb.x1, bb.y1, bb.z1);
|
|
218
|
-
|
|
219
|
-
const diagonal = c0.distanceTo(c1);
|
|
220
|
-
|
|
221
|
-
const offset = direction.clone().multiplyScalar(diagonal);
|
|
222
|
-
|
|
223
|
-
transform.position.add(offset);
|
|
224
|
-
|
|
225
|
-
//remove listener
|
|
226
|
-
ecd.removeEntityEventListener(entityCreateAction.entity, MeshEvents.DataSet, handleMeshSetEvent);
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
if (hit_found) {
|
|
230
|
-
//got a terrain ray hit, set world placement position to that point
|
|
231
|
-
worldPosition.copy(sp3.position);
|
|
232
|
-
} else {
|
|
233
|
-
//set position to the source of the ray pick if there's nothing else available
|
|
234
|
-
worldPosition.copy(source);
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
//wait for mesh to load
|
|
238
|
-
ecd.addEntityEventListener(entityCreateAction.entity, MeshEvents.DataSet, handleMeshSetEvent);
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
transform.position.copy(worldPosition);
|
|
242
|
-
|
|
243
|
-
mesh.url = url;
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
actions.doMany([
|
|
247
|
-
new ComponentAddAction(entityCreateAction.entity, transform),
|
|
248
|
-
new ComponentAddAction(entityCreateAction.entity, mesh),
|
|
249
|
-
//automatically select newly placed object
|
|
250
|
-
new SelectionClearAction(),
|
|
251
|
-
new SelectionAddAction([entityCreateAction.entity])
|
|
252
|
-
]);
|
|
253
|
-
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
function handleDragOverEvent(event) {
|
|
257
|
-
event.preventDefault();
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
meshLibraryView.on.linked.add(function () {
|
|
262
|
-
resolveEngine(editor.engine);
|
|
263
|
-
|
|
264
|
-
const viewport = editor.engine.graphics.viewport;
|
|
265
|
-
|
|
266
|
-
viewport.el.addEventListener('drop', handleDropEvent);
|
|
267
|
-
viewport.el.addEventListener('dragover', handleDragOverEvent);
|
|
268
|
-
});
|
|
269
|
-
|
|
270
|
-
meshLibraryView.on.unlinked.add(function () {
|
|
271
|
-
const viewport = editor.engine.graphics.viewport;
|
|
272
|
-
|
|
273
|
-
viewport.el.removeEventListener('drop', handleDropEvent);
|
|
274
|
-
viewport.el.removeEventListener('dragover', handleDragOverEvent);
|
|
275
|
-
});
|
|
276
|
-
|
|
277
|
-
meshLibraryView.size.set(400, 400);
|
|
116
|
+
class EditorView extends View {
|
|
117
|
+
main = new EmptyView()
|
|
278
118
|
|
|
279
|
-
|
|
280
|
-
meshLibraryView.addChild(resizeHandleView);
|
|
119
|
+
mainViewport = new EmptyView();
|
|
281
120
|
|
|
282
|
-
return meshLibraryView;
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
class EditorView extends View {
|
|
286
121
|
/**
|
|
287
122
|
*
|
|
288
123
|
* @param {Editor} editor
|
|
@@ -311,6 +146,11 @@ class EditorView extends View {
|
|
|
311
146
|
const decorators = makeEntityDecorators();
|
|
312
147
|
|
|
313
148
|
|
|
149
|
+
const entity_list_view = new HierarchicalEntityListView();
|
|
150
|
+
|
|
151
|
+
entity_list_view.dataset = editor.engine.entityManager.dataset;
|
|
152
|
+
entity_list_view.on.interact.add(inspectEntity);
|
|
153
|
+
|
|
314
154
|
const entityListView = new EntityListView({ editor, decorators });
|
|
315
155
|
this.entityListView = entityListView;
|
|
316
156
|
|
|
@@ -324,6 +164,8 @@ class EditorView extends View {
|
|
|
324
164
|
const em = editor.engine.entityManager;
|
|
325
165
|
entityEditor.entityManager.set(em);
|
|
326
166
|
entityEditor.model.set(entity);
|
|
167
|
+
|
|
168
|
+
entity_list_view.selection = [entity];
|
|
327
169
|
}
|
|
328
170
|
|
|
329
171
|
this.bindSignal(editor.selection.on.added, function (entity) {
|
|
@@ -339,7 +181,6 @@ class EditorView extends View {
|
|
|
339
181
|
const toolSettings = new ToolSettingsView({});
|
|
340
182
|
this.toolSettings = toolSettings;
|
|
341
183
|
|
|
342
|
-
//tool bar
|
|
343
184
|
const toolBar = new ListView(editor.toolEngine.tools, {
|
|
344
185
|
elementFactory: function (tool) {
|
|
345
186
|
const toolView = new ToolView({ tool, editor });
|
|
@@ -398,46 +239,46 @@ class EditorView extends View {
|
|
|
398
239
|
this.selectionView = selectionView;
|
|
399
240
|
|
|
400
241
|
|
|
401
|
-
|
|
402
|
-
this.coordinateView = coordinateView;
|
|
403
|
-
|
|
404
|
-
this.meshLibraryView = prepareMeshLibrary(editor);
|
|
405
|
-
this.meshLibraryView.size.set(340, 200);
|
|
242
|
+
this.coordinateView = new GridPickCoordinateView(editor);
|
|
406
243
|
|
|
407
244
|
//
|
|
408
245
|
this.bindSignal(this.size.onChanged, this.layout.bind(this));
|
|
409
246
|
|
|
410
247
|
|
|
411
|
-
this.addChild(this.coordinateView);
|
|
412
|
-
this.addChild(this.selectionView);
|
|
413
|
-
this.addChild(this.
|
|
414
|
-
this.addChild(this.
|
|
415
|
-
this.addChild(this.
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
248
|
+
this.mainViewport.addChild(this.coordinateView);
|
|
249
|
+
this.mainViewport.addChild(this.selectionView);
|
|
250
|
+
this.mainViewport.addChild(this.toolBar);
|
|
251
|
+
this.mainViewport.addChild(this.processBar);
|
|
252
|
+
this.mainViewport.addChild(this.toolSettings);
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
const split = SplitView.from({
|
|
256
|
+
fraction: 0.2,
|
|
257
|
+
a: entity_list_view,
|
|
258
|
+
b: SplitView.from({
|
|
259
|
+
fraction: 0.7,
|
|
260
|
+
a: this.mainViewport,
|
|
261
|
+
b: this.entityEditor,
|
|
262
|
+
})
|
|
263
|
+
});
|
|
264
|
+
this.main.addChild(split);
|
|
265
|
+
|
|
266
|
+
this.main.size.onChanged.add(split.size.set, split.size);
|
|
267
|
+
|
|
268
|
+
this.addChild(this.main);
|
|
419
269
|
}
|
|
420
270
|
|
|
421
271
|
layout() {
|
|
422
272
|
const size = this.size;
|
|
423
273
|
|
|
424
|
-
this.
|
|
425
|
-
this.entityEditor.position.set(size.x - this.entityEditor.size.x, 0);
|
|
426
|
-
|
|
427
|
-
this.entityListView.size.set(200, size.y);
|
|
428
|
-
this.entityListView.position.set(0, 0);
|
|
429
|
-
|
|
274
|
+
this.main.size.copy(size);
|
|
430
275
|
if (this.gameView !== null) {
|
|
431
|
-
this.gameView.position.set(this.entityListView.position.x + this.entityListView.size.x, 0);
|
|
432
|
-
this.gameView.size.set(size.x - (this.entityEditor.size.x + this.entityListView.size.x), size.y);
|
|
433
|
-
|
|
434
276
|
this.toolBar.size.set(this.gameView.size.x, 36);
|
|
435
277
|
this.toolBar.position.set(this.gameView.position.x + 5, this.gameView.position.y + this.gameView.size.y - (this.toolBar.size.y + 5));
|
|
436
278
|
|
|
437
279
|
// this.processBar.size.set(this.gameView.size.x, 36);
|
|
438
280
|
// this.processBar.position.set(this.toolBar.position.x, 5);
|
|
439
281
|
|
|
440
|
-
this.meshLibraryView.position.set(this.gameView.position.x + this.gameView.size.x - (this.meshLibraryView.size.x + 5), 5);
|
|
441
282
|
}
|
|
442
283
|
}
|
|
443
284
|
|
|
@@ -446,7 +287,9 @@ class EditorView extends View {
|
|
|
446
287
|
|
|
447
288
|
//hijack game view from the engine
|
|
448
289
|
this.gameView = this.editor.engine.gameView;
|
|
449
|
-
this.addChild(this.gameView);
|
|
290
|
+
this.mainViewport.addChild(this.gameView);
|
|
291
|
+
|
|
292
|
+
this.mainViewport.size.onChanged.add(this.gameView.size.set, this.gameView.size);
|
|
450
293
|
|
|
451
294
|
this.layout();
|
|
452
295
|
}
|
|
@@ -455,7 +298,8 @@ class EditorView extends View {
|
|
|
455
298
|
super.unlink();
|
|
456
299
|
if (this.gameView !== null) {
|
|
457
300
|
//release game view
|
|
458
|
-
this.removeChild(this.gameView);
|
|
301
|
+
this.mainViewport.removeChild(this.gameView);
|
|
302
|
+
this.mainViewport.size.onChanged.remove(this.gameView.size.set, this.gameView.size);
|
|
459
303
|
this.gameView = null;
|
|
460
304
|
}
|
|
461
305
|
}
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import Name from "../../../../model/game/ecs/component/Name.js";
|
|
2
|
+
import { arraySetSortingDiff } from "../../../src/core/collection/array/arraySetSortingDiff.js";
|
|
3
|
+
import List from "../../../src/core/collection/list/List.js";
|
|
4
|
+
import Signal from "../../../src/core/events/signal/Signal.js";
|
|
5
|
+
import { number_compare_ascending } from "../../../src/core/primitives/numbers/number_compare_ascending.js";
|
|
6
|
+
import { ParentEntity } from "../../../src/engine/ecs/parent/ParentEntity.js";
|
|
7
|
+
import { MouseEvents } from "../../../src/engine/input/devices/events/MouseEvents.js";
|
|
8
|
+
import LabelView from "../../../src/view/common/LabelView.js";
|
|
9
|
+
import ListView from "../../../src/view/common/ListView.js";
|
|
10
|
+
import EmptyView from "../../../src/view/elements/EmptyView.js";
|
|
11
|
+
import style from "./HierarchicalEntityListView.module.scss";
|
|
12
|
+
|
|
13
|
+
export class HierarchicalEntityListView extends EmptyView {
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
*
|
|
17
|
+
* @type {EntityComponentDataset|null}
|
|
18
|
+
*/
|
|
19
|
+
#dataset = null;
|
|
20
|
+
|
|
21
|
+
#roots = new List();
|
|
22
|
+
|
|
23
|
+
#child_map = new Map();
|
|
24
|
+
|
|
25
|
+
#selected = new List();
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
#update_roots() {
|
|
29
|
+
const new_roots = [];
|
|
30
|
+
|
|
31
|
+
const ecd = this.#dataset;
|
|
32
|
+
|
|
33
|
+
ecd.traverseEntityIndices(id => {
|
|
34
|
+
|
|
35
|
+
const parent = ecd.getComponent(id, ParentEntity);
|
|
36
|
+
|
|
37
|
+
if (parent !== undefined) {
|
|
38
|
+
const childMap = this.#child_map;
|
|
39
|
+
let children = childMap.get(parent.entity);
|
|
40
|
+
if (children === undefined) {
|
|
41
|
+
children = [];
|
|
42
|
+
childMap.set(parent.entity, children);
|
|
43
|
+
}
|
|
44
|
+
children.push(id);
|
|
45
|
+
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
new_roots.push(id);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
// perform patch
|
|
53
|
+
const diff = arraySetSortingDiff(new_roots, this.#roots.asArray(), number_compare_ascending);
|
|
54
|
+
|
|
55
|
+
for (let i = 0; i < diff.uniqueB.length; i++) {
|
|
56
|
+
const removal_id = diff.uniqueB[i];
|
|
57
|
+
|
|
58
|
+
this.#roots.removeOneOf(removal_id);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
for (let i = 0; i < diff.uniqueA.length; i++) {
|
|
63
|
+
const addition_id = diff.uniqueA[i];
|
|
64
|
+
|
|
65
|
+
this.#roots.add(addition_id);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
set selection(entities) {
|
|
70
|
+
this.#selected.patch(entities);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
set dataset(v) {
|
|
74
|
+
this.#roots.reset();
|
|
75
|
+
|
|
76
|
+
this.#dataset = v;
|
|
77
|
+
|
|
78
|
+
this.#update_roots();
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
*
|
|
83
|
+
* @param {number} entity
|
|
84
|
+
*/
|
|
85
|
+
#make_entity_view(entity) {
|
|
86
|
+
|
|
87
|
+
const ecd = this.#dataset;
|
|
88
|
+
|
|
89
|
+
const children = this.#child_map.get(entity);
|
|
90
|
+
|
|
91
|
+
const has_children = children !== undefined;
|
|
92
|
+
|
|
93
|
+
const entity_view = new EmptyView({
|
|
94
|
+
classList:[style.entityView],
|
|
95
|
+
css: {
|
|
96
|
+
position: 'relative',
|
|
97
|
+
pointerEvents: "auto",
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
let label_text = `${entity}`;
|
|
102
|
+
|
|
103
|
+
const name = ecd.getComponent(entity, Name);
|
|
104
|
+
|
|
105
|
+
if (name !== undefined) {
|
|
106
|
+
label_text += `: ${name}`
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
entity_view.addChild(new LabelView(label_text, {
|
|
110
|
+
css: {
|
|
111
|
+
position: 'relative'
|
|
112
|
+
}
|
|
113
|
+
}));
|
|
114
|
+
|
|
115
|
+
if (has_children) {
|
|
116
|
+
|
|
117
|
+
const children_container = new EmptyView({
|
|
118
|
+
css: {
|
|
119
|
+
paddingLeft: "8px"
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
for (let i = 0; i < children.length; i++) {
|
|
124
|
+
|
|
125
|
+
const child = children[i];
|
|
126
|
+
|
|
127
|
+
const child_view = this.#make_entity_view(child);
|
|
128
|
+
|
|
129
|
+
children_container.addChild(child_view);
|
|
130
|
+
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
entity_view.addChild(children_container);
|
|
134
|
+
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
entity_view.el.addEventListener(MouseEvents.Click, (evt) => {
|
|
138
|
+
this.on.interact.send1(entity);
|
|
139
|
+
|
|
140
|
+
evt.stopPropagation();
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
const update_selection = () => {
|
|
145
|
+
const is_selected = this.#selected.contains(entity);
|
|
146
|
+
|
|
147
|
+
entity_view.setClass("selected", is_selected);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
entity_view.bindSignal(this.#selected.on.added, update_selection);
|
|
151
|
+
entity_view.bindSignal(this.#selected.on.removed, update_selection);
|
|
152
|
+
entity_view.on.linked.add(update_selection);
|
|
153
|
+
|
|
154
|
+
return entity_view;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
constructor() {
|
|
158
|
+
super();
|
|
159
|
+
|
|
160
|
+
const listView = new ListView(this.#roots, {
|
|
161
|
+
classList: [
|
|
162
|
+
style.main
|
|
163
|
+
],
|
|
164
|
+
elementFactory: (entity) => {
|
|
165
|
+
|
|
166
|
+
return this.#make_entity_view(entity);
|
|
167
|
+
},
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
listView.css({
|
|
171
|
+
display: 'flex',
|
|
172
|
+
flexDirection: 'column'
|
|
173
|
+
})
|
|
174
|
+
|
|
175
|
+
this.size.onChanged.add(listView.size.set, listView.size);
|
|
176
|
+
|
|
177
|
+
this.on.interact = new Signal();
|
|
178
|
+
|
|
179
|
+
this.addChild(listView);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
link() {
|
|
183
|
+
super.link();
|
|
184
|
+
|
|
185
|
+
this.#update_roots();
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
unlink() {
|
|
189
|
+
super.unlink();
|
|
190
|
+
}
|
|
191
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
.main {
|
|
2
|
+
padding-left: 2px;
|
|
3
|
+
background: white;
|
|
4
|
+
|
|
5
|
+
overflow-y: auto; // enable scrolling
|
|
6
|
+
pointer-events: auto; // enable scroll-bar to capture pointer events
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
.entityView:nth-child(2n) {
|
|
10
|
+
padding-top: 1px;
|
|
11
|
+
padding-bottom: 1px;
|
|
12
|
+
background: #efefef;
|
|
13
|
+
}
|