@woosh/meep-engine 2.37.16 → 2.37.19

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.
Files changed (122) hide show
  1. package/core/assert.js +16 -2
  2. package/core/collection/array/typed/isTypedArray.js +20 -0
  3. package/core/collection/array/typedArrayToDataType.js +2 -1
  4. package/core/collection/table/RowFirstTable.js +34 -0
  5. package/core/collection/table/RowFirstTable.spec.js +59 -1
  6. package/core/color/Color.js +14 -0
  7. package/core/color/rgb2hex.js +1 -1
  8. package/core/events/signal/Signal.js +8 -8
  9. package/core/events/signal/Signal.spec.js +16 -0
  10. package/core/geom/Quaternion.d.ts +5 -0
  11. package/core/geom/Quaternion.js +152 -137
  12. package/core/geom/Quaternion.spec.js +47 -2
  13. package/core/geom/Vector3.schema.json +16 -0
  14. package/core/json/JsonUtils.js +2 -20
  15. package/core/model/ObservedEnum.js +8 -0
  16. package/editor/Editor.js +97 -1
  17. package/editor/actions/concrete/PatchTerrainHeightAction.js +1 -1
  18. package/editor/ecs/component/FieldDescriptor.js +34 -0
  19. package/editor/ecs/component/FieldValueAdapter.js +20 -0
  20. package/editor/ecs/component/TypeEditor.js +33 -0
  21. package/editor/ecs/component/TypeSchema.d.ts +38 -0
  22. package/editor/ecs/component/createFieldEditor.js +90 -0
  23. package/editor/ecs/component/createObjectEditor.js +242 -60
  24. package/editor/ecs/component/editors/ColorEditor.js +39 -0
  25. package/editor/ecs/component/editors/HTMLElementEditor.js +17 -0
  26. package/editor/ecs/component/editors/ImagePathEditor.js +50 -0
  27. package/editor/ecs/component/editors/NumericIntervalEditor.js +86 -0
  28. package/editor/ecs/component/editors/ObservedBooleanEditor.js +13 -0
  29. package/editor/ecs/component/editors/ObservedEnumEditor.js +32 -0
  30. package/editor/ecs/component/editors/ObservedIntegerEditor.js +43 -0
  31. package/editor/ecs/component/editors/ObservedStringEditor.js +51 -0
  32. package/editor/ecs/component/editors/Sampler2DEditor.js +60 -0
  33. package/editor/ecs/component/editors/collection/ListEditor.js +83 -0
  34. package/editor/ecs/component/editors/common/BitFlagsEditor.js +80 -0
  35. package/editor/ecs/component/editors/common/EnumEditor.js +41 -0
  36. package/editor/ecs/component/editors/common/makeV3_editor.js +85 -0
  37. package/editor/ecs/component/editors/common/noEditor.js +9 -0
  38. package/editor/ecs/component/editors/ecs/GridObstacleEditor.js +17 -0
  39. package/editor/ecs/component/editors/ecs/MinimapMarkerEditor.js +16 -0
  40. package/editor/ecs/component/editors/ecs/ParameterLookupTableEditor.js +44 -0
  41. package/editor/ecs/component/editors/ecs/ParameterTrackEditor.js +17 -0
  42. package/editor/ecs/component/editors/ecs/ParticleEmitterEditor.js +58 -0
  43. package/editor/ecs/component/editors/ecs/ParticleEmitterLayerEditor.js +54 -0
  44. package/editor/ecs/component/editors/ecs/SimulationStepDefinitionEditor.js +21 -0
  45. package/editor/ecs/component/editors/ecs/Trail2DEditor.js +33 -0
  46. package/editor/ecs/component/editors/ecs/TransformEditor.js +23 -0
  47. package/editor/ecs/component/editors/ecs/terrain/SplatMappingEditor.js +21 -0
  48. package/editor/ecs/component/editors/ecs/terrain/TerrainEditor.js +42 -0
  49. package/editor/ecs/component/editors/ecs/terrain/TerrainLayerEditor.js +18 -0
  50. package/editor/ecs/component/editors/ecs/terrain/TerrainLayersEditor.js +22 -0
  51. package/editor/ecs/component/editors/ecs/terrain/TerrainOverlayEditor.js +20 -0
  52. package/editor/ecs/component/editors/geom/QuaternionEditor.js +56 -0
  53. package/editor/ecs/component/editors/geom/Vector1Editor.js +57 -0
  54. package/editor/ecs/component/editors/geom/Vector2Editor.js +11 -0
  55. package/editor/ecs/component/editors/geom/Vector3Editor.js +13 -0
  56. package/editor/ecs/component/editors/geom/Vector4Editor.js +12 -0
  57. package/editor/ecs/component/editors/primitive/ArrayEditor.js +46 -0
  58. package/editor/ecs/component/editors/primitive/BooleanEditor.js +27 -0
  59. package/editor/ecs/component/editors/primitive/FunctionEditor.js +25 -0
  60. package/editor/ecs/component/editors/primitive/NumberEditor.js +60 -0
  61. package/editor/ecs/component/editors/primitive/ObjectEditor.js +12 -0
  62. package/editor/ecs/component/editors/primitive/StringEditor.js +31 -0
  63. package/editor/ecs/component/editors/three/BufferGeometryEditor.js +28 -0
  64. package/editor/ecs/component/editors/three/MaterialEditor.js +27 -0
  65. package/editor/ecs/component/editors/three/MeshEditor.js +35 -0
  66. package/editor/ecs/component/editors/three/TextureEditor.js +32 -0
  67. package/editor/ecs/component/findNearestRegisteredType.js +59 -0
  68. package/editor/ecs/component/prototypeObjectEditor.js +379 -0
  69. package/editor/view/EditorView.js +1 -1
  70. package/editor/view/ecs/ComponentControlView.js +2 -30
  71. package/editor/view/ecs/EntityEditor.js +61 -139
  72. package/editor/view/ecs/components/GridObstacleController.js +4 -4
  73. package/editor/view/ecs/components/TerrainController.js +1 -1
  74. package/editor/view/ecs/components/common/NumberController.js +19 -7
  75. package/engine/animation/keyed2/AnimationTrack.js +1 -1
  76. package/engine/asset/AssetManager.js +1 -1
  77. package/engine/ecs/EntityBlueprint.js +1 -1
  78. package/engine/ecs/EntityBuilder.js +2 -2
  79. package/engine/ecs/EntityManager.js +1 -1
  80. package/engine/ecs/components/TagEditor.js +15 -0
  81. package/engine/ecs/parent/EntityNode.js +3 -0
  82. package/engine/ecs/storage/binary/object/BinaryObjectSerializationAdapter.js +1 -1
  83. package/engine/ecs/terrain/ecs/Terrain.js +23 -42
  84. package/engine/ecs/terrain/ecs/TerrainSystem.js +2 -2
  85. package/engine/ecs/terrain/ecs/layers/TerrainLayer.js +1 -1
  86. package/engine/ecs/terrain/util/loadVisibleTerrainTiles.js +1 -1
  87. package/engine/ecs/transform/Transform.editor.schema.json +16 -0
  88. package/engine/ecs/transform/Transform.js +3 -0
  89. package/engine/ecs/util/hideEntityGracefully.js +4 -2
  90. package/engine/graphics/ecs/highlight/HighlightEditor.js +17 -0
  91. package/engine/graphics/ecs/mesh/MeshEditor.js +28 -0
  92. package/engine/graphics/ecs/mesh-v2/aggregate/prototypeSGMesh.js +3 -3
  93. package/engine/graphics/micron/render/instanced/shader/shader_rewrite_standard.js +15 -15
  94. package/engine/graphics/particles/particular/engine/ParticularEngine.js +5 -0
  95. package/engine/graphics/texture/sampler/Sampler2D.js +16 -0
  96. package/engine/graphics/util/ScaleObject3ToBox.js +14 -1
  97. package/engine/graphics/util/makeMeshPreviewScene.js +2 -1
  98. package/engine/grid/components/GridObstacle.js +0 -44
  99. package/engine/grid/components/GridObstacleSerializationAdapter.js +46 -0
  100. package/engine/knowledge/database/StaticKnowledgeDatabase.js +1 -1
  101. package/engine/navigation/ecs/components/Path.d.ts +2 -0
  102. package/engine/navigation/ecs/components/Path.js +6 -1
  103. package/engine/sound/material/concrete/json/serializeSoundMaterialToJSON.js +1 -1
  104. package/generation/example/SampleGenerator0.js +33 -29
  105. package/generation/example/generators/interactive/mir_generator_place_buff_objects.js +7 -6
  106. package/generation/example/generators/mir_generator_place_bases.js +7 -3
  107. package/generation/example/generators/mir_generator_place_road_decorators.js +3 -3
  108. package/generation/example/generators/mir_generator_place_starting_point.js +3 -2
  109. package/generation/markers/GridCellActionPlaceMarker.js +9 -3
  110. package/generation/markers/transform/MarkerNodeTransformerOffsetPosition.js +1 -1
  111. package/generation/placement/GridCellPlacementRule.js +22 -23
  112. package/generation/theme/ThemeEngine.js +1 -1
  113. package/package.json +1 -1
  114. package/samples/terrain/main.js +1 -1
  115. package/view/View.js +23 -1
  116. package/view/common/LabelView.js +1 -1
  117. package/view/compose3x3transform.js +32 -8
  118. package/view/controller/dat/DatGuiUtils.js +1 -1
  119. package/view/elements/DropDownSelectionView.js +11 -3
  120. package/view/elements/image/ImageView.js +3 -1
  121. package/core/model/ObservedReal.js +0 -55
  122. package/editor/ecs/component/ObjectEditor.js +0 -0
@@ -0,0 +1,34 @@
1
+ /**
2
+ * @template T
3
+ */
4
+ export class FieldDescriptor {
5
+ constructor() {
6
+ /**
7
+ *
8
+ * @type {string}
9
+ */
10
+ this.name = "";
11
+
12
+ /**
13
+ * typeof field
14
+ * @type {Class<T>}
15
+ */
16
+ this.type = null;
17
+
18
+ /**
19
+ *
20
+ * @type {FieldValueAdapter|null}
21
+ */
22
+ this.adapter = null;
23
+
24
+ /**
25
+ *
26
+ * @type {{}|undefined}
27
+ */
28
+ this.schema = undefined;
29
+ }
30
+
31
+ toString() {
32
+ return `FieldDescriptor[name='${this.name}']`;
33
+ }
34
+ }
@@ -0,0 +1,20 @@
1
+ import { assert } from "../../../core/assert.js";
2
+
3
+ export class FieldValueAdapter {
4
+ constructor() {
5
+ this.writable = true;
6
+ this.readable = true;
7
+
8
+ }
9
+
10
+ read(object, field_name) {
11
+ assert.isString(field_name, 'field_name');
12
+
13
+
14
+ return object[field_name];
15
+ }
16
+
17
+ write(object, field_name, value) {
18
+ object[field_name] = value;
19
+ }
20
+ }
@@ -0,0 +1,33 @@
1
+ /**
2
+ * @class
3
+ * @template T
4
+ */
5
+ export class TypeEditor {
6
+ inline = true;
7
+
8
+ /**
9
+ * Class is hidden and editor should not be displayed
10
+ * @returns {boolean}
11
+ */
12
+ get hidden() {
13
+ return false;
14
+ }
15
+
16
+ /**
17
+ *
18
+ * @returns {TypeSchema|undefined}
19
+ */
20
+ get schema() {
21
+ return undefined;
22
+ }
23
+
24
+ /**
25
+ * @param {*} parent
26
+ * @param {FieldDescriptor} field
27
+ * @param {Map<*, TypeEditor>} registry
28
+ * @returns {View|void}
29
+ */
30
+ build(parent, field, registry) {
31
+ throw new Error('Not Implemented');
32
+ }
33
+ }
@@ -0,0 +1,38 @@
1
+ import {DataType} from "../../../core/parser/simple/DataType";
2
+
3
+ interface Type<T> extends Function {
4
+ new(...args: any[]): T;
5
+ }
6
+
7
+ interface PropertiesSchema {
8
+ [key: string]: FieldSchema<any>;
9
+ }
10
+
11
+ export interface TypeSchema {
12
+ additionalProperties?: boolean
13
+ properties: PropertiesSchema
14
+ }
15
+
16
+ interface TypeEditor {
17
+
18
+ }
19
+
20
+ export interface FieldSchema<T> {
21
+ type: Type<T>
22
+ type_parameters?: any[]
23
+ transient?: boolean
24
+ description?: string,
25
+ editor?: TypeEditor
26
+ deprecated?: boolean,
27
+ enum?: T[],
28
+ numeric_type: DataType,
29
+ /**
30
+ * Small image to be displayed next to field name
31
+ */
32
+ thumbnail: string,
33
+ /**
34
+ * @see https://datatracker.ietf.org/doc/html/draft-bhutton-json-schema-validation-00#section-6.2.2
35
+ */
36
+ maximum?: number,
37
+ minimum?: number
38
+ }
@@ -0,0 +1,90 @@
1
+ import EmptyView from "../../../view/elements/EmptyView.js";
2
+ import LabelView from "../../../view/common/LabelView.js";
3
+
4
+ function format_field_name(name) {
5
+ return name
6
+ .replace(/([a-z])([A-Z])/g, '$1 $2') // break up camel case
7
+ .replace(/([^.])_([^.])/g, '$1 $2') // break up underscore case
8
+ .replace(/(^\w{1})|(\s+\w{1})/g, letter => letter.toUpperCase()); // capitalize every word
9
+ }
10
+
11
+ /**
12
+ * @template CTX
13
+ * @param {Object} object
14
+ * @param {FieldDescriptor} field
15
+ * @param {Map<*, TypeEditor>} registry
16
+ */
17
+ export function createFieldEditor(object, field, registry) {
18
+
19
+ const field_schema = field.schema;
20
+
21
+ let vValue;
22
+
23
+ /**
24
+ * @type {TypeEditor}
25
+ */
26
+ let factory;
27
+ if (field_schema !== undefined) {
28
+ const specific_field_editor = field_schema.editor;
29
+
30
+ if (specific_field_editor !== undefined) {
31
+ // field has a dedicated editor
32
+ factory = specific_field_editor;
33
+ }
34
+ }
35
+
36
+ if (factory === undefined) {
37
+ factory = registry.get(field.type);
38
+ }
39
+
40
+ let orientation_inline = true;
41
+
42
+ if (factory !== undefined) {
43
+ if (factory.hidden) {
44
+ // hidden class
45
+ return null;
46
+ }
47
+
48
+ vValue = factory.build(object, field, registry);
49
+
50
+ if (vValue) {
51
+ orientation_inline = factory.inline;
52
+ }
53
+ }
54
+
55
+ if (vValue === null || vValue === undefined) {
56
+ // no view
57
+ return null;
58
+ }
59
+
60
+ const vResult = new EmptyView({
61
+ classList: ['auto-field-editor']
62
+ });
63
+
64
+ if (orientation_inline) {
65
+ vResult.addClass('orientation-inline');
66
+ }
67
+
68
+ const field_formatted_name = format_field_name(field.name);
69
+
70
+ const vLabel = new LabelView(field_formatted_name, { classList: ['field-name'] });
71
+
72
+ vResult.addChild(vLabel);
73
+ vResult.addChild(vValue);
74
+
75
+
76
+ if (field_schema !== undefined) {
77
+ if (field_schema.description !== undefined && field_schema.description.length > 0) {
78
+ // add tooltip
79
+ vLabel.attr({
80
+ title: field_schema.description
81
+ });
82
+ }
83
+
84
+ if (field_schema.deprecated) {
85
+ vResult.addClass('field-deprecated');
86
+ }
87
+ }
88
+
89
+ return vResult;
90
+ }
@@ -1,52 +1,30 @@
1
1
  import EmptyView from "../../../view/elements/EmptyView.js";
2
+ import { FieldDescriptor } from "./FieldDescriptor.js";
3
+ import { FieldValueAdapter } from "./FieldValueAdapter.js";
4
+ import { createFieldEditor } from "./createFieldEditor.js";
5
+ import { findNearestRegisteredType } from "./findNearestRegisteredType.js";
2
6
  import LabelView from "../../../view/common/LabelView.js";
3
7
 
4
- class FieldValueAdapter {
5
- read(object, field_name) {
6
-
7
- }
8
-
9
- write(object, field_name, value) {
10
-
11
- }
12
- }
13
-
14
8
  /**
15
9
  * @template T
10
+ * @param {T|undefined} value
16
11
  */
17
- class FieldDescriptor {
18
- constructor() {
19
- /**
20
- *
21
- * @type {string}
22
- */
23
- this.name = "";
24
-
25
- /**
26
- * typeof field
27
- * @type {Class<T>}
28
- */
29
- this.type = null;
30
-
31
- /**
32
- *
33
- * @type {FieldValueAdapter|null}
34
- */
35
- this.adapter = null;
36
-
12
+ function objectToClass(value) {
13
+ if (value === null || value === undefined) {
14
+ return;
37
15
  }
38
- }
39
16
 
40
- /**
41
- * @template T
42
- * @param {T} value
43
- */
44
- function objectToClass(value) {
45
17
  const type = typeof value;
46
18
 
47
19
  switch (type) {
48
20
  case "object":
49
- return value.__ptoto__.constructor;
21
+ const proto = Object.getPrototypeOf(value);
22
+
23
+ if (proto === null) {
24
+ return;
25
+ }
26
+
27
+ return proto.constructor;
50
28
  case "boolean":
51
29
  return Boolean;
52
30
  case "function":
@@ -78,10 +56,24 @@ function isPublicField(object, field_name) {
78
56
  /**
79
57
  *
80
58
  * @param {Object} object
81
- * @returns {FieldDescriptor[]}
59
+ * @param {string} field_name
60
+ * @returns {boolean}
82
61
  */
83
- function extractObjectFields(object) {
84
- const result = [];
62
+ function isReservedField(object, field_name) {
63
+ if (field_name.startsWith('@')) {
64
+ return true;
65
+ }
66
+
67
+ return false;
68
+ }
69
+
70
+ /**
71
+ *
72
+ * @param {Object} object
73
+ * @param {FieldDescriptor[]} result
74
+ * @param {*} object_proto
75
+ */
76
+ function extract_object_fields_reflection(object, result, object_proto) {
85
77
  const keys = Object.keys(object);
86
78
 
87
79
  for (let i = 0; i < keys.length; i++) {
@@ -91,6 +83,10 @@ function extractObjectFields(object) {
91
83
  continue;
92
84
  }
93
85
 
86
+ if (isReservedField(object, key)) {
87
+ continue;
88
+ }
89
+
94
90
  const field_type = objectToClass(object[key]);
95
91
 
96
92
  if (field_type === undefined) {
@@ -100,56 +96,242 @@ function extractObjectFields(object) {
100
96
  const descriptor = new FieldDescriptor();
101
97
  descriptor.name = key;
102
98
  descriptor.type = field_type;
99
+ descriptor.adapter = new FieldValueAdapter();
103
100
 
104
101
  result.push(descriptor);
105
102
  }
106
103
 
107
- return result;
104
+ const descriptors = Object.getOwnPropertyDescriptors(object_proto);
105
+
106
+ for (let d_name in descriptors) {
107
+ const d = descriptors[d_name];
108
+
109
+ const adapter = new FieldValueAdapter();
110
+
111
+ if (d.get === undefined) {
112
+ adapter.readable = false;
113
+ }
114
+
115
+ if (d.set === undefined) {
116
+ adapter.writable = false;
117
+ }
118
+
119
+ if (!adapter.readable) {
120
+ continue;
121
+ }
122
+
123
+
124
+ let field_value;
125
+
126
+ try {
127
+ field_value = adapter.read(object, d_name);
128
+ } catch (e) {
129
+ console.warn(e);
130
+ continue;
131
+ }
132
+
133
+ const field_type = objectToClass(field_value);
134
+
135
+ if (field_type === undefined) {
136
+ continue;
137
+ }
138
+
139
+ const descriptor = new FieldDescriptor();
140
+
141
+ descriptor.name = d_name;
142
+ descriptor.type = field_type;
143
+ descriptor.adapter = adapter;
144
+
145
+ result.push(descriptor);
146
+ }
108
147
  }
109
148
 
110
149
  /**
111
150
  *
112
151
  * @param {Object} object
113
- * @param {FieldDescriptor} field
114
- * @param {Map<*, (parent:*, field:FieldDescriptor)=>View>} registry
152
+ * @param {Map<*, TypeEditor>} registry
153
+ * @returns {FieldDescriptor[]}
115
154
  */
116
- export function createFieldEditor(object, field, registry) {
117
- const vResult = new EmptyView({});
155
+ function extractObjectFields(object, registry) {
156
+ const result = [];
118
157
 
119
- vResult.addChild(new LabelView(field.name));
158
+ const object_proto = Object.getPrototypeOf(object);
159
+ const Klass = object_proto.constructor;
120
160
 
121
- let vValue;
161
+ const editor = registry.get(Klass);
122
162
 
123
- const factory = registry.get(field.type);
163
+ if (!(editor?.schema?.additionalProperties === false)) {
164
+
165
+ extract_object_fields_reflection(object, result, object_proto);
124
166
 
125
- if (factory !== undefined) {
126
- vValue = factory(object, field);
127
- } else {
128
- vValue = createObjectEditor(object, registry);
129
167
  }
130
168
 
131
- vResult.addChild(vValue);
132
169
 
133
- return vResult;
170
+ if (editor !== undefined) {
171
+
172
+ const schema = editor.schema;
173
+
174
+ if (schema !== undefined) {
175
+ // has schema, apply
176
+ const prop_keys = Object.keys(schema.properties);
177
+
178
+ for (let i = 0; i < prop_keys.length; i++) {
179
+ const key = prop_keys[i];
180
+
181
+ const property = schema.properties[key];
182
+
183
+ const field_index = result.findIndex(a => a.name === key);
184
+
185
+ let field;
186
+
187
+ if (field_index === -1) {
188
+ // not in schema yet, build
189
+ field = new FieldDescriptor();
190
+ field.name = key;
191
+ field.adapter = new FieldValueAdapter();
192
+
193
+ result.push(field);
194
+ } else {
195
+ field = result[field_index];
196
+ }
197
+
198
+ let actual_type = field.type;
199
+
200
+ if (actual_type === undefined || actual_type === null) {
201
+ let actual_value;
202
+
203
+ try {
204
+ actual_value = field.adapter.read(object, key);
205
+ } catch (e) {
206
+ // silent failure
207
+ }
208
+
209
+ if (actual_value !== undefined && actual_value !== null) {
210
+ actual_type = objectToClass(actual_value);
211
+ }
212
+ }
213
+
214
+ if (property.type) {
215
+ // validate type
216
+ if (actual_type !== undefined && actual_type !== null) {
217
+ if (actual_type !== property.type) {
218
+ console.error(`Schema violation at field '${key}', schema type is different from actual type`, schema, actual_type);
219
+ }
220
+ }
221
+
222
+ field.type = property.type;
223
+ } else if (actual_type !== undefined && field.type !== actual_type) {
224
+ field.type = actual_type;
225
+ }
226
+
227
+
228
+ field.schema = property;
229
+
230
+ if (property.transient === true) {
231
+ // no point in editing transient
232
+ result.splice(field_index, 1);
233
+ }
234
+ }
235
+ }
236
+ }
237
+
238
+ return result;
134
239
  }
135
240
 
241
+ const build_path = [];
242
+ let build_path_offset = 0;
243
+
244
+
136
245
  /**
137
- *
138
246
  * @param {Object} object
139
- * @param {Map<*, (parent:*, field:FieldDescriptor)=>View>} registry
247
+ * @param {Map<*, TypeEditor>} registry
248
+ * @param {FieldDescriptor} [field_descriptor]
249
+ */
250
+ export function buildObjectEditorFromRegistry(object, registry, field_descriptor) {
251
+
252
+ const editor = findNearestRegisteredType(registry, object);
253
+
254
+ let fd;
255
+
256
+ if (field_descriptor === undefined) {
257
+
258
+ fd = new FieldDescriptor();
259
+ fd.adapter = new FieldValueAdapter();
260
+
261
+ fd.adapter.read = () => object;
262
+ fd.adapter.writable = false;
263
+
264
+ if (editor.schema) {
265
+ fd.schema = editor.schema;
266
+ }
267
+
268
+ } else {
269
+ fd = field_descriptor;
270
+ }
271
+
272
+ return editor.build(null, fd, registry);
273
+ }
274
+
275
+ const MAX_DEPTH = 7;
276
+
277
+ /**
278
+ * @param {Object} object
279
+ * @param {Map<*, TypeEditor>} registry
140
280
  */
141
281
  export function createObjectEditor(object, registry) {
142
- const fields = extractObjectFields(object);
143
282
 
144
- const vResult = new EmptyView({});
283
+ if (build_path_offset > MAX_DEPTH) {
284
+ // too deep
285
+ return undefined;
286
+ }
287
+
288
+ const seen_index = build_path.indexOf(object);
289
+ if (seen_index >= 0 && seen_index < build_path_offset) {
290
+ // recursion
291
+ return undefined;
292
+ }
293
+
294
+
295
+ build_path[build_path_offset++] = object;
296
+
297
+
298
+ const vResult = new EmptyView({
299
+ classList: ['auto-object-editor'],
300
+ css: {}
301
+ });
302
+
303
+
304
+ const fields = extractObjectFields(object, registry);
305
+
306
+ const field_views = [];
145
307
 
146
308
  for (let i = 0; i < fields.length; i++) {
147
309
  const field = fields[i];
148
310
 
149
- const vField = createFieldEditor(object, field, registry);
311
+ let vField;
312
+
313
+ try {
314
+ vField = createFieldEditor(object, field, registry);
315
+ } catch (e) {
316
+ vField = new LabelView('ERROR');
317
+ console.warn(e);
318
+ }
150
319
 
151
- vResult.addChild(vField);
320
+ if (vField === null) {
321
+ continue;
322
+ }
323
+
324
+ field_views.push(vField);
152
325
  }
153
326
 
327
+ build_path_offset--;
328
+
329
+ if (field_views.length === 0) {
330
+ // skip containers with no data
331
+ return null;
332
+ }
333
+
334
+ vResult.addChildren(field_views);
335
+
154
336
  return vResult;
155
337
  }
@@ -0,0 +1,39 @@
1
+ import { TypeEditor } from "../TypeEditor.js";
2
+ import EmptyView from "../../../../view/elements/EmptyView.js";
3
+ import { rgb2hex } from "../../../../core/color/rgb2hex.js";
4
+
5
+ export class ColorEditor extends TypeEditor {
6
+ build(parent, field) {
7
+
8
+ /**
9
+ * @type {Color}
10
+ */
11
+ const color = field.adapter.read(parent, field.name);
12
+
13
+ const view = new EmptyView({
14
+ tag: 'input'
15
+ });
16
+
17
+ view.attr({
18
+ type: "color"
19
+ });
20
+
21
+ function sync_up() {
22
+ view.attr({
23
+ value: `#${rgb2hex(color.r * 255, color.g * 255, color.b * 255)}`
24
+ })
25
+ }
26
+
27
+ function sync_down(e) {
28
+ const color_value = e.target.value;
29
+
30
+ color.parse(color_value);
31
+ }
32
+
33
+ view.on.linked.add(sync_up);
34
+ view.el.addEventListener('input', sync_down, false);
35
+ view.el.addEventListener('change', sync_down, false);
36
+
37
+ return view;
38
+ }
39
+ }
@@ -0,0 +1,17 @@
1
+ import { TypeEditor } from "../TypeEditor.js";
2
+ import View from "../../../../view/View.js";
3
+
4
+ export class HTMLElementEditor extends TypeEditor {
5
+ build(parent, field, registry) {
6
+ const el = field.adapter?.read(parent, field.name);
7
+
8
+ const view = new View();
9
+
10
+ view.el = el;
11
+
12
+ // make the size small
13
+ view.size.setScalar(32);
14
+
15
+ return view;
16
+ }
17
+ }
@@ -0,0 +1,50 @@
1
+ import { TypeEditor } from "../TypeEditor.js";
2
+ import { StringEditor } from "./primitive/StringEditor.js";
3
+ import EmptyView from "../../../../view/elements/EmptyView.js";
4
+ import ImageView from "../../../../view/elements/image/ImageView.js";
5
+ import ObservedString from "../../../../core/model/ObservedString.js";
6
+ import { ObservedStringEditor } from "./ObservedStringEditor.js";
7
+
8
+ export class ImagePathEditor extends TypeEditor {
9
+ inline = true;
10
+
11
+ build(parent, field, registry) {
12
+ let url_editor;
13
+
14
+ if (field.type === String) {
15
+
16
+ url_editor = new StringEditor();
17
+
18
+ } else if (field.type === ObservedString) {
19
+
20
+ url_editor = new ObservedStringEditor();
21
+
22
+ } else {
23
+ throw new Error(`Unsupported type`);
24
+ }
25
+
26
+ const vEditor = url_editor.build(parent, field, registry);
27
+
28
+ const r = new EmptyView({
29
+ css: {
30
+ display: "flex",
31
+ flexDirection: "row"
32
+ }
33
+ });
34
+
35
+ const vPreview = new ImageView(field.adapter.read(parent, field.name));
36
+
37
+ vPreview.size.set(32, 32);
38
+
39
+ function update() {
40
+ vPreview.__setSource(vEditor.el.value);
41
+ }
42
+
43
+ r.addChild(vPreview);
44
+ r.addChild(vEditor);
45
+
46
+ vEditor.el.addEventListener('input', update);
47
+
48
+ return r;
49
+ }
50
+ }