@m2c2kit/addons 0.3.14 → 0.3.16
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/dist/index.d.ts +437 -40
- package/dist/index.js +1373 -389
- package/dist/index.js.map +1 -1
- package/dist/index.min.js +1 -1
- package/package.json +8 -8
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Composite, WebColors, Shape, Label, CanvasKitHelpers, M2EventType, MutablePath, Easings, Story, Transition, TransitionDirection, LabelHorizontalAlignmentMode, Scene, Dimensions, Sprite, Action } from '@m2c2kit/core';
|
|
1
|
+
import { M2c2KitHelpers, Composite, WebColors, Shape, EventStoreMode, Equal, Label, CanvasKitHelpers, M2EventType, Timer, MutablePath, Easings, Story, Transition, TransitionDirection, LabelHorizontalAlignmentMode, Scene, Dimensions, Sprite, Action } from '@m2c2kit/core';
|
|
2
2
|
|
|
3
3
|
class Grid extends Composite {
|
|
4
4
|
/**
|
|
@@ -13,16 +13,16 @@ class Grid extends Composite {
|
|
|
13
13
|
*/
|
|
14
14
|
constructor(options) {
|
|
15
15
|
super(options);
|
|
16
|
-
this.compositeType = "
|
|
16
|
+
this.compositeType = "Grid";
|
|
17
17
|
// Grid options
|
|
18
|
-
|
|
19
|
-
this.
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
this.
|
|
23
|
-
this.
|
|
24
|
-
this.
|
|
25
|
-
this.
|
|
18
|
+
this._rows = 0;
|
|
19
|
+
this._columns = 0;
|
|
20
|
+
// default Grid is: transparent blue, red lines, line width 1
|
|
21
|
+
this._gridBackgroundColor = [0, 0, 255, 0.25];
|
|
22
|
+
this._gridLineColor = WebColors.Red;
|
|
23
|
+
this._gridLineWidth = 1;
|
|
24
|
+
this._gridChildren = new Array();
|
|
25
|
+
this.cellContainers = new Array();
|
|
26
26
|
if (options.size) {
|
|
27
27
|
this.size = options.size;
|
|
28
28
|
} else {
|
|
@@ -32,19 +32,19 @@ class Grid extends Composite {
|
|
|
32
32
|
if (options.rows >= 1) {
|
|
33
33
|
this.rows = options.rows;
|
|
34
34
|
} else {
|
|
35
|
-
throw new Error("rows must be at least 1");
|
|
35
|
+
throw new Error("grid rows must be at least 1");
|
|
36
36
|
}
|
|
37
37
|
} else {
|
|
38
|
-
throw new Error("rows must be specified");
|
|
38
|
+
throw new Error("grid rows must be specified");
|
|
39
39
|
}
|
|
40
40
|
if (options.columns) {
|
|
41
41
|
if (options.columns >= 1) {
|
|
42
42
|
this.columns = options.columns;
|
|
43
43
|
} else {
|
|
44
|
-
throw new Error("columns must be at least 1");
|
|
44
|
+
throw new Error("grid columns must be at least 1");
|
|
45
45
|
}
|
|
46
46
|
} else {
|
|
47
|
-
throw new Error("columns must be specified");
|
|
47
|
+
throw new Error("grid columns must be specified");
|
|
48
48
|
}
|
|
49
49
|
if (options.backgroundColor) {
|
|
50
50
|
this.gridBackgroundColor = options.backgroundColor;
|
|
@@ -57,56 +57,114 @@ class Grid extends Composite {
|
|
|
57
57
|
}
|
|
58
58
|
this.cellWidth = this.size.width / this.columns;
|
|
59
59
|
this.cellHeight = this.size.height / this.rows;
|
|
60
|
+
this.saveNodeNewEvent();
|
|
61
|
+
}
|
|
62
|
+
get completeNodeOptions() {
|
|
63
|
+
return {
|
|
64
|
+
...this.options,
|
|
65
|
+
...this.getNodeOptions(),
|
|
66
|
+
...this.getDrawableOptions(),
|
|
67
|
+
rows: this.rows,
|
|
68
|
+
columns: this.columns,
|
|
69
|
+
size: this.size,
|
|
70
|
+
backgroundColor: this.gridBackgroundColor,
|
|
71
|
+
gridLineWidth: this.gridLineWidth,
|
|
72
|
+
gridLineColor: this.gridLineColor
|
|
73
|
+
};
|
|
60
74
|
}
|
|
61
75
|
initialize() {
|
|
62
|
-
|
|
76
|
+
this.descendants.forEach((d) => {
|
|
77
|
+
if (d.parent === this) {
|
|
78
|
+
super.removeChild(d);
|
|
79
|
+
} else {
|
|
80
|
+
d.parent?.removeChild(d);
|
|
81
|
+
}
|
|
82
|
+
});
|
|
63
83
|
this.gridBackground = new Shape({
|
|
64
|
-
name: "
|
|
84
|
+
name: "__" + this.name + "-gridRectangle",
|
|
65
85
|
rect: { size: this.size },
|
|
66
|
-
//size: this.size,
|
|
67
86
|
fillColor: this.gridBackgroundColor,
|
|
68
87
|
strokeColor: this.gridLineColor,
|
|
69
88
|
lineWidth: this.gridLineWidth,
|
|
70
|
-
isUserInteractionEnabled: this.isUserInteractionEnabled
|
|
89
|
+
isUserInteractionEnabled: this.isUserInteractionEnabled,
|
|
90
|
+
suppressEvents: true
|
|
71
91
|
});
|
|
72
|
-
|
|
92
|
+
super.addChild(this.gridBackground);
|
|
73
93
|
this.gridBackground.isUserInteractionEnabled = this.isUserInteractionEnabled;
|
|
74
94
|
for (let col = 1; col < this.columns; col++) {
|
|
75
95
|
const verticalLine = new Shape({
|
|
76
|
-
name: "
|
|
96
|
+
name: "__" + this.name + "-gridVerticalLine-" + (col - 1),
|
|
77
97
|
rect: {
|
|
78
98
|
size: { width: this.gridLineWidth, height: this.size.height },
|
|
79
99
|
origin: { x: -this.size.width / 2 + this.cellWidth * col, y: 0 }
|
|
80
100
|
},
|
|
81
|
-
fillColor: this.gridLineColor
|
|
101
|
+
fillColor: this.gridLineColor,
|
|
102
|
+
suppressEvents: true
|
|
82
103
|
});
|
|
83
104
|
this.gridBackground.addChild(verticalLine);
|
|
84
105
|
}
|
|
85
106
|
for (let row = 1; row < this.rows; row++) {
|
|
86
107
|
const horizontalLine = new Shape({
|
|
87
|
-
name: "
|
|
108
|
+
name: "__" + this.name + "-gridHorizontalLine-" + (row - 1),
|
|
88
109
|
rect: {
|
|
89
110
|
size: { width: this.size.width, height: this.gridLineWidth },
|
|
90
111
|
origin: { x: 0, y: -this.size.height / 2 + this.cellHeight * row }
|
|
91
112
|
},
|
|
92
|
-
fillColor: this.gridLineColor
|
|
113
|
+
fillColor: this.gridLineColor,
|
|
114
|
+
suppressEvents: true
|
|
93
115
|
});
|
|
94
116
|
this.gridBackground.addChild(horizontalLine);
|
|
95
117
|
}
|
|
96
|
-
|
|
118
|
+
this.cellContainers = new Array(this.rows).fill([]).map(() => new Array(this.columns));
|
|
119
|
+
for (let row = 0; row < this.rows; row++) {
|
|
120
|
+
for (let col = 0; col < this.columns; col++) {
|
|
121
|
+
const cellContainer = new Shape({
|
|
122
|
+
name: "__" + this.name + "-gridCellContainer-" + row + "-" + col,
|
|
123
|
+
rect: {
|
|
124
|
+
size: { width: this.cellWidth, height: this.cellHeight },
|
|
125
|
+
origin: {
|
|
126
|
+
x: -this.size.width / 2 + this.cellWidth * col + this.cellWidth / 2,
|
|
127
|
+
y: -this.size.height / 2 + this.cellHeight * row + this.cellHeight / 2
|
|
128
|
+
}
|
|
129
|
+
},
|
|
130
|
+
fillColor: WebColors.Transparent,
|
|
131
|
+
lineWidth: 0,
|
|
132
|
+
suppressEvents: true
|
|
133
|
+
});
|
|
134
|
+
this.gridBackground.addChild(cellContainer);
|
|
135
|
+
this.cellContainers[row][col] = cellContainer;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
if (this.gridChildren.length > 0) {
|
|
97
139
|
this.gridChildren.forEach((gridChild) => {
|
|
98
140
|
if (!this.cellWidth || !this.cellHeight || !this.gridBackground) {
|
|
99
141
|
throw new Error(
|
|
100
142
|
"cellWidth, cellHeight, or gridBackground undefined or null"
|
|
101
143
|
);
|
|
102
144
|
}
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
145
|
+
if (this.game.eventStore.mode === EventStoreMode.Replay) {
|
|
146
|
+
const childNode = [
|
|
147
|
+
...this.game.nodes,
|
|
148
|
+
...this.game.materializedNodes
|
|
149
|
+
].find(
|
|
150
|
+
(n) => (
|
|
151
|
+
// gridChild.node is the uuid of the child node here!
|
|
152
|
+
n.uuid === gridChild.node
|
|
153
|
+
)
|
|
154
|
+
);
|
|
155
|
+
if (!childNode) {
|
|
156
|
+
throw new Error("grid: child node not found");
|
|
157
|
+
}
|
|
158
|
+
childNode?.parent?.removeChild(childNode);
|
|
159
|
+
this.cellContainers[gridChild.row][gridChild.column].addChild(
|
|
160
|
+
childNode
|
|
161
|
+
);
|
|
162
|
+
} else {
|
|
163
|
+
gridChild.node.parent?.removeChild(gridChild.node);
|
|
164
|
+
this.cellContainers[gridChild.row][gridChild.column].addChild(
|
|
165
|
+
gridChild.node
|
|
166
|
+
);
|
|
167
|
+
}
|
|
110
168
|
});
|
|
111
169
|
}
|
|
112
170
|
this.needsInitialization = false;
|
|
@@ -120,6 +178,60 @@ class Grid extends Composite {
|
|
|
120
178
|
set gridBackground(gridBackground) {
|
|
121
179
|
this._gridBackground = gridBackground;
|
|
122
180
|
}
|
|
181
|
+
/**
|
|
182
|
+
* note: below we do not have getter and setter for size because the getter
|
|
183
|
+
* and setter in M2Node will handle it.
|
|
184
|
+
*/
|
|
185
|
+
get rows() {
|
|
186
|
+
return this._rows;
|
|
187
|
+
}
|
|
188
|
+
set rows(rows) {
|
|
189
|
+
if (Equal.value(this._rows, rows)) {
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
this._rows = rows;
|
|
193
|
+
this.needsInitialization = true;
|
|
194
|
+
}
|
|
195
|
+
get columns() {
|
|
196
|
+
return this._columns;
|
|
197
|
+
}
|
|
198
|
+
set columns(columns) {
|
|
199
|
+
if (Equal.value(this._columns, columns)) {
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
this._columns = columns;
|
|
203
|
+
this.needsInitialization = true;
|
|
204
|
+
}
|
|
205
|
+
get gridBackgroundColor() {
|
|
206
|
+
return this._gridBackgroundColor;
|
|
207
|
+
}
|
|
208
|
+
set gridBackgroundColor(backgroundColor) {
|
|
209
|
+
if (Equal.value(this._gridBackgroundColor, backgroundColor)) {
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
this._gridBackgroundColor = backgroundColor;
|
|
213
|
+
this.needsInitialization = true;
|
|
214
|
+
}
|
|
215
|
+
get gridLineWidth() {
|
|
216
|
+
return this._gridLineWidth;
|
|
217
|
+
}
|
|
218
|
+
set gridLineWidth(gridLineWidth) {
|
|
219
|
+
if (Equal.value(this._gridLineWidth, gridLineWidth)) {
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
this._gridLineWidth = gridLineWidth;
|
|
223
|
+
this.needsInitialization = true;
|
|
224
|
+
}
|
|
225
|
+
get gridLineColor() {
|
|
226
|
+
return this._gridLineColor;
|
|
227
|
+
}
|
|
228
|
+
set gridLineColor(gridLineColor) {
|
|
229
|
+
if (Equal.value(this._gridLineColor, gridLineColor)) {
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
232
|
+
this._gridLineColor = gridLineColor;
|
|
233
|
+
this.needsInitialization = true;
|
|
234
|
+
}
|
|
123
235
|
// all nodes that make up grid are added as children, so they
|
|
124
236
|
// have their own dispose methods
|
|
125
237
|
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
@@ -168,25 +280,49 @@ class Grid extends Composite {
|
|
|
168
280
|
child.warmup(canvas);
|
|
169
281
|
});
|
|
170
282
|
}
|
|
171
|
-
// override M2Node.RemoveAllChildren() so that when RemoveAllChildren() is called on a Grid,
|
|
172
|
-
// it removes only nodes added to the grid cells (what we call grid children), not the grid lines!
|
|
173
283
|
/**
|
|
174
|
-
*
|
|
284
|
+
* The child nodes that have been added to the grid.
|
|
285
|
+
*
|
|
286
|
+
* @remarks Do not set this property directly. Use the methods for adding
|
|
287
|
+
* and removing grid children, such as `addAtCell()`, `removeAllAtCell()`,
|
|
288
|
+
* `removeGridChild()`, and `removeAllGridChildren()`.
|
|
175
289
|
*/
|
|
176
|
-
|
|
290
|
+
get gridChildren() {
|
|
291
|
+
return this._gridChildren;
|
|
292
|
+
}
|
|
293
|
+
set gridChildren(gridChildren) {
|
|
294
|
+
this._gridChildren = gridChildren;
|
|
295
|
+
this.needsInitialization = true;
|
|
296
|
+
if (this.game.eventStore.mode === EventStoreMode.Record) {
|
|
297
|
+
this.savePropertyChangeEvent(
|
|
298
|
+
"gridChildren",
|
|
299
|
+
this.gridChildren.map(
|
|
300
|
+
(gridChild) => ({
|
|
301
|
+
node: gridChild.node.uuid,
|
|
302
|
+
row: gridChild.row,
|
|
303
|
+
column: gridChild.column
|
|
304
|
+
})
|
|
305
|
+
)
|
|
306
|
+
);
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
/**
|
|
310
|
+
* Removes all grid children from the grid.
|
|
311
|
+
*
|
|
312
|
+
* @remarks This retains grid lines and grid appearance.
|
|
313
|
+
*/
|
|
314
|
+
removeAllGridChildren() {
|
|
177
315
|
if (this.gridChildren.length === 0) {
|
|
178
316
|
return;
|
|
179
317
|
}
|
|
180
318
|
while (this.gridChildren.length) {
|
|
181
|
-
|
|
182
|
-
if (gridChild) {
|
|
183
|
-
this.gridBackground.removeChild(gridChild.node);
|
|
184
|
-
}
|
|
319
|
+
this.gridChildren = this.gridChildren.slice(0, -1);
|
|
185
320
|
}
|
|
186
321
|
this.needsInitialization = true;
|
|
187
322
|
}
|
|
188
323
|
/**
|
|
189
|
-
* Adds a node to the grid at the specified row and column
|
|
324
|
+
* Adds a node as a grid child to the grid at the specified row and column
|
|
325
|
+
* position.
|
|
190
326
|
*
|
|
191
327
|
* @param node - node to add to the grid
|
|
192
328
|
* @param row - row position within grid to add node; zero-based indexing
|
|
@@ -198,49 +334,68 @@ class Grid extends Composite {
|
|
|
198
334
|
`warning: addAtCell() requested to add node at row ${row}, column ${column}. This is outside the bounds of grid ${this.name}, which is size ${this.rows}x${this.columns}. Note that addAtCell() uses zero-based indexing. AddAtCell() will proceed, but may draw nodes outside the grid`
|
|
199
335
|
);
|
|
200
336
|
}
|
|
201
|
-
this.gridChildren
|
|
337
|
+
this.gridChildren = [
|
|
338
|
+
...this.gridChildren,
|
|
339
|
+
{ node, row, column }
|
|
340
|
+
];
|
|
202
341
|
this.needsInitialization = true;
|
|
203
342
|
}
|
|
204
343
|
/**
|
|
205
|
-
* Removes all child nodes at the specified row and column position.
|
|
344
|
+
* Removes all grid child nodes at the specified row and column position.
|
|
206
345
|
*
|
|
207
|
-
* @param row - row position within grid at which to remove children; zero-based indexing
|
|
208
|
-
* @param column - column position within grid at which to remove children; zero-based indexing
|
|
346
|
+
* @param row - row position within grid at which to remove grid children; zero-based indexing
|
|
347
|
+
* @param column - column position within grid at which to remove grid children; zero-based indexing
|
|
209
348
|
*/
|
|
210
349
|
removeAllAtCell(row, column) {
|
|
211
|
-
const gridChildrenToRemove = this.gridChildren.filter(
|
|
212
|
-
(gridChild) => gridChild.row === row && gridChild.column === column
|
|
213
|
-
);
|
|
214
|
-
if (gridChildrenToRemove.length === 0) {
|
|
215
|
-
return;
|
|
216
|
-
}
|
|
217
|
-
this.gridBackground.removeChildren(
|
|
218
|
-
gridChildrenToRemove.map((gridChild) => gridChild.node)
|
|
219
|
-
);
|
|
220
350
|
this.gridChildren = this.gridChildren.filter(
|
|
221
351
|
(gridChild) => gridChild.row !== row && gridChild.column !== column
|
|
222
352
|
);
|
|
223
353
|
this.needsInitialization = true;
|
|
224
354
|
}
|
|
225
|
-
// override M2Node.RemoveChild() so that when RemoveChild() is called on a Grid, it removes the
|
|
226
|
-
// node from the gridBackground rectangle AND our grid's own list of children (in gridChildren)
|
|
227
355
|
/**
|
|
228
|
-
* Removes the child node from the grid.
|
|
356
|
+
* Removes the grid child node from the grid.
|
|
229
357
|
*
|
|
230
358
|
* @param node - node to remove
|
|
231
359
|
*/
|
|
232
|
-
|
|
233
|
-
this.gridBackground.removeChild(node);
|
|
360
|
+
removeGridChild(node) {
|
|
234
361
|
this.gridChildren = this.gridChildren.filter(
|
|
235
362
|
(gridChild) => gridChild.node != node
|
|
236
363
|
);
|
|
237
364
|
this.needsInitialization = true;
|
|
238
365
|
}
|
|
366
|
+
// The Grid manages its own children (background, lines, and cell
|
|
367
|
+
// containers). It is probably a mistake when the user tries to add or remove
|
|
368
|
+
// these children. The user probably meant to add or remove grid children
|
|
369
|
+
// instead. Warn the user about this.
|
|
370
|
+
addChild(child) {
|
|
371
|
+
console.warn(
|
|
372
|
+
"Grid.addChild() was called -- did you mean to call addAtCell() instead?"
|
|
373
|
+
);
|
|
374
|
+
super.addChild(child);
|
|
375
|
+
}
|
|
376
|
+
removeAllChildren() {
|
|
377
|
+
console.warn(
|
|
378
|
+
"Grid.removeAllChildren() was called -- did you mean to call removeAllGridChildren() instead?"
|
|
379
|
+
);
|
|
380
|
+
super.removeAllChildren();
|
|
381
|
+
}
|
|
382
|
+
removeChild(child) {
|
|
383
|
+
console.warn(
|
|
384
|
+
"Grid.removeChild() was called -- did you mean to call removeGridChild() instead?"
|
|
385
|
+
);
|
|
386
|
+
super.removeChild(child);
|
|
387
|
+
}
|
|
388
|
+
removeChildren(children) {
|
|
389
|
+
console.warn(
|
|
390
|
+
"Grid.removeChildren() was called -- did you mean to call removeGridChild() instead?"
|
|
391
|
+
);
|
|
392
|
+
super.removeChildren(children);
|
|
393
|
+
}
|
|
239
394
|
}
|
|
395
|
+
M2c2KitHelpers.registerM2NodeClass(Grid);
|
|
240
396
|
|
|
241
397
|
class Button extends Composite {
|
|
242
|
-
//
|
|
243
|
-
// todo: add default "behaviors" (?) like button click animation?
|
|
398
|
+
// TODO: add default "behaviors" (?) like button click animation?
|
|
244
399
|
/**
|
|
245
400
|
* A simple button of rectangle with text centered inside.
|
|
246
401
|
*
|
|
@@ -252,23 +407,33 @@ class Button extends Composite {
|
|
|
252
407
|
*/
|
|
253
408
|
constructor(options) {
|
|
254
409
|
super(options);
|
|
255
|
-
this.compositeType = "
|
|
410
|
+
this.compositeType = "Button";
|
|
411
|
+
this.isText = true;
|
|
256
412
|
// Button options
|
|
257
413
|
this._backgroundColor = WebColors.Black;
|
|
258
|
-
this.
|
|
259
|
-
this.
|
|
260
|
-
this.fontSize = 20;
|
|
414
|
+
this._cornerRadius = 9;
|
|
415
|
+
this._fontSize = 20;
|
|
261
416
|
this._text = "";
|
|
262
417
|
this._fontColor = WebColors.White;
|
|
418
|
+
this._interpolation = {};
|
|
419
|
+
this._localize = true;
|
|
263
420
|
if (options.text) {
|
|
264
421
|
this.text = options.text;
|
|
265
422
|
}
|
|
266
423
|
if (options.size) {
|
|
267
424
|
this.size = options.size;
|
|
425
|
+
} else {
|
|
426
|
+
this.size = { width: 200, height: 50 };
|
|
268
427
|
}
|
|
269
428
|
if (options.cornerRadius !== void 0) {
|
|
270
429
|
this.cornerRadius = options.cornerRadius;
|
|
271
430
|
}
|
|
431
|
+
if (options.fontName) {
|
|
432
|
+
this.fontName = options.fontName;
|
|
433
|
+
}
|
|
434
|
+
if (options.fontNames) {
|
|
435
|
+
this.fontNames = options.fontNames;
|
|
436
|
+
}
|
|
272
437
|
if (options.fontSize !== void 0) {
|
|
273
438
|
this.fontSize = options.fontSize;
|
|
274
439
|
}
|
|
@@ -278,6 +443,25 @@ class Button extends Composite {
|
|
|
278
443
|
if (options.backgroundColor) {
|
|
279
444
|
this.backgroundColor = options.backgroundColor;
|
|
280
445
|
}
|
|
446
|
+
if (options.interpolation) {
|
|
447
|
+
this.interpolation = options.interpolation;
|
|
448
|
+
}
|
|
449
|
+
if (options.localize !== void 0) {
|
|
450
|
+
this.localize = options.localize;
|
|
451
|
+
}
|
|
452
|
+
this.saveNodeNewEvent();
|
|
453
|
+
}
|
|
454
|
+
get completeNodeOptions() {
|
|
455
|
+
return {
|
|
456
|
+
...this.options,
|
|
457
|
+
...this.getNodeOptions(),
|
|
458
|
+
...this.getDrawableOptions(),
|
|
459
|
+
...this.getTextOptions(),
|
|
460
|
+
size: this.size,
|
|
461
|
+
cornerRadius: this.cornerRadius,
|
|
462
|
+
backgroundColor: this.backgroundColor,
|
|
463
|
+
fontNames: this.fontNames
|
|
464
|
+
};
|
|
281
465
|
}
|
|
282
466
|
initialize() {
|
|
283
467
|
this.removeAllChildren();
|
|
@@ -292,15 +476,23 @@ class Button extends Composite {
|
|
|
292
476
|
);
|
|
293
477
|
this.backgroundPaint.setStyle(this.canvasKit.PaintStyle.Fill);
|
|
294
478
|
const buttonRectangle = new Shape({
|
|
479
|
+
name: "__" + this.name + "-buttonRectangle",
|
|
295
480
|
rect: { size: this.size },
|
|
296
481
|
cornerRadius: this.cornerRadius,
|
|
297
|
-
fillColor: this._backgroundColor
|
|
482
|
+
fillColor: this._backgroundColor,
|
|
483
|
+
suppressEvents: true
|
|
298
484
|
});
|
|
299
485
|
this.addChild(buttonRectangle);
|
|
300
486
|
const buttonLabel = new Label({
|
|
487
|
+
name: "__" + this.name + "-buttonLabel",
|
|
301
488
|
text: this.text,
|
|
489
|
+
localize: this.localize,
|
|
490
|
+
interpolation: this.interpolation,
|
|
491
|
+
fontName: this.fontName,
|
|
492
|
+
fontNames: this.fontNames,
|
|
302
493
|
fontSize: this.fontSize,
|
|
303
|
-
fontColor: this.fontColor
|
|
494
|
+
fontColor: this.fontColor,
|
|
495
|
+
suppressEvents: true
|
|
304
496
|
});
|
|
305
497
|
buttonRectangle.addChild(buttonLabel);
|
|
306
498
|
this.needsInitialization = false;
|
|
@@ -312,22 +504,101 @@ class Button extends Composite {
|
|
|
312
504
|
return this._text;
|
|
313
505
|
}
|
|
314
506
|
set text(text) {
|
|
507
|
+
if (Equal.value(this._text, text)) {
|
|
508
|
+
return;
|
|
509
|
+
}
|
|
315
510
|
this._text = text;
|
|
316
511
|
this.needsInitialization = true;
|
|
512
|
+
this.savePropertyChangeEvent("text", text);
|
|
317
513
|
}
|
|
318
514
|
get backgroundColor() {
|
|
319
515
|
return this._backgroundColor;
|
|
320
516
|
}
|
|
321
517
|
set backgroundColor(backgroundColor) {
|
|
518
|
+
if (Equal.value(this._backgroundColor, backgroundColor)) {
|
|
519
|
+
return;
|
|
520
|
+
}
|
|
322
521
|
this._backgroundColor = backgroundColor;
|
|
323
522
|
this.needsInitialization = true;
|
|
523
|
+
this.savePropertyChangeEvent("backgroundColor", backgroundColor);
|
|
324
524
|
}
|
|
325
525
|
get fontColor() {
|
|
326
526
|
return this._fontColor;
|
|
327
527
|
}
|
|
328
528
|
set fontColor(fontColor) {
|
|
529
|
+
if (Equal.value(this._fontColor, fontColor)) {
|
|
530
|
+
return;
|
|
531
|
+
}
|
|
329
532
|
this._fontColor = fontColor;
|
|
330
533
|
this.needsInitialization = true;
|
|
534
|
+
this.savePropertyChangeEvent("fontColor", fontColor);
|
|
535
|
+
}
|
|
536
|
+
get fontName() {
|
|
537
|
+
return this._fontName;
|
|
538
|
+
}
|
|
539
|
+
set fontName(fontName) {
|
|
540
|
+
if (this._fontName === fontName) {
|
|
541
|
+
return;
|
|
542
|
+
}
|
|
543
|
+
this._fontName = fontName;
|
|
544
|
+
this.needsInitialization = true;
|
|
545
|
+
this.savePropertyChangeEvent("fontName", fontName);
|
|
546
|
+
}
|
|
547
|
+
get fontNames() {
|
|
548
|
+
return this._fontNames;
|
|
549
|
+
}
|
|
550
|
+
set fontNames(fontNames) {
|
|
551
|
+
if (Equal.value(this._fontNames, fontNames)) {
|
|
552
|
+
return;
|
|
553
|
+
}
|
|
554
|
+
this._fontNames = fontNames;
|
|
555
|
+
this.needsInitialization = true;
|
|
556
|
+
this.savePropertyChangeEvent("fontNames", fontNames);
|
|
557
|
+
}
|
|
558
|
+
get cornerRadius() {
|
|
559
|
+
return this._cornerRadius;
|
|
560
|
+
}
|
|
561
|
+
set cornerRadius(cornerRadius) {
|
|
562
|
+
if (Equal.value(this._cornerRadius, cornerRadius)) {
|
|
563
|
+
return;
|
|
564
|
+
}
|
|
565
|
+
this._cornerRadius = cornerRadius;
|
|
566
|
+
this.needsInitialization = true;
|
|
567
|
+
this.savePropertyChangeEvent("cornerRadius", cornerRadius);
|
|
568
|
+
}
|
|
569
|
+
get fontSize() {
|
|
570
|
+
return this._fontSize;
|
|
571
|
+
}
|
|
572
|
+
set fontSize(fontSize) {
|
|
573
|
+
if (Equal.value(this._fontSize, fontSize)) {
|
|
574
|
+
return;
|
|
575
|
+
}
|
|
576
|
+
this._fontSize = fontSize;
|
|
577
|
+
this.needsInitialization = true;
|
|
578
|
+
this.savePropertyChangeEvent("fontSize", fontSize);
|
|
579
|
+
}
|
|
580
|
+
get interpolation() {
|
|
581
|
+
return this._interpolation;
|
|
582
|
+
}
|
|
583
|
+
set interpolation(interpolation) {
|
|
584
|
+
if (Equal.value(this._interpolation, interpolation)) {
|
|
585
|
+
return;
|
|
586
|
+
}
|
|
587
|
+
this._interpolation = interpolation;
|
|
588
|
+
Object.freeze(this._interpolation);
|
|
589
|
+
this.needsInitialization = true;
|
|
590
|
+
this.savePropertyChangeEvent("interpolation", interpolation);
|
|
591
|
+
}
|
|
592
|
+
get localize() {
|
|
593
|
+
return this._localize;
|
|
594
|
+
}
|
|
595
|
+
set localize(localize) {
|
|
596
|
+
if (Equal.value(this._localize, localize)) {
|
|
597
|
+
return;
|
|
598
|
+
}
|
|
599
|
+
this._localize = localize;
|
|
600
|
+
this.needsInitialization = true;
|
|
601
|
+
this.savePropertyChangeEvent("localize", localize);
|
|
331
602
|
}
|
|
332
603
|
/**
|
|
333
604
|
* Duplicates a node using deep copy.
|
|
@@ -348,7 +619,11 @@ class Button extends Composite {
|
|
|
348
619
|
cornerRadius: this.cornerRadius,
|
|
349
620
|
backgroundColor: this.backgroundColor,
|
|
350
621
|
fontColor: this.fontColor,
|
|
351
|
-
name: newName
|
|
622
|
+
name: newName,
|
|
623
|
+
localize: this.localize,
|
|
624
|
+
interpolation: JSON.parse(JSON.stringify(this.interpolation)),
|
|
625
|
+
fontName: this.fontName,
|
|
626
|
+
fontNames: JSON.parse(JSON.stringify(this.fontNames))
|
|
352
627
|
});
|
|
353
628
|
if (this.children.length > 0) {
|
|
354
629
|
dest.children = this.children.map((child) => {
|
|
@@ -372,6 +647,7 @@ class Button extends Composite {
|
|
|
372
647
|
});
|
|
373
648
|
}
|
|
374
649
|
}
|
|
650
|
+
M2c2KitHelpers.registerM2NodeClass(Button);
|
|
375
651
|
|
|
376
652
|
var DialogResult = /* @__PURE__ */ ((DialogResult2) => {
|
|
377
653
|
DialogResult2["Dismiss"] = "Dismiss";
|
|
@@ -391,9 +667,9 @@ class Dialog extends Composite {
|
|
|
391
667
|
this.contentText = "";
|
|
392
668
|
this.positiveButtonText = "";
|
|
393
669
|
this.negativeButtonText = "";
|
|
670
|
+
this._fontColor = WebColors.White;
|
|
394
671
|
this.zPosition = Number.MAX_VALUE;
|
|
395
672
|
this.hidden = true;
|
|
396
|
-
this._fontColor = WebColors.White;
|
|
397
673
|
if (!options) {
|
|
398
674
|
return;
|
|
399
675
|
}
|
|
@@ -427,7 +703,7 @@ class Dialog extends Composite {
|
|
|
427
703
|
}
|
|
428
704
|
onDialogResult(callback, options) {
|
|
429
705
|
const eventListener = {
|
|
430
|
-
type: M2EventType.
|
|
706
|
+
type: M2EventType.Composite,
|
|
431
707
|
compositeType: "DialogResult",
|
|
432
708
|
nodeUuid: this.uuid,
|
|
433
709
|
callback
|
|
@@ -443,10 +719,10 @@ class Dialog extends Composite {
|
|
|
443
719
|
this.removeAllChildren();
|
|
444
720
|
const overlay = new Shape({
|
|
445
721
|
rect: {
|
|
446
|
-
width:
|
|
447
|
-
height:
|
|
448
|
-
x:
|
|
449
|
-
y:
|
|
722
|
+
width: m2c2Globals.canvasCssWidth,
|
|
723
|
+
height: m2c2Globals.canvasCssHeight,
|
|
724
|
+
x: m2c2Globals.canvasCssWidth / 2,
|
|
725
|
+
y: m2c2Globals.canvasCssHeight / 2
|
|
450
726
|
},
|
|
451
727
|
fillColor: [0, 0, 0, this.overlayAlpha],
|
|
452
728
|
zPosition: -1,
|
|
@@ -456,12 +732,14 @@ class Dialog extends Composite {
|
|
|
456
732
|
e.handled = true;
|
|
457
733
|
this.hidden = true;
|
|
458
734
|
if (this.eventListeners.length > 0) {
|
|
459
|
-
this.eventListeners.filter((listener) => listener.type === M2EventType.
|
|
735
|
+
this.eventListeners.filter((listener) => listener.type === M2EventType.Composite).forEach((listener) => {
|
|
460
736
|
const dialogEvent = {
|
|
461
|
-
type: M2EventType.
|
|
737
|
+
type: M2EventType.Composite,
|
|
462
738
|
target: this,
|
|
463
739
|
handled: false,
|
|
464
|
-
dialogResult: "Dismiss" /* Dismiss
|
|
740
|
+
dialogResult: "Dismiss" /* Dismiss */,
|
|
741
|
+
timestamp: Timer.now(),
|
|
742
|
+
iso8601Timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
465
743
|
};
|
|
466
744
|
listener.callback(dialogEvent);
|
|
467
745
|
});
|
|
@@ -472,8 +750,8 @@ class Dialog extends Composite {
|
|
|
472
750
|
rect: {
|
|
473
751
|
width: 300,
|
|
474
752
|
height: 150,
|
|
475
|
-
x:
|
|
476
|
-
y:
|
|
753
|
+
x: m2c2Globals.canvasCssWidth / 2,
|
|
754
|
+
y: m2c2Globals.canvasCssHeight / 2
|
|
477
755
|
},
|
|
478
756
|
cornerRadius: this.cornerRadius,
|
|
479
757
|
fillColor: this.backgroundColor,
|
|
@@ -504,12 +782,14 @@ class Dialog extends Composite {
|
|
|
504
782
|
e.handled = true;
|
|
505
783
|
this.hidden = true;
|
|
506
784
|
if (this.eventListeners.length > 0) {
|
|
507
|
-
this.eventListeners.filter((listener) => listener.type === M2EventType.
|
|
785
|
+
this.eventListeners.filter((listener) => listener.type === M2EventType.Composite).forEach((listener) => {
|
|
508
786
|
const dialogEvent = {
|
|
509
|
-
type: M2EventType.
|
|
787
|
+
type: M2EventType.Composite,
|
|
510
788
|
target: this,
|
|
511
789
|
handled: false,
|
|
512
|
-
dialogResult: "Negative" /* Negative
|
|
790
|
+
dialogResult: "Negative" /* Negative */,
|
|
791
|
+
timestamp: Timer.now(),
|
|
792
|
+
iso8601Timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
513
793
|
};
|
|
514
794
|
listener.callback(dialogEvent);
|
|
515
795
|
});
|
|
@@ -526,12 +806,14 @@ class Dialog extends Composite {
|
|
|
526
806
|
e.handled = true;
|
|
527
807
|
this.hidden = true;
|
|
528
808
|
if (this.eventListeners.length > 0) {
|
|
529
|
-
this.eventListeners.filter((listener) => listener.type === M2EventType.
|
|
809
|
+
this.eventListeners.filter((listener) => listener.type === M2EventType.Composite).forEach((listener) => {
|
|
530
810
|
const dialogEvent = {
|
|
531
|
-
type: M2EventType.
|
|
811
|
+
type: M2EventType.Composite,
|
|
532
812
|
target: this,
|
|
533
813
|
handled: false,
|
|
534
|
-
dialogResult: "Positive" /* Positive
|
|
814
|
+
dialogResult: "Positive" /* Positive */,
|
|
815
|
+
timestamp: Timer.now(),
|
|
816
|
+
iso8601Timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
535
817
|
};
|
|
536
818
|
listener.callback(dialogEvent);
|
|
537
819
|
});
|
|
@@ -555,6 +837,13 @@ class Dialog extends Composite {
|
|
|
555
837
|
this._fontColor = fontColor;
|
|
556
838
|
this.needsInitialization = true;
|
|
557
839
|
}
|
|
840
|
+
get hidden() {
|
|
841
|
+
return this._hidden;
|
|
842
|
+
}
|
|
843
|
+
set hidden(hidden) {
|
|
844
|
+
this._hidden = hidden;
|
|
845
|
+
this.needsInitialization;
|
|
846
|
+
}
|
|
558
847
|
/**
|
|
559
848
|
* Duplicates a node using deep copy.
|
|
560
849
|
*
|
|
@@ -566,7 +855,7 @@ class Dialog extends Composite {
|
|
|
566
855
|
* provided, name will be the new uuid
|
|
567
856
|
*/
|
|
568
857
|
duplicate(newName) {
|
|
569
|
-
throw new Error(
|
|
858
|
+
throw new Error(`duplicate not implemented. ${newName}`);
|
|
570
859
|
}
|
|
571
860
|
update() {
|
|
572
861
|
super.update();
|
|
@@ -617,6 +906,7 @@ class DrawPad extends Composite {
|
|
|
617
906
|
* of all interactions with each DrawPadStroke.
|
|
618
907
|
*/
|
|
619
908
|
this.strokes = new Array();
|
|
909
|
+
this.originalOptions = JSON.parse(JSON.stringify(options));
|
|
620
910
|
if (options.isUserInteractionEnabled === void 0) {
|
|
621
911
|
this.isUserInteractionEnabled = true;
|
|
622
912
|
}
|
|
@@ -648,6 +938,15 @@ class DrawPad extends Composite {
|
|
|
648
938
|
if (options.continuousDrawingOnlyExceptionDistance !== void 0) {
|
|
649
939
|
this.continuousDrawingOnlyExceptionDistance = options.continuousDrawingOnlyExceptionDistance;
|
|
650
940
|
}
|
|
941
|
+
this.saveNodeNewEvent();
|
|
942
|
+
}
|
|
943
|
+
get completeNodeOptions() {
|
|
944
|
+
return {
|
|
945
|
+
...this.options,
|
|
946
|
+
...this.getNodeOptions(),
|
|
947
|
+
...this.getDrawableOptions(),
|
|
948
|
+
...this.originalOptions
|
|
949
|
+
};
|
|
651
950
|
}
|
|
652
951
|
initialize() {
|
|
653
952
|
this.initializeDrawShape();
|
|
@@ -670,7 +969,8 @@ class DrawPad extends Composite {
|
|
|
670
969
|
if (!this.drawArea) {
|
|
671
970
|
this.drawArea = new Shape({
|
|
672
971
|
rect: { size: this.size },
|
|
673
|
-
isUserInteractionEnabled: true
|
|
972
|
+
isUserInteractionEnabled: true,
|
|
973
|
+
suppressEvents: true
|
|
674
974
|
});
|
|
675
975
|
this.addChild(this.drawArea);
|
|
676
976
|
this.drawArea.onTapDown((e) => {
|
|
@@ -714,7 +1014,8 @@ class DrawPad extends Composite {
|
|
|
714
1014
|
type: DrawPadEventType.StrokeStart,
|
|
715
1015
|
target: this,
|
|
716
1016
|
handled: false,
|
|
717
|
-
position: e.point
|
|
1017
|
+
position: e.point,
|
|
1018
|
+
...M2c2KitHelpers.createTimestamps()
|
|
718
1019
|
};
|
|
719
1020
|
this.strokes.push([
|
|
720
1021
|
{
|
|
@@ -745,7 +1046,8 @@ class DrawPad extends Composite {
|
|
|
745
1046
|
type: DrawPadEventType.StrokeMove,
|
|
746
1047
|
target: this,
|
|
747
1048
|
handled: false,
|
|
748
|
-
position: interpolatedPoint
|
|
1049
|
+
position: interpolatedPoint,
|
|
1050
|
+
...M2c2KitHelpers.createTimestamps()
|
|
749
1051
|
};
|
|
750
1052
|
this.strokes[strokeCount - 1].push({
|
|
751
1053
|
type: DrawPadEventType.StrokeMove,
|
|
@@ -775,7 +1077,8 @@ class DrawPad extends Composite {
|
|
|
775
1077
|
type: DrawPadEventType.StrokeEnd,
|
|
776
1078
|
position: this.strokes[strokeCount - 1][strokeInteractionCount - 1].position,
|
|
777
1079
|
target: this,
|
|
778
|
-
handled: false
|
|
1080
|
+
handled: false,
|
|
1081
|
+
...M2c2KitHelpers.createTimestamps()
|
|
779
1082
|
};
|
|
780
1083
|
this.strokes[strokeCount - 1].push({
|
|
781
1084
|
type: DrawPadEventType.StrokeEnd,
|
|
@@ -803,7 +1106,8 @@ class DrawPad extends Composite {
|
|
|
803
1106
|
type: DrawPadEventType.StrokeEnd,
|
|
804
1107
|
position: this.strokes[strokeCount - 1][strokeInteractionCount - 1].position,
|
|
805
1108
|
target: this,
|
|
806
|
-
handled: false
|
|
1109
|
+
handled: false,
|
|
1110
|
+
...M2c2KitHelpers.createTimestamps()
|
|
807
1111
|
};
|
|
808
1112
|
this.strokes[strokeCount - 1].push({
|
|
809
1113
|
type: DrawPadEventType.StrokeEnd,
|
|
@@ -831,7 +1135,8 @@ class DrawPad extends Composite {
|
|
|
831
1135
|
type: DrawPadEventType.StrokeMove,
|
|
832
1136
|
target: this,
|
|
833
1137
|
handled: false,
|
|
834
|
-
position: e.point
|
|
1138
|
+
position: e.point,
|
|
1139
|
+
...M2c2KitHelpers.createTimestamps()
|
|
835
1140
|
};
|
|
836
1141
|
const strokeCount = this.strokes.length;
|
|
837
1142
|
this.strokes[strokeCount - 1].push({
|
|
@@ -986,7 +1291,8 @@ class DrawPad extends Composite {
|
|
|
986
1291
|
node.isStrokeWithinBounds = true;
|
|
987
1292
|
const drawPadItemEvent = {
|
|
988
1293
|
type: DrawPadItemEventType.StrokeEnter,
|
|
989
|
-
target: node
|
|
1294
|
+
target: node,
|
|
1295
|
+
...M2c2KitHelpers.createTimestamps()
|
|
990
1296
|
};
|
|
991
1297
|
this.raiseDrawPadItemEvent(node, drawPadItemEvent);
|
|
992
1298
|
}
|
|
@@ -998,7 +1304,8 @@ class DrawPad extends Composite {
|
|
|
998
1304
|
node.isStrokeWithinBounds = true;
|
|
999
1305
|
const drawPadItemEvent = {
|
|
1000
1306
|
type: DrawPadItemEventType.StrokeEnter,
|
|
1001
|
-
target: node
|
|
1307
|
+
target: node,
|
|
1308
|
+
...M2c2KitHelpers.createTimestamps()
|
|
1002
1309
|
};
|
|
1003
1310
|
this.raiseDrawPadItemEvent(node, drawPadItemEvent);
|
|
1004
1311
|
}
|
|
@@ -1010,7 +1317,8 @@ class DrawPad extends Composite {
|
|
|
1010
1317
|
node.isStrokeWithinBounds = false;
|
|
1011
1318
|
const drawPadItemEvent = {
|
|
1012
1319
|
type: DrawPadItemEventType.StrokeLeave,
|
|
1013
|
-
target: node
|
|
1320
|
+
target: node,
|
|
1321
|
+
...M2c2KitHelpers.createTimestamps()
|
|
1014
1322
|
};
|
|
1015
1323
|
this.raiseDrawPadItemEvent(node, drawPadItemEvent);
|
|
1016
1324
|
}
|
|
@@ -1021,7 +1329,8 @@ class DrawPad extends Composite {
|
|
|
1021
1329
|
node.isStrokeWithinBounds = false;
|
|
1022
1330
|
const drawPadItemEvent = {
|
|
1023
1331
|
type: DrawPadItemEventType.StrokeLeave,
|
|
1024
|
-
target: node
|
|
1332
|
+
target: node,
|
|
1333
|
+
...M2c2KitHelpers.createTimestamps()
|
|
1025
1334
|
};
|
|
1026
1335
|
this.raiseDrawPadItemEvent(node, drawPadItemEvent);
|
|
1027
1336
|
}
|
|
@@ -1044,10 +1353,10 @@ class DrawPad extends Composite {
|
|
|
1044
1353
|
if (!drawArea) {
|
|
1045
1354
|
throw new Error("DrawPad.takeScreenshot(): no drawArea");
|
|
1046
1355
|
}
|
|
1047
|
-
const sx = (drawArea.absolutePosition.x - drawArea.size.width / 2) *
|
|
1048
|
-
const sy = (drawArea.absolutePosition.y - drawArea.size.height / 2) *
|
|
1049
|
-
const sw = drawArea.size.width *
|
|
1050
|
-
const sh = drawArea.size.height *
|
|
1356
|
+
const sx = (drawArea.absolutePosition.x - drawArea.size.width / 2) * m2c2Globals.canvasScale;
|
|
1357
|
+
const sy = (drawArea.absolutePosition.y - drawArea.size.height / 2) * m2c2Globals.canvasScale;
|
|
1358
|
+
const sw = drawArea.size.width * m2c2Globals.canvasScale;
|
|
1359
|
+
const sh = drawArea.size.height * m2c2Globals.canvasScale;
|
|
1051
1360
|
const imageInfo = {
|
|
1052
1361
|
alphaType: this.game.canvasKit.AlphaType.Unpremul,
|
|
1053
1362
|
colorType: this.game.canvasKit.ColorType.RGBA_8888,
|
|
@@ -1186,9 +1495,10 @@ class DrawPad extends Composite {
|
|
|
1186
1495
|
this.needsInitialization = true;
|
|
1187
1496
|
}
|
|
1188
1497
|
duplicate(newName) {
|
|
1189
|
-
throw new Error(
|
|
1498
|
+
throw new Error(`DrawPad.duplicate(): Method not implemented. ${newName}`);
|
|
1190
1499
|
}
|
|
1191
1500
|
}
|
|
1501
|
+
M2c2KitHelpers.registerM2NodeClass(DrawPad);
|
|
1192
1502
|
|
|
1193
1503
|
class VirtualKeyboard extends Composite {
|
|
1194
1504
|
/**
|
|
@@ -1198,8 +1508,15 @@ class VirtualKeyboard extends Composite {
|
|
|
1198
1508
|
*/
|
|
1199
1509
|
constructor(options) {
|
|
1200
1510
|
super(options);
|
|
1201
|
-
this.
|
|
1511
|
+
this.compositeType = "VirtualKeyboard";
|
|
1512
|
+
this.keyboardRows = new Array();
|
|
1202
1513
|
this.shiftActivated = false;
|
|
1514
|
+
this.keyShapes = new Array();
|
|
1515
|
+
this.keyLabels = new Array();
|
|
1516
|
+
this.originalOptions = JSON.parse(JSON.stringify(options));
|
|
1517
|
+
if (options.isUserInteractionEnabled === void 0) {
|
|
1518
|
+
this._isUserInteractionEnabled = true;
|
|
1519
|
+
}
|
|
1203
1520
|
this.size = options.size;
|
|
1204
1521
|
this.position = options.position ?? { x: 0, y: 0 };
|
|
1205
1522
|
this.keyboardHorizontalPaddingPercent = options.keyboardHorizontalPaddingPercent ?? 0.02;
|
|
@@ -1207,11 +1524,12 @@ class VirtualKeyboard extends Composite {
|
|
|
1207
1524
|
this.keyHorizontalPaddingPercent = options.keyHorizontalPaddingPercent ?? 0.1;
|
|
1208
1525
|
this.keyVerticalPaddingPercent = options.keyVerticalPaddingPercent ?? 0.1;
|
|
1209
1526
|
if (options.rows !== void 0) {
|
|
1210
|
-
this.
|
|
1527
|
+
this.keyboardRows = options.rows.map((row) => {
|
|
1211
1528
|
const internalRow = row.map((key) => {
|
|
1212
1529
|
if (key instanceof Object && !Array.isArray(key)) {
|
|
1213
1530
|
const internalKeyConfig = key;
|
|
1214
1531
|
if (key.keyIconShapeOptions) {
|
|
1532
|
+
key.keyIconShapeOptions.suppressEvents = true;
|
|
1215
1533
|
internalKeyConfig.keyIcon = new Shape(key.keyIconShapeOptions);
|
|
1216
1534
|
internalKeyConfig.keyIconShapeOptions = void 0;
|
|
1217
1535
|
}
|
|
@@ -1233,156 +1551,48 @@ class VirtualKeyboard extends Composite {
|
|
|
1233
1551
|
this.specialKeyDownColor = options.specialKeyDownColor ?? WebColors.LightSteelBlue;
|
|
1234
1552
|
this.backgroundColor = options.backgroundColor ?? [242, 240, 244, 1];
|
|
1235
1553
|
this.showKeyDownPreview = options.showKeyDownPreview ?? true;
|
|
1554
|
+
this.saveNodeNewEvent();
|
|
1555
|
+
}
|
|
1556
|
+
get completeNodeOptions() {
|
|
1557
|
+
return {
|
|
1558
|
+
...this.options,
|
|
1559
|
+
...this.getNodeOptions(),
|
|
1560
|
+
...this.getDrawableOptions(),
|
|
1561
|
+
...this.originalOptions
|
|
1562
|
+
};
|
|
1236
1563
|
}
|
|
1237
1564
|
initialize() {
|
|
1238
|
-
if (this.
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
["5", "%"],
|
|
1245
|
-
["6", "^"],
|
|
1246
|
-
["7", "&"],
|
|
1247
|
-
["8", "*"],
|
|
1248
|
-
["9", "("],
|
|
1249
|
-
["0", ")"]
|
|
1250
|
-
];
|
|
1251
|
-
const row1 = [
|
|
1252
|
-
"q",
|
|
1253
|
-
"w",
|
|
1254
|
-
"e",
|
|
1255
|
-
"r",
|
|
1256
|
-
"t",
|
|
1257
|
-
"y",
|
|
1258
|
-
"u",
|
|
1259
|
-
"i",
|
|
1260
|
-
"o",
|
|
1261
|
-
"p"
|
|
1262
|
-
];
|
|
1263
|
-
const row2 = [
|
|
1264
|
-
"a",
|
|
1265
|
-
"s",
|
|
1266
|
-
"d",
|
|
1267
|
-
"f",
|
|
1268
|
-
"g",
|
|
1269
|
-
"h",
|
|
1270
|
-
"j",
|
|
1271
|
-
"k",
|
|
1272
|
-
"l"
|
|
1273
|
-
];
|
|
1274
|
-
const shiftArrowShapeOptions = {
|
|
1275
|
-
path: {
|
|
1276
|
-
// Public Domain from https://www.freesvg.org
|
|
1277
|
-
pathString: "m288-6.6849e-14 -288 288h144v288h288v-288h144l-288-288z",
|
|
1278
|
-
width: 24
|
|
1279
|
-
},
|
|
1280
|
-
lineWidth: 2,
|
|
1281
|
-
strokeColor: WebColors.Black,
|
|
1282
|
-
fillColor: WebColors.Transparent
|
|
1283
|
-
};
|
|
1284
|
-
const backspaceShapeOptions = {
|
|
1285
|
-
path: {
|
|
1286
|
-
// CC0 from https://www.svgrepo.com
|
|
1287
|
-
pathString: "M10.625 5.09 0 22.09l10.625 17H44.18v-34H10.625zm31.555 32H11.734l-9.375-15 9.375-15H42.18v30zm-23.293-6.293 7.293-7.293 7.293 7.293 1.414-1.414-7.293-7.293 7.293-7.293-1.414-1.414-7.293 7.293-7.293-7.293-1.414 1.414 7.293 7.293-7.293 7.293",
|
|
1288
|
-
width: 24
|
|
1289
|
-
},
|
|
1290
|
-
lineWidth: 1,
|
|
1291
|
-
strokeColor: WebColors.Black,
|
|
1292
|
-
fillColor: WebColors.Red
|
|
1293
|
-
};
|
|
1294
|
-
const row3 = [
|
|
1295
|
-
{
|
|
1296
|
-
code: "Shift",
|
|
1297
|
-
isShift: true,
|
|
1298
|
-
widthRatio: 1.5,
|
|
1299
|
-
keyIcon: new Shape(shiftArrowShapeOptions)
|
|
1300
|
-
},
|
|
1301
|
-
"z",
|
|
1302
|
-
"x",
|
|
1303
|
-
"c",
|
|
1304
|
-
"v",
|
|
1305
|
-
"b",
|
|
1306
|
-
"n",
|
|
1307
|
-
"m",
|
|
1308
|
-
{
|
|
1309
|
-
code: "Backspace",
|
|
1310
|
-
widthRatio: 1.5,
|
|
1311
|
-
keyIcon: new Shape(backspaceShapeOptions)
|
|
1312
|
-
}
|
|
1313
|
-
];
|
|
1314
|
-
const row4 = [
|
|
1315
|
-
{ code: " ", labelText: "SPACE", widthRatio: 5 }
|
|
1316
|
-
];
|
|
1317
|
-
const keyboardRows = [
|
|
1318
|
-
numKeys,
|
|
1319
|
-
row1,
|
|
1320
|
-
row2,
|
|
1321
|
-
row3,
|
|
1322
|
-
row4
|
|
1323
|
-
];
|
|
1324
|
-
this.rowsConfiguration = keyboardRows;
|
|
1325
|
-
this.keysPerRow = this.rowsConfiguration.reduce(
|
|
1565
|
+
if (this.game.eventStore.mode === EventStoreMode.Replay) {
|
|
1566
|
+
this._isUserInteractionEnabled = false;
|
|
1567
|
+
}
|
|
1568
|
+
if (this.keyboardRows.length === 0) {
|
|
1569
|
+
this.keyboardRows = this.createDefaultKeyboardRows();
|
|
1570
|
+
this.keysPerRow = this.keyboardRows.reduce(
|
|
1326
1571
|
(max, row) => Math.max(max, row.length),
|
|
1327
1572
|
0
|
|
1328
1573
|
);
|
|
1329
|
-
this.fontSize = this.size.height / this.
|
|
1574
|
+
this.fontSize = this.size.height / this.keyboardRows.length / 2.5;
|
|
1330
1575
|
}
|
|
1331
1576
|
const keyboardRectangle = new Shape({
|
|
1332
1577
|
rect: { size: this.size },
|
|
1333
|
-
fillColor: this.backgroundColor
|
|
1578
|
+
fillColor: this.backgroundColor,
|
|
1579
|
+
suppressEvents: true
|
|
1334
1580
|
});
|
|
1335
1581
|
this.addChild(keyboardRectangle);
|
|
1336
|
-
const
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
const heightRatio = 1;
|
|
1340
|
-
let code;
|
|
1341
|
-
let label;
|
|
1342
|
-
let labelShifted;
|
|
1343
|
-
let keyIcon;
|
|
1344
|
-
let isShift = false;
|
|
1345
|
-
if (typeof key === "string") {
|
|
1346
|
-
code = key;
|
|
1347
|
-
if (this.capitalLettersOnly) {
|
|
1348
|
-
label = code.toUpperCase();
|
|
1349
|
-
} else {
|
|
1350
|
-
label = code;
|
|
1351
|
-
}
|
|
1352
|
-
labelShifted = code.toUpperCase();
|
|
1353
|
-
} else if (Array.isArray(key)) {
|
|
1354
|
-
code = key[0];
|
|
1355
|
-
label = code;
|
|
1356
|
-
labelShifted = key[1];
|
|
1357
|
-
} else {
|
|
1358
|
-
code = key.code;
|
|
1359
|
-
label = key.labelText ?? "";
|
|
1360
|
-
labelShifted = key.labelTextShifted ?? label;
|
|
1361
|
-
widthRatio = key.widthRatio ?? 1;
|
|
1362
|
-
keyIcon = key.keyIcon;
|
|
1363
|
-
isShift = key.isShift ?? false;
|
|
1364
|
-
}
|
|
1365
|
-
return {
|
|
1366
|
-
widthRatio,
|
|
1367
|
-
heightRatio,
|
|
1368
|
-
code,
|
|
1369
|
-
labelText: label,
|
|
1370
|
-
labelTextShifted: labelShifted,
|
|
1371
|
-
keyIcon,
|
|
1372
|
-
isShift
|
|
1373
|
-
};
|
|
1374
|
-
});
|
|
1375
|
-
});
|
|
1582
|
+
const keyboard = this.internalKeyboardRowsToInternalKeyboardConfiguration(
|
|
1583
|
+
this.keyboardRows
|
|
1584
|
+
);
|
|
1376
1585
|
const keyboardOrigin = {
|
|
1377
1586
|
x: -keyboardRectangle.size.width / 2,
|
|
1378
1587
|
y: -keyboardRectangle.size.height / 2
|
|
1379
1588
|
};
|
|
1380
1589
|
const keyboardVerticalPadding = (this.keyboardVerticalPaddingPercent ?? 0.025) * this.size.height;
|
|
1381
1590
|
const keyboardHorizontalPadding = (this.keyboardHorizontalPaddingPercent ?? 0.02) * this.size.width;
|
|
1382
|
-
const keyBoxHeight = (this.size.height - 2 * keyboardVerticalPadding) /
|
|
1591
|
+
const keyBoxHeight = (this.size.height - 2 * keyboardVerticalPadding) / keyboard.length;
|
|
1383
1592
|
const keyBoxWidth = (this.size.width - 2 * keyboardHorizontalPadding) / this.keysPerRow;
|
|
1384
|
-
|
|
1385
|
-
|
|
1593
|
+
this.keyShapes = [];
|
|
1594
|
+
for (let r = 0; r < keyboard.length; r++) {
|
|
1595
|
+
const row = keyboard[r];
|
|
1386
1596
|
const rowSumKeyWidths = row.reduce(
|
|
1387
1597
|
(sum, key) => sum + (key.widthRatio ?? 1),
|
|
1388
1598
|
0
|
|
@@ -1393,7 +1603,7 @@ class VirtualKeyboard extends Composite {
|
|
|
1393
1603
|
}
|
|
1394
1604
|
for (let k = 0; k < row.length; k++) {
|
|
1395
1605
|
const key = row[k];
|
|
1396
|
-
if (this.hiddenKeys?.split(",").map((s) => s.trim()).includes(key.code)) {
|
|
1606
|
+
if (this.hiddenKeys?.split(",").map((s) => s === " " ? " " : s.trim()).includes(key.code)) {
|
|
1397
1607
|
continue;
|
|
1398
1608
|
}
|
|
1399
1609
|
const keyBoxWidthsSoFar = row.slice(0, k).reduce((sum, key2) => sum + (key2.widthRatio ?? 1), 0) * keyBoxWidth;
|
|
@@ -1410,7 +1620,8 @@ class VirtualKeyboard extends Composite {
|
|
|
1410
1620
|
position: {
|
|
1411
1621
|
x: extraPadding + keyboardOrigin.x + keyboardHorizontalPadding + keyBoxWidthsSoFar + (key.widthRatio ?? 1) * keyBoxWidth / 2,
|
|
1412
1622
|
y: keyboardOrigin.y + keyboardVerticalPadding + r * keyBoxHeight + keyBoxHeight / 2
|
|
1413
|
-
}
|
|
1623
|
+
},
|
|
1624
|
+
suppressEvents: true
|
|
1414
1625
|
});
|
|
1415
1626
|
const keyWidth = keyBoxWidth * (key.widthRatio ?? 1) - 2 * this.keyHorizontalPaddingPercent * keyBoxWidth;
|
|
1416
1627
|
const keyHeight = keyBoxHeight - (key.heightRatio ?? 1) - 2 * this.keyVerticalPaddingPercent * keyBoxHeight;
|
|
@@ -1419,163 +1630,50 @@ class VirtualKeyboard extends Composite {
|
|
|
1419
1630
|
cornerRadius: 4,
|
|
1420
1631
|
fillColor: this.keyColor,
|
|
1421
1632
|
lineWidth: 0,
|
|
1422
|
-
isUserInteractionEnabled:
|
|
1633
|
+
isUserInteractionEnabled: this.isUserInteractionEnabled,
|
|
1634
|
+
suppressEvents: true
|
|
1423
1635
|
});
|
|
1636
|
+
keyShape.userData = { code: key.code };
|
|
1424
1637
|
keyBox.addChild(keyShape);
|
|
1425
|
-
|
|
1426
|
-
let keyAsString = "";
|
|
1427
|
-
if (!key.isShift) {
|
|
1428
|
-
if (this.shiftActivated) {
|
|
1429
|
-
this.shiftActivated = false;
|
|
1430
|
-
if (this.shiftKeyShape) {
|
|
1431
|
-
this.shiftKeyShape.fillColor = this.keyColor;
|
|
1432
|
-
if (key.keyIcon) {
|
|
1433
|
-
key.keyIcon.fillColor = WebColors.Transparent;
|
|
1434
|
-
}
|
|
1435
|
-
}
|
|
1436
|
-
rows.flatMap((k2) => k2).forEach((k2) => {
|
|
1437
|
-
if (k2.keyLabel?.text !== void 0) {
|
|
1438
|
-
k2.keyLabel.text = k2.labelText ?? "";
|
|
1439
|
-
}
|
|
1440
|
-
});
|
|
1441
|
-
keyAsString = key.labelTextShifted ?? key.code;
|
|
1442
|
-
} else {
|
|
1443
|
-
keyAsString = key.labelText ?? key.code;
|
|
1444
|
-
}
|
|
1445
|
-
if (key.code === " " || key.code === "Backspace") {
|
|
1446
|
-
keyAsString = key.code;
|
|
1447
|
-
}
|
|
1448
|
-
keyShape.fillColor = this.keyColor;
|
|
1449
|
-
} else {
|
|
1450
|
-
if (!this.shiftActivated) {
|
|
1451
|
-
keyShape.fillColor = this.keyColor;
|
|
1452
|
-
} else {
|
|
1453
|
-
keyShape.fillColor = this.specialKeyDownColor;
|
|
1454
|
-
}
|
|
1455
|
-
keyAsString = key.code;
|
|
1456
|
-
}
|
|
1457
|
-
letterCircle.hidden = true;
|
|
1458
|
-
if (this.eventListeners.length > 0) {
|
|
1459
|
-
this.eventListeners.filter(
|
|
1460
|
-
(listener) => listener.type === M2EventType.CompositeCustom && listener.compositeType === "VirtualKeyboardKeyUp"
|
|
1461
|
-
).forEach((listener) => {
|
|
1462
|
-
const virtualKeyboardEvent = {
|
|
1463
|
-
type: M2EventType.CompositeCustom,
|
|
1464
|
-
target: this,
|
|
1465
|
-
handled: false,
|
|
1466
|
-
key: keyAsString,
|
|
1467
|
-
code: key.code,
|
|
1468
|
-
shiftKey: this.shiftActivated,
|
|
1469
|
-
keyTapMetadata: {
|
|
1470
|
-
size: keyShape.size,
|
|
1471
|
-
point: tapEvent.point,
|
|
1472
|
-
buttons: tapEvent.buttons
|
|
1473
|
-
}
|
|
1474
|
-
};
|
|
1475
|
-
listener.callback(virtualKeyboardEvent);
|
|
1476
|
-
});
|
|
1477
|
-
}
|
|
1478
|
-
});
|
|
1479
|
-
keyShape.onTapDown((tapEvent) => {
|
|
1480
|
-
if (key.isShift) {
|
|
1481
|
-
this.shiftActivated = !this.shiftActivated;
|
|
1482
|
-
if (this.shiftActivated) {
|
|
1483
|
-
keyShape.fillColor = this.specialKeyDownColor;
|
|
1484
|
-
if (key.keyIcon) {
|
|
1485
|
-
key.keyIcon.fillColor = WebColors.Black;
|
|
1486
|
-
}
|
|
1487
|
-
rows.flatMap((k2) => k2).forEach((k2) => {
|
|
1488
|
-
if (k2.keyLabel?.text !== void 0) {
|
|
1489
|
-
k2.keyLabel.text = k2.labelTextShifted ?? k2.labelText ?? "";
|
|
1490
|
-
}
|
|
1491
|
-
});
|
|
1492
|
-
} else {
|
|
1493
|
-
keyShape.fillColor = this.keyColor;
|
|
1494
|
-
if (key.keyIcon) {
|
|
1495
|
-
key.keyIcon.fillColor = WebColors.Transparent;
|
|
1496
|
-
}
|
|
1497
|
-
rows.flatMap((k2) => k2).forEach((k2) => {
|
|
1498
|
-
if (k2.keyLabel?.text !== void 0) {
|
|
1499
|
-
k2.keyLabel.text = k2.labelText ?? "";
|
|
1500
|
-
}
|
|
1501
|
-
});
|
|
1502
|
-
}
|
|
1503
|
-
}
|
|
1504
|
-
let keyAsString = "";
|
|
1505
|
-
if (key.isShift || key.code === " " || key.code === "Backspace") {
|
|
1506
|
-
keyShape.fillColor = this.specialKeyDownColor;
|
|
1507
|
-
keyAsString = key.code;
|
|
1508
|
-
} else {
|
|
1509
|
-
keyShape.fillColor = this.keyDownColor;
|
|
1510
|
-
if (this.showKeyDownPreview) {
|
|
1511
|
-
letterCircle.hidden = false;
|
|
1512
|
-
letterCircle.position.x = keyBox.position.x;
|
|
1513
|
-
letterCircle.position.y = keyBox.position.y - keyHeight * 1.2;
|
|
1514
|
-
if (this.shiftActivated) {
|
|
1515
|
-
letterCircleLabel.text = key.labelTextShifted ?? key.code;
|
|
1516
|
-
} else {
|
|
1517
|
-
letterCircleLabel.text = key.labelText ?? key.code;
|
|
1518
|
-
}
|
|
1519
|
-
}
|
|
1520
|
-
if (this.shiftActivated) {
|
|
1521
|
-
keyAsString = key.labelTextShifted ?? key.code;
|
|
1522
|
-
} else {
|
|
1523
|
-
keyAsString = key.labelText ?? key.code;
|
|
1524
|
-
}
|
|
1525
|
-
}
|
|
1526
|
-
if (this.eventListeners.length > 0) {
|
|
1527
|
-
this.eventListeners.filter(
|
|
1528
|
-
(listener) => listener.type === M2EventType.CompositeCustom && listener.compositeType === "VirtualKeyboardKeyDown"
|
|
1529
|
-
).forEach((listener) => {
|
|
1530
|
-
const virtualKeyboardEvent = {
|
|
1531
|
-
type: M2EventType.CompositeCustom,
|
|
1532
|
-
target: this,
|
|
1533
|
-
handled: false,
|
|
1534
|
-
key: keyAsString,
|
|
1535
|
-
code: key.code,
|
|
1536
|
-
shiftKey: this.shiftActivated,
|
|
1537
|
-
keyTapMetadata: {
|
|
1538
|
-
size: keyShape.size,
|
|
1539
|
-
point: tapEvent.point,
|
|
1540
|
-
buttons: tapEvent.buttons
|
|
1541
|
-
}
|
|
1542
|
-
};
|
|
1543
|
-
listener.callback(virtualKeyboardEvent);
|
|
1544
|
-
});
|
|
1545
|
-
}
|
|
1546
|
-
});
|
|
1547
|
-
keyShape.onTapLeave(() => {
|
|
1548
|
-
keyShape.fillColor = this.keyColor;
|
|
1549
|
-
letterCircle.hidden = true;
|
|
1550
|
-
});
|
|
1638
|
+
this.keyShapes.push(keyShape);
|
|
1551
1639
|
const keyLabel = new Label({
|
|
1552
1640
|
text: key.labelText,
|
|
1553
1641
|
fontSize: this.fontSize,
|
|
1554
|
-
fontNames: this.fontNames
|
|
1642
|
+
fontNames: this.fontNames,
|
|
1643
|
+
suppressEvents: true
|
|
1555
1644
|
});
|
|
1645
|
+
keyLabel.userData = { code: key.code };
|
|
1556
1646
|
keyBox.addChild(keyLabel);
|
|
1557
|
-
|
|
1558
|
-
if (key.isShift) {
|
|
1559
|
-
this.shiftKeyShape = keyShape;
|
|
1560
|
-
}
|
|
1647
|
+
this.keyLabels.push(keyLabel);
|
|
1561
1648
|
if (key.keyIcon) {
|
|
1562
1649
|
keyBox.addChild(key.keyIcon);
|
|
1563
1650
|
}
|
|
1564
1651
|
keyboardRectangle.addChild(keyBox);
|
|
1652
|
+
keyShape.onTapUp((tapEvent) => {
|
|
1653
|
+
this.handleKeyShapeTapUp(key, keyShape, tapEvent);
|
|
1654
|
+
});
|
|
1655
|
+
keyShape.onTapDown((tapEvent) => {
|
|
1656
|
+
this.handleKeyShapeTapDown(key, keyShape, tapEvent);
|
|
1657
|
+
});
|
|
1658
|
+
keyShape.onTapLeave((tapEvent) => {
|
|
1659
|
+
this.handleKeyShapeTapLeave(key, keyShape, tapEvent);
|
|
1660
|
+
});
|
|
1565
1661
|
}
|
|
1566
1662
|
}
|
|
1567
|
-
|
|
1663
|
+
this.letterCircle = new Shape({
|
|
1568
1664
|
circleOfRadius: 28,
|
|
1569
1665
|
fillColor: WebColors.Silver,
|
|
1570
|
-
hidden: true
|
|
1666
|
+
hidden: true,
|
|
1667
|
+
suppressEvents: true
|
|
1571
1668
|
});
|
|
1572
|
-
keyboardRectangle.addChild(letterCircle);
|
|
1573
|
-
|
|
1669
|
+
keyboardRectangle.addChild(this.letterCircle);
|
|
1670
|
+
this.letterCircleLabel = new Label({
|
|
1574
1671
|
text: "",
|
|
1575
1672
|
fontSize: this.fontSize,
|
|
1576
|
-
fontNames: this.fontNames
|
|
1673
|
+
fontNames: this.fontNames,
|
|
1674
|
+
suppressEvents: true
|
|
1577
1675
|
});
|
|
1578
|
-
letterCircle.addChild(letterCircleLabel);
|
|
1676
|
+
this.letterCircle.addChild(this.letterCircleLabel);
|
|
1579
1677
|
this.needsInitialization = false;
|
|
1580
1678
|
}
|
|
1581
1679
|
/**
|
|
@@ -1586,8 +1684,9 @@ class VirtualKeyboard extends Composite {
|
|
|
1586
1684
|
*/
|
|
1587
1685
|
onKeyDown(callback, options) {
|
|
1588
1686
|
const eventListener = {
|
|
1589
|
-
type: M2EventType.
|
|
1590
|
-
|
|
1687
|
+
type: M2EventType.Composite,
|
|
1688
|
+
compositeEventType: "VirtualKeyboardKeyDown",
|
|
1689
|
+
compositeType: this.compositeType,
|
|
1591
1690
|
nodeUuid: this.uuid,
|
|
1592
1691
|
callback
|
|
1593
1692
|
};
|
|
@@ -1601,20 +1700,35 @@ class VirtualKeyboard extends Composite {
|
|
|
1601
1700
|
*/
|
|
1602
1701
|
onKeyUp(callback, options) {
|
|
1603
1702
|
const eventListener = {
|
|
1604
|
-
type: M2EventType.
|
|
1605
|
-
|
|
1703
|
+
type: M2EventType.Composite,
|
|
1704
|
+
compositeEventType: "VirtualKeyboardKeyUp",
|
|
1705
|
+
compositeType: this.compositeType,
|
|
1606
1706
|
nodeUuid: this.uuid,
|
|
1607
1707
|
callback
|
|
1608
1708
|
};
|
|
1609
1709
|
this.addVirtualKeyboardEventListener(eventListener, options);
|
|
1610
1710
|
}
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1711
|
+
/**
|
|
1712
|
+
* Executes a callback when the user has pressed a key with the pointer, but
|
|
1713
|
+
* moves the pointer outside the key bounds before releasing the pointer.
|
|
1714
|
+
*
|
|
1715
|
+
* @remarks Typically, this event will not be used, since it is a user's
|
|
1716
|
+
* inaccurate interaction with the keyboard. However, it can be used to
|
|
1717
|
+
* provide feedback to the user that they have moved the pointer outside the
|
|
1718
|
+
* key bounds, and thus the key stroke will not be registered.
|
|
1719
|
+
*
|
|
1720
|
+
* @param callback - function to execute
|
|
1721
|
+
* @param options
|
|
1722
|
+
*/
|
|
1723
|
+
onKeyLeave(callback, options) {
|
|
1724
|
+
const eventListener = {
|
|
1725
|
+
type: M2EventType.Composite,
|
|
1726
|
+
compositeEventType: "VirtualKeyboardKeyLeave",
|
|
1727
|
+
compositeType: this.compositeType,
|
|
1728
|
+
nodeUuid: this.uuid,
|
|
1729
|
+
callback
|
|
1730
|
+
};
|
|
1731
|
+
this.addVirtualKeyboardEventListener(eventListener, options);
|
|
1618
1732
|
}
|
|
1619
1733
|
update() {
|
|
1620
1734
|
super.update();
|
|
@@ -1629,9 +1743,417 @@ class VirtualKeyboard extends Composite {
|
|
|
1629
1743
|
});
|
|
1630
1744
|
}
|
|
1631
1745
|
duplicate(newName) {
|
|
1632
|
-
throw new Error(
|
|
1746
|
+
throw new Error(`Method not implemented. ${newName}`);
|
|
1747
|
+
}
|
|
1748
|
+
handleKeyShapeTapDown(key, keyShape, tapEvent) {
|
|
1749
|
+
if (key.isShift) {
|
|
1750
|
+
this.shiftActivated = !this.shiftActivated;
|
|
1751
|
+
}
|
|
1752
|
+
const keyAsString = this.getKeyAsString(key);
|
|
1753
|
+
const virtualKeyboardEvent = {
|
|
1754
|
+
type: M2EventType.Composite,
|
|
1755
|
+
compositeType: "VirtualKeyboard",
|
|
1756
|
+
compositeEventType: "VirtualKeyboardKeyDown",
|
|
1757
|
+
target: this,
|
|
1758
|
+
handled: false,
|
|
1759
|
+
key: keyAsString,
|
|
1760
|
+
code: key.code,
|
|
1761
|
+
shiftKey: this.shiftActivated,
|
|
1762
|
+
keyTapMetadata: {
|
|
1763
|
+
size: keyShape.size,
|
|
1764
|
+
point: tapEvent.point,
|
|
1765
|
+
buttons: tapEvent.buttons
|
|
1766
|
+
},
|
|
1767
|
+
...M2c2KitHelpers.createTimestamps()
|
|
1768
|
+
};
|
|
1769
|
+
this.handleCompositeEvent(virtualKeyboardEvent);
|
|
1770
|
+
this.saveEvent(virtualKeyboardEvent);
|
|
1771
|
+
if (this.eventListeners.length > 0) {
|
|
1772
|
+
this.eventListeners.filter(
|
|
1773
|
+
(listener) => listener.type === M2EventType.Composite && listener.compositeType === "VirtualKeyboard" && listener.compositeEventType === "VirtualKeyboardKeyDown"
|
|
1774
|
+
).forEach((listener) => {
|
|
1775
|
+
listener.callback(virtualKeyboardEvent);
|
|
1776
|
+
});
|
|
1777
|
+
}
|
|
1778
|
+
}
|
|
1779
|
+
handleKeyShapeTapUp(key, keyShape, tapEvent) {
|
|
1780
|
+
const keyAsString = this.getKeyAsString(key);
|
|
1781
|
+
const virtualKeyboardEvent = {
|
|
1782
|
+
type: M2EventType.Composite,
|
|
1783
|
+
compositeType: "VirtualKeyboard",
|
|
1784
|
+
compositeEventType: "VirtualKeyboardKeyUp",
|
|
1785
|
+
target: this,
|
|
1786
|
+
handled: false,
|
|
1787
|
+
key: keyAsString,
|
|
1788
|
+
code: key.code,
|
|
1789
|
+
shiftKey: this.shiftActivated,
|
|
1790
|
+
keyTapMetadata: {
|
|
1791
|
+
size: keyShape.size,
|
|
1792
|
+
point: tapEvent.point,
|
|
1793
|
+
buttons: tapEvent.buttons
|
|
1794
|
+
},
|
|
1795
|
+
...M2c2KitHelpers.createTimestamps()
|
|
1796
|
+
};
|
|
1797
|
+
this.handleCompositeEvent(virtualKeyboardEvent);
|
|
1798
|
+
this.saveEvent(virtualKeyboardEvent);
|
|
1799
|
+
if (this.eventListeners.length > 0) {
|
|
1800
|
+
this.eventListeners.filter(
|
|
1801
|
+
(listener) => listener.type === M2EventType.Composite && listener.compositeType === "VirtualKeyboard" && listener.compositeEventType === "VirtualKeyboardKeyUp"
|
|
1802
|
+
).forEach((listener) => {
|
|
1803
|
+
listener.callback(virtualKeyboardEvent);
|
|
1804
|
+
});
|
|
1805
|
+
}
|
|
1806
|
+
}
|
|
1807
|
+
handleKeyShapeTapLeave(key, keyShape, tapEvent) {
|
|
1808
|
+
const keyAsString = this.getKeyAsString(key);
|
|
1809
|
+
const virtualKeyboardEvent = {
|
|
1810
|
+
type: M2EventType.Composite,
|
|
1811
|
+
compositeType: "VirtualKeyboard",
|
|
1812
|
+
compositeEventType: "VirtualKeyboardKeyLeave",
|
|
1813
|
+
target: this,
|
|
1814
|
+
handled: false,
|
|
1815
|
+
key: keyAsString,
|
|
1816
|
+
code: key.code,
|
|
1817
|
+
shiftKey: this.shiftActivated,
|
|
1818
|
+
keyTapMetadata: {
|
|
1819
|
+
size: keyShape.size,
|
|
1820
|
+
point: tapEvent.point,
|
|
1821
|
+
buttons: tapEvent.buttons
|
|
1822
|
+
},
|
|
1823
|
+
...M2c2KitHelpers.createTimestamps()
|
|
1824
|
+
};
|
|
1825
|
+
this.handleCompositeEvent(virtualKeyboardEvent);
|
|
1826
|
+
this.saveEvent(virtualKeyboardEvent);
|
|
1827
|
+
if (this.eventListeners.length > 0) {
|
|
1828
|
+
this.eventListeners.filter(
|
|
1829
|
+
(listener) => listener.type === M2EventType.Composite && listener.compositeType === "VirtualKeyboard" && listener.compositeEventType === "VirtualKeyboardKeyLeave"
|
|
1830
|
+
).forEach((listener) => {
|
|
1831
|
+
listener.callback(virtualKeyboardEvent);
|
|
1832
|
+
});
|
|
1833
|
+
}
|
|
1834
|
+
}
|
|
1835
|
+
getKeyAsString(key) {
|
|
1836
|
+
if (key.isShift || key.code === " " || key.code === "Backspace") {
|
|
1837
|
+
return key.code;
|
|
1838
|
+
} else {
|
|
1839
|
+
if (this.shiftActivated) {
|
|
1840
|
+
return key.labelTextShifted ?? key.code;
|
|
1841
|
+
} else {
|
|
1842
|
+
return key.labelText ?? key.code;
|
|
1843
|
+
}
|
|
1844
|
+
}
|
|
1845
|
+
}
|
|
1846
|
+
/**
|
|
1847
|
+
* Converts the keyboard rows to the internal keyboard configuration.
|
|
1848
|
+
*
|
|
1849
|
+
* @remarks This normalizes the keyboard rows so that each key is a
|
|
1850
|
+
* full `KeyConfigurationWithShape` object, instead of a string or array of
|
|
1851
|
+
* strings.
|
|
1852
|
+
*
|
|
1853
|
+
* @param keyboardRows
|
|
1854
|
+
* @returns the keyboard for internal use
|
|
1855
|
+
*/
|
|
1856
|
+
internalKeyboardRowsToInternalKeyboardConfiguration(keyboardRows) {
|
|
1857
|
+
return keyboardRows.map((row) => {
|
|
1858
|
+
return row.map((key) => {
|
|
1859
|
+
let widthRatio = 1;
|
|
1860
|
+
const heightRatio = 1;
|
|
1861
|
+
let code;
|
|
1862
|
+
let label;
|
|
1863
|
+
let labelShifted;
|
|
1864
|
+
let keyIcon;
|
|
1865
|
+
let isShift = false;
|
|
1866
|
+
if (typeof key === "string") {
|
|
1867
|
+
code = key;
|
|
1868
|
+
if (this.capitalLettersOnly) {
|
|
1869
|
+
label = code.toUpperCase();
|
|
1870
|
+
} else {
|
|
1871
|
+
label = code;
|
|
1872
|
+
}
|
|
1873
|
+
labelShifted = code.toUpperCase();
|
|
1874
|
+
} else if (Array.isArray(key)) {
|
|
1875
|
+
code = key[0];
|
|
1876
|
+
label = code;
|
|
1877
|
+
labelShifted = key[1];
|
|
1878
|
+
} else {
|
|
1879
|
+
code = key.code;
|
|
1880
|
+
label = key.labelText ?? "";
|
|
1881
|
+
labelShifted = key.labelTextShifted ?? label;
|
|
1882
|
+
widthRatio = key.widthRatio ?? 1;
|
|
1883
|
+
keyIcon = key.keyIcon;
|
|
1884
|
+
isShift = key.isShift ?? false;
|
|
1885
|
+
}
|
|
1886
|
+
return {
|
|
1887
|
+
widthRatio,
|
|
1888
|
+
heightRatio,
|
|
1889
|
+
code,
|
|
1890
|
+
labelText: label,
|
|
1891
|
+
labelTextShifted: labelShifted,
|
|
1892
|
+
keyIcon,
|
|
1893
|
+
isShift
|
|
1894
|
+
};
|
|
1895
|
+
});
|
|
1896
|
+
});
|
|
1897
|
+
}
|
|
1898
|
+
handleCompositeEvent(event) {
|
|
1899
|
+
const keyboard = this.internalKeyboardRowsToInternalKeyboardConfiguration(
|
|
1900
|
+
this.keyboardRows
|
|
1901
|
+
);
|
|
1902
|
+
const keyShape = this.keyShapes.find((k) => k.userData.code === event.code);
|
|
1903
|
+
if (!keyShape) {
|
|
1904
|
+
throw new Error("keyShape is not defined");
|
|
1905
|
+
}
|
|
1906
|
+
this.shiftActivated = event.shiftKey;
|
|
1907
|
+
switch (event.compositeEventType) {
|
|
1908
|
+
case "VirtualKeyboardKeyDown": {
|
|
1909
|
+
this.handleKeyDownEvent(event, keyboard, keyShape);
|
|
1910
|
+
break;
|
|
1911
|
+
}
|
|
1912
|
+
case "VirtualKeyboardKeyUp": {
|
|
1913
|
+
this.handleKeyUpEvent(event, keyboard, keyShape);
|
|
1914
|
+
break;
|
|
1915
|
+
}
|
|
1916
|
+
case "VirtualKeyboardKeyLeave": {
|
|
1917
|
+
this.handleKeyLeaveEvent(event, keyboard, keyShape);
|
|
1918
|
+
break;
|
|
1919
|
+
}
|
|
1920
|
+
default: {
|
|
1921
|
+
throw new Error(
|
|
1922
|
+
`Unknown VirtualKeyboardEvent: ${event.compositeEventType}`
|
|
1923
|
+
);
|
|
1924
|
+
}
|
|
1925
|
+
}
|
|
1926
|
+
}
|
|
1927
|
+
handleKeyDownEvent(event, keyboard, keyShape) {
|
|
1928
|
+
if (event.code.toLowerCase().includes("shift")) {
|
|
1929
|
+
if (event.shiftKey) {
|
|
1930
|
+
this.showKeyboardShifted(keyboard);
|
|
1931
|
+
} else {
|
|
1932
|
+
this.showKeyboardNotShifted(keyboard);
|
|
1933
|
+
}
|
|
1934
|
+
} else if (event.code === " " || event.code === "Backspace") {
|
|
1935
|
+
keyShape.fillColor = this.specialKeyDownColor;
|
|
1936
|
+
} else {
|
|
1937
|
+
keyShape.fillColor = this.keyDownColor;
|
|
1938
|
+
if (this.showKeyDownPreview) {
|
|
1939
|
+
if (!this.letterCircle || !this.letterCircleLabel) {
|
|
1940
|
+
throw new Error("letterCircle is not defined");
|
|
1941
|
+
}
|
|
1942
|
+
this.letterCircle.hidden = false;
|
|
1943
|
+
const keyBox = keyShape.parent;
|
|
1944
|
+
this.letterCircle.position.x = keyBox.position.x;
|
|
1945
|
+
if (keyShape.rect?.size?.height === void 0) {
|
|
1946
|
+
throw new Error("keyShape.rect.height is undefined");
|
|
1947
|
+
}
|
|
1948
|
+
this.letterCircle.position.y = keyBox.position.y - keyShape.rect.size.height * 1.2;
|
|
1949
|
+
const keyboard2 = this.internalKeyboardRowsToInternalKeyboardConfiguration(
|
|
1950
|
+
this.keyboardRows
|
|
1951
|
+
);
|
|
1952
|
+
const key = keyboard2.flat().find((k) => k.code === event.code);
|
|
1953
|
+
if (!key) {
|
|
1954
|
+
throw new Error("key is not defined");
|
|
1955
|
+
}
|
|
1956
|
+
if (this.shiftActivated) {
|
|
1957
|
+
this.letterCircleLabel.text = key.labelTextShifted ?? key.code;
|
|
1958
|
+
} else {
|
|
1959
|
+
this.letterCircleLabel.text = key.labelText ?? key.code;
|
|
1960
|
+
}
|
|
1961
|
+
}
|
|
1962
|
+
}
|
|
1963
|
+
}
|
|
1964
|
+
handleKeyUpEvent(event, keyboard, keyShape) {
|
|
1965
|
+
if (event.code.toLowerCase().includes("shift") && event.shiftKey) {
|
|
1966
|
+
return;
|
|
1967
|
+
}
|
|
1968
|
+
if (event.code.toLowerCase().includes("shift") && !event.shiftKey) {
|
|
1969
|
+
this.shiftActivated = false;
|
|
1970
|
+
this.showKeyboardNotShifted(keyboard);
|
|
1971
|
+
return;
|
|
1972
|
+
}
|
|
1973
|
+
keyShape.fillColor = this.keyColor;
|
|
1974
|
+
if (!this.letterCircle) {
|
|
1975
|
+
throw new Error("letterCircle is not defined");
|
|
1976
|
+
}
|
|
1977
|
+
this.letterCircle.hidden = true;
|
|
1978
|
+
if (!event.code.toLowerCase().includes("shift") && event.shiftKey) {
|
|
1979
|
+
this.shiftActivated = false;
|
|
1980
|
+
this.showKeyboardNotShifted(keyboard);
|
|
1981
|
+
}
|
|
1982
|
+
}
|
|
1983
|
+
handleKeyLeaveEvent(event, keyboard, keyShape) {
|
|
1984
|
+
if (event.code.toLowerCase().includes("shift")) {
|
|
1985
|
+
if (event.shiftKey) {
|
|
1986
|
+
this.showKeyboardNotShifted(keyboard);
|
|
1987
|
+
this.shiftActivated = false;
|
|
1988
|
+
} else {
|
|
1989
|
+
this.showKeyboardShifted(keyboard);
|
|
1990
|
+
this.shiftActivated = true;
|
|
1991
|
+
}
|
|
1992
|
+
return;
|
|
1993
|
+
}
|
|
1994
|
+
keyShape.fillColor = this.keyColor;
|
|
1995
|
+
if (!this.letterCircle) {
|
|
1996
|
+
throw new Error("letterCircle is not defined");
|
|
1997
|
+
}
|
|
1998
|
+
this.letterCircle.hidden = true;
|
|
1999
|
+
}
|
|
2000
|
+
showKeyboardShifted(keyboard) {
|
|
2001
|
+
const shiftKeyShapes = this.keyShapes.filter(
|
|
2002
|
+
(shape) => shape.userData.code.toLowerCase().includes("shift")
|
|
2003
|
+
);
|
|
2004
|
+
shiftKeyShapes.forEach((shape) => {
|
|
2005
|
+
shape.fillColor = this.specialKeyDownColor;
|
|
2006
|
+
});
|
|
2007
|
+
const shiftKeys = keyboard.flat().filter((k) => k.isShift);
|
|
2008
|
+
shiftKeys.forEach((k) => {
|
|
2009
|
+
if (k.keyIcon) {
|
|
2010
|
+
k.keyIcon.fillColor = WebColors.Black;
|
|
2011
|
+
}
|
|
2012
|
+
});
|
|
2013
|
+
keyboard.flatMap((k) => k).forEach((k) => {
|
|
2014
|
+
const keyLabel = this.keyLabels.find((l) => l.userData.code === k.code);
|
|
2015
|
+
if (!keyLabel) {
|
|
2016
|
+
throw new Error("keyLabel is not defined");
|
|
2017
|
+
}
|
|
2018
|
+
if (keyLabel.text !== void 0) {
|
|
2019
|
+
keyLabel.text = k.labelTextShifted ?? "";
|
|
2020
|
+
}
|
|
2021
|
+
});
|
|
2022
|
+
}
|
|
2023
|
+
showKeyboardNotShifted(keyboard) {
|
|
2024
|
+
const shiftKeyShapes = this.keyShapes.filter(
|
|
2025
|
+
(shape) => shape.userData.code.toLowerCase().includes("shift")
|
|
2026
|
+
);
|
|
2027
|
+
shiftKeyShapes.forEach((shape) => {
|
|
2028
|
+
shape.fillColor = this.keyColor;
|
|
2029
|
+
});
|
|
2030
|
+
const shiftKeys = keyboard.flat().filter((k) => k.isShift);
|
|
2031
|
+
shiftKeys.forEach((k) => {
|
|
2032
|
+
if (k.keyIcon) {
|
|
2033
|
+
k.keyIcon.fillColor = WebColors.Transparent;
|
|
2034
|
+
}
|
|
2035
|
+
});
|
|
2036
|
+
keyboard.flatMap((k) => k).forEach((k) => {
|
|
2037
|
+
const keyLabel = this.keyLabels.find((l) => l.userData.code === k.code);
|
|
2038
|
+
if (!keyLabel) {
|
|
2039
|
+
throw new Error("keyLabel is not defined");
|
|
2040
|
+
}
|
|
2041
|
+
if (keyLabel.text !== void 0) {
|
|
2042
|
+
keyLabel.text = k.labelText ?? "";
|
|
2043
|
+
}
|
|
2044
|
+
});
|
|
2045
|
+
}
|
|
2046
|
+
createDefaultKeyboardRows() {
|
|
2047
|
+
const numKeys = [
|
|
2048
|
+
["1", "!"],
|
|
2049
|
+
["2", "@"],
|
|
2050
|
+
["3", "#"],
|
|
2051
|
+
["4", "$"],
|
|
2052
|
+
["5", "%"],
|
|
2053
|
+
["6", "^"],
|
|
2054
|
+
["7", "&"],
|
|
2055
|
+
["8", "*"],
|
|
2056
|
+
["9", "("],
|
|
2057
|
+
["0", ")"]
|
|
2058
|
+
];
|
|
2059
|
+
const row1 = [
|
|
2060
|
+
"q",
|
|
2061
|
+
"w",
|
|
2062
|
+
"e",
|
|
2063
|
+
"r",
|
|
2064
|
+
"t",
|
|
2065
|
+
"y",
|
|
2066
|
+
"u",
|
|
2067
|
+
"i",
|
|
2068
|
+
"o",
|
|
2069
|
+
"p"
|
|
2070
|
+
];
|
|
2071
|
+
const row2 = [
|
|
2072
|
+
"a",
|
|
2073
|
+
"s",
|
|
2074
|
+
"d",
|
|
2075
|
+
"f",
|
|
2076
|
+
"g",
|
|
2077
|
+
"h",
|
|
2078
|
+
"j",
|
|
2079
|
+
"k",
|
|
2080
|
+
"l"
|
|
2081
|
+
];
|
|
2082
|
+
const shiftArrowShapeOptions = {
|
|
2083
|
+
path: {
|
|
2084
|
+
// Public Domain from https://www.freesvg.org
|
|
2085
|
+
pathString: "m288-6.6849e-14 -288 288h144v288h288v-288h144l-288-288z",
|
|
2086
|
+
width: 24
|
|
2087
|
+
},
|
|
2088
|
+
lineWidth: 2,
|
|
2089
|
+
strokeColor: WebColors.Black,
|
|
2090
|
+
fillColor: WebColors.Transparent,
|
|
2091
|
+
suppressEvents: true
|
|
2092
|
+
};
|
|
2093
|
+
const backspaceShapeOptions = {
|
|
2094
|
+
path: {
|
|
2095
|
+
// CC0 from https://www.svgrepo.com
|
|
2096
|
+
pathString: "M10.625 5.09 0 22.09l10.625 17H44.18v-34H10.625zm31.555 32H11.734l-9.375-15 9.375-15H42.18v30zm-23.293-6.293 7.293-7.293 7.293 7.293 1.414-1.414-7.293-7.293 7.293-7.293-1.414-1.414-7.293 7.293-7.293-7.293-1.414 1.414 7.293 7.293-7.293 7.293",
|
|
2097
|
+
width: 24
|
|
2098
|
+
},
|
|
2099
|
+
lineWidth: 1,
|
|
2100
|
+
strokeColor: WebColors.Black,
|
|
2101
|
+
fillColor: WebColors.Red,
|
|
2102
|
+
suppressEvents: true
|
|
2103
|
+
};
|
|
2104
|
+
const row3 = [
|
|
2105
|
+
{
|
|
2106
|
+
code: "Shift",
|
|
2107
|
+
isShift: true,
|
|
2108
|
+
widthRatio: 1.5,
|
|
2109
|
+
keyIcon: new Shape(shiftArrowShapeOptions)
|
|
2110
|
+
},
|
|
2111
|
+
"z",
|
|
2112
|
+
"x",
|
|
2113
|
+
"c",
|
|
2114
|
+
"v",
|
|
2115
|
+
"b",
|
|
2116
|
+
"n",
|
|
2117
|
+
"m",
|
|
2118
|
+
{
|
|
2119
|
+
code: "Backspace",
|
|
2120
|
+
widthRatio: 1.5,
|
|
2121
|
+
keyIcon: new Shape(backspaceShapeOptions)
|
|
2122
|
+
}
|
|
2123
|
+
];
|
|
2124
|
+
const row4 = [
|
|
2125
|
+
{ code: " ", labelText: "SPACE", widthRatio: 5 }
|
|
2126
|
+
];
|
|
2127
|
+
const keyboardRows = [numKeys, row1, row2, row3, row4];
|
|
2128
|
+
return keyboardRows;
|
|
2129
|
+
}
|
|
2130
|
+
addVirtualKeyboardEventListener(eventListener, options) {
|
|
2131
|
+
if (options?.replaceExisting) {
|
|
2132
|
+
this.eventListeners = this.eventListeners.filter(
|
|
2133
|
+
(listener) => !(listener.nodeUuid === eventListener.nodeUuid && listener.type === eventListener.type && listener.compositeType === eventListener.compositeType)
|
|
2134
|
+
);
|
|
2135
|
+
}
|
|
2136
|
+
this.eventListeners.push(eventListener);
|
|
2137
|
+
}
|
|
2138
|
+
/**
|
|
2139
|
+
* Does the `VirtualKeyboard` respond to user events? Default is true.
|
|
2140
|
+
*/
|
|
2141
|
+
get isUserInteractionEnabled() {
|
|
2142
|
+
return this._isUserInteractionEnabled;
|
|
2143
|
+
}
|
|
2144
|
+
/**
|
|
2145
|
+
* Does the `VirtualKeyboard` respond to user events? Default is true.
|
|
2146
|
+
*/
|
|
2147
|
+
set isUserInteractionEnabled(isUserInteractionEnabled) {
|
|
2148
|
+
this._isUserInteractionEnabled = isUserInteractionEnabled;
|
|
2149
|
+
this.keyShapes?.forEach((keyShape) => {
|
|
2150
|
+
keyShape.isUserInteractionEnabled = isUserInteractionEnabled;
|
|
2151
|
+
});
|
|
1633
2152
|
}
|
|
1634
2153
|
}
|
|
2154
|
+
M2c2KitHelpers.registerM2NodeClass(
|
|
2155
|
+
VirtualKeyboard
|
|
2156
|
+
);
|
|
1635
2157
|
|
|
1636
2158
|
const SCENE_TRANSITION_EASING$1 = Easings.sinusoidalInOut;
|
|
1637
2159
|
const SCENE_TRANSITION_DURATION = 500;
|
|
@@ -1981,7 +2503,469 @@ class CountdownScene extends Scene {
|
|
|
1981
2503
|
}
|
|
1982
2504
|
}
|
|
1983
2505
|
|
|
1984
|
-
|
|
2506
|
+
class LocalePicker extends Composite {
|
|
2507
|
+
/**
|
|
2508
|
+
* An icon and dialog box for selecting a locale from a list of options.
|
|
2509
|
+
*
|
|
2510
|
+
* @remarks This composite node is composed of a dialog box that appears
|
|
2511
|
+
* when the user taps a globe icon. Typically, the `LocalePicker` will be
|
|
2512
|
+
* added as a free node to the game so that it exists independently of
|
|
2513
|
+
* the game's scenes. The dialog box contains a list of locales that the
|
|
2514
|
+
* user can choose from. By default, this list is populated with the locales
|
|
2515
|
+
* in the game's `Translation` object. When the user selects a locale, the
|
|
2516
|
+
* dialog box disappears and the locale is set as the game's current locale.
|
|
2517
|
+
* The dialog box is automatically sized to fit the number of locale
|
|
2518
|
+
* options.
|
|
2519
|
+
*
|
|
2520
|
+
* @example
|
|
2521
|
+
* let localePicker: LocalePicker;
|
|
2522
|
+
* if (game.getParameter<boolean>("show_locale_picker")) {
|
|
2523
|
+
* localePicker = new LocalePicker();
|
|
2524
|
+
* game.addFreeNode(localePicker);
|
|
2525
|
+
* }
|
|
2526
|
+
*
|
|
2527
|
+
* @param options - {@link LocalePickerOptions}
|
|
2528
|
+
*/
|
|
2529
|
+
constructor(options) {
|
|
2530
|
+
super(options);
|
|
2531
|
+
this.compositeType = "LocalePicker";
|
|
2532
|
+
this.DEFAULT_FONT_SIZE = 24;
|
|
2533
|
+
this.automaticallyChangeLocale = true;
|
|
2534
|
+
this._localeOptions = new Array();
|
|
2535
|
+
this._backgroundColor = WebColors.White;
|
|
2536
|
+
this._fontSize = this.DEFAULT_FONT_SIZE;
|
|
2537
|
+
this._fontColor = WebColors.Black;
|
|
2538
|
+
this._cornerRadius = 8;
|
|
2539
|
+
this._overlayAlpha = 0.5;
|
|
2540
|
+
this._icon = {
|
|
2541
|
+
// public domain SVG from https://commons.wikimedia.org/wiki/File:Globe_icon.svg
|
|
2542
|
+
svgString: `<svg xmlns="http://www.w3.org/2000/svg" width="420" height="420" stroke="#000" fill="none"><path stroke-width="26" d="M209 15a195 195 0 1 0 2 0z"/><path stroke-width="18" d="M210 15v390m195-195H15M59 90a260 260 0 0 0 302 0m0 240a260 260 0 0 0-302 0M195 20a250 250 0 0 0 0 382m30 0a250 250 0 0 0 0-382"/></svg>`,
|
|
2543
|
+
height: 32,
|
|
2544
|
+
width: 32
|
|
2545
|
+
};
|
|
2546
|
+
this._iconPosition = { x: 32, y: 32 };
|
|
2547
|
+
/**
|
|
2548
|
+
* Wrap displayed locale in double angle quotes if it is the current locale.
|
|
2549
|
+
* Note: Although the code editor will allow us to enter almost any
|
|
2550
|
+
* unicode character, it will not render correctly if the font does
|
|
2551
|
+
* not support the character. Thus, be careful to use characters that
|
|
2552
|
+
* are supported by the font. For example, check a page like
|
|
2553
|
+
* https://www.fontspace.com/roboto-font-f13281 to see which characters
|
|
2554
|
+
* are supported by Roboto Regular, which is often the default font in
|
|
2555
|
+
* m2c2kit. Emoji or checkmarks like ✓ are not in Roboto Regular!
|
|
2556
|
+
*/
|
|
2557
|
+
this.LEFT_SELECTION_INDICATOR = "\xAB";
|
|
2558
|
+
this.RIGHT_SELECTION_INDICATOR = "\xBB";
|
|
2559
|
+
this.zPosition = Number.MAX_VALUE;
|
|
2560
|
+
if (!options) {
|
|
2561
|
+
return;
|
|
2562
|
+
}
|
|
2563
|
+
if (options.localeOptions) {
|
|
2564
|
+
this.localeOptions = options.localeOptions;
|
|
2565
|
+
}
|
|
2566
|
+
if (options.backgroundColor) {
|
|
2567
|
+
this.backgroundColor = options.backgroundColor;
|
|
2568
|
+
}
|
|
2569
|
+
if (options.overlayAlpha !== void 0) {
|
|
2570
|
+
this.overlayAlpha = options.overlayAlpha;
|
|
2571
|
+
}
|
|
2572
|
+
if (options.fontSize !== void 0) {
|
|
2573
|
+
this.fontSize = options.fontSize;
|
|
2574
|
+
}
|
|
2575
|
+
if (options.fontColor) {
|
|
2576
|
+
this.fontColor = options.fontColor;
|
|
2577
|
+
}
|
|
2578
|
+
if (options.cornerRadius) {
|
|
2579
|
+
this.cornerRadius = options.cornerRadius;
|
|
2580
|
+
}
|
|
2581
|
+
if (options.currentLocale !== void 0) {
|
|
2582
|
+
this.currentLocale = options.currentLocale;
|
|
2583
|
+
}
|
|
2584
|
+
if (options.icon) {
|
|
2585
|
+
this.icon = options.icon;
|
|
2586
|
+
}
|
|
2587
|
+
if (options.automaticallyChangeLocale !== void 0) {
|
|
2588
|
+
this.automaticallyChangeLocale = options.automaticallyChangeLocale;
|
|
2589
|
+
}
|
|
2590
|
+
}
|
|
2591
|
+
/**
|
|
2592
|
+
* Executes a callback when the user selects a locale.
|
|
2593
|
+
*
|
|
2594
|
+
* @param callback - function to execute
|
|
2595
|
+
* @param options - {@link CallbackOptions}
|
|
2596
|
+
*/
|
|
2597
|
+
onResult(callback, options) {
|
|
2598
|
+
const eventListener = {
|
|
2599
|
+
type: M2EventType.Composite,
|
|
2600
|
+
compositeType: "LocalePickerResult",
|
|
2601
|
+
nodeUuid: this.uuid,
|
|
2602
|
+
callback
|
|
2603
|
+
};
|
|
2604
|
+
if (options?.replaceExisting) {
|
|
2605
|
+
this.eventListeners = this.eventListeners.filter(
|
|
2606
|
+
(listener) => !(listener.nodeUuid === eventListener.nodeUuid && listener.type === "LocalePickerResult")
|
|
2607
|
+
);
|
|
2608
|
+
}
|
|
2609
|
+
this.eventListeners.push(eventListener);
|
|
2610
|
+
}
|
|
2611
|
+
initialize() {
|
|
2612
|
+
if (this.currentLocale === void 0) {
|
|
2613
|
+
this.currentLocale = this.game.i18n?.locale;
|
|
2614
|
+
}
|
|
2615
|
+
if (this.localeOptions.length === 0) {
|
|
2616
|
+
const locales = Object.keys(this.game.i18n?.translation || {});
|
|
2617
|
+
locales.filter((locale) => locale !== "configuration").forEach((locale) => {
|
|
2618
|
+
this.localeOptions.push({
|
|
2619
|
+
text: this.game.i18n?.translation[locale].localeName || locale,
|
|
2620
|
+
locale,
|
|
2621
|
+
svg: this.game.i18n?.translation[locale].localeSvg
|
|
2622
|
+
});
|
|
2623
|
+
});
|
|
2624
|
+
}
|
|
2625
|
+
if (this.localeOptions.length === 0) {
|
|
2626
|
+
throw new Error("No locales available for LocalePicker");
|
|
2627
|
+
}
|
|
2628
|
+
this.children.filter((child) => child.name !== "localePickerIcon").forEach((child) => this.removeChild(child));
|
|
2629
|
+
this.game.imageManager.loadImages([
|
|
2630
|
+
{
|
|
2631
|
+
imageName: "__localePickerIcon",
|
|
2632
|
+
svgString: this.icon.svgString,
|
|
2633
|
+
height: this.icon.height,
|
|
2634
|
+
width: this.icon.width
|
|
2635
|
+
}
|
|
2636
|
+
]);
|
|
2637
|
+
if (!this.iconSprite) {
|
|
2638
|
+
this.iconSprite = new Sprite({
|
|
2639
|
+
// name is how we refer to this sprite, as a node.
|
|
2640
|
+
name: "localePickerIcon",
|
|
2641
|
+
// imageName is the loaded image that we can assign to the sprite
|
|
2642
|
+
imageName: "__localePickerIcon",
|
|
2643
|
+
position: this.iconPosition,
|
|
2644
|
+
isUserInteractionEnabled: true
|
|
2645
|
+
});
|
|
2646
|
+
this.addChild(this.iconSprite);
|
|
2647
|
+
this.iconSprite.onTapDown(() => {
|
|
2648
|
+
this.setDialogVisibility(true);
|
|
2649
|
+
});
|
|
2650
|
+
}
|
|
2651
|
+
const overlay = new Shape({
|
|
2652
|
+
rect: {
|
|
2653
|
+
width: m2c2Globals.canvasCssWidth,
|
|
2654
|
+
height: m2c2Globals.canvasCssHeight,
|
|
2655
|
+
x: m2c2Globals.canvasCssWidth / 2,
|
|
2656
|
+
y: m2c2Globals.canvasCssHeight / 2
|
|
2657
|
+
},
|
|
2658
|
+
fillColor: [0, 0, 0, this.overlayAlpha],
|
|
2659
|
+
zPosition: -1,
|
|
2660
|
+
isUserInteractionEnabled: true,
|
|
2661
|
+
hidden: true
|
|
2662
|
+
});
|
|
2663
|
+
overlay.onTapDown((e) => {
|
|
2664
|
+
e.handled = true;
|
|
2665
|
+
if (this.eventListeners.length > 0) {
|
|
2666
|
+
this.eventListeners.filter((listener) => listener.type === "LocalePickerResult").forEach((listener) => {
|
|
2667
|
+
const languagePickerEvent = {
|
|
2668
|
+
type: M2EventType.Composite,
|
|
2669
|
+
compositeType: this.compositeType,
|
|
2670
|
+
compositeEventType: "LocalePickerResult",
|
|
2671
|
+
target: this,
|
|
2672
|
+
handled: false,
|
|
2673
|
+
result: {
|
|
2674
|
+
locale: void 0
|
|
2675
|
+
},
|
|
2676
|
+
timestamp: Timer.now(),
|
|
2677
|
+
iso8601Timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
2678
|
+
};
|
|
2679
|
+
listener.callback(languagePickerEvent);
|
|
2680
|
+
});
|
|
2681
|
+
}
|
|
2682
|
+
this.setDialogVisibility(false);
|
|
2683
|
+
});
|
|
2684
|
+
this.addChild(overlay);
|
|
2685
|
+
const lineHeight = this.fontSize / this.DEFAULT_FONT_SIZE * 50;
|
|
2686
|
+
const dialogHeight = this.localeOptions.length * lineHeight;
|
|
2687
|
+
const dialogWidth = m2c2Globals.canvasCssWidth / 2;
|
|
2688
|
+
const sceneCenter = {
|
|
2689
|
+
x: m2c2Globals.canvasCssWidth / 2,
|
|
2690
|
+
y: m2c2Globals.canvasCssHeight / 2
|
|
2691
|
+
};
|
|
2692
|
+
const localeDialog = new Shape({
|
|
2693
|
+
rect: {
|
|
2694
|
+
width: dialogWidth,
|
|
2695
|
+
height: dialogHeight,
|
|
2696
|
+
x: sceneCenter.x,
|
|
2697
|
+
y: sceneCenter.y
|
|
2698
|
+
},
|
|
2699
|
+
cornerRadius: this.cornerRadius,
|
|
2700
|
+
fillColor: this.backgroundColor,
|
|
2701
|
+
isUserInteractionEnabled: true,
|
|
2702
|
+
hidden: true
|
|
2703
|
+
});
|
|
2704
|
+
localeDialog.onTapDown((e) => {
|
|
2705
|
+
e.handled = true;
|
|
2706
|
+
});
|
|
2707
|
+
this.addChild(localeDialog);
|
|
2708
|
+
for (let i = 0; i < this.localeOptions.length; i++) {
|
|
2709
|
+
const localeOption = this.localeOptions[i];
|
|
2710
|
+
if (!localeOption.svg) {
|
|
2711
|
+
let labelText = localeOption.text;
|
|
2712
|
+
if (this.currentLocale === localeOption.locale) {
|
|
2713
|
+
labelText = `${this.LEFT_SELECTION_INDICATOR} ${labelText} ${this.RIGHT_SELECTION_INDICATOR}`;
|
|
2714
|
+
}
|
|
2715
|
+
const text = new Label({
|
|
2716
|
+
text: labelText,
|
|
2717
|
+
fontSize: this.fontSize,
|
|
2718
|
+
fontColor: this.fontColor,
|
|
2719
|
+
position: {
|
|
2720
|
+
x: sceneCenter.x,
|
|
2721
|
+
y: sceneCenter.y + i * lineHeight - dialogHeight / 2 + lineHeight / 2
|
|
2722
|
+
},
|
|
2723
|
+
isUserInteractionEnabled: true,
|
|
2724
|
+
zPosition: 1,
|
|
2725
|
+
hidden: true,
|
|
2726
|
+
// do not localize the text of each language option
|
|
2727
|
+
localize: false
|
|
2728
|
+
});
|
|
2729
|
+
text.onTapDown((e) => {
|
|
2730
|
+
this.handleLocaleSelection(e, localeOption);
|
|
2731
|
+
});
|
|
2732
|
+
this.addChild(text);
|
|
2733
|
+
} else {
|
|
2734
|
+
this.game.imageManager.loadImages([
|
|
2735
|
+
{
|
|
2736
|
+
imageName: localeOption.text,
|
|
2737
|
+
svgString: localeOption.svg.svgString,
|
|
2738
|
+
height: localeOption.svg.height,
|
|
2739
|
+
width: localeOption.svg.width
|
|
2740
|
+
}
|
|
2741
|
+
]);
|
|
2742
|
+
const localeSprite = new Sprite({
|
|
2743
|
+
imageName: localeOption.text,
|
|
2744
|
+
position: {
|
|
2745
|
+
x: sceneCenter.x,
|
|
2746
|
+
y: sceneCenter.y + i * lineHeight - dialogHeight / 2 + lineHeight / 2
|
|
2747
|
+
},
|
|
2748
|
+
isUserInteractionEnabled: true,
|
|
2749
|
+
zPosition: 1,
|
|
2750
|
+
hidden: true
|
|
2751
|
+
});
|
|
2752
|
+
this.addChild(localeSprite);
|
|
2753
|
+
if (this.currentLocale === localeOption.locale) {
|
|
2754
|
+
const leftSelectionIndicator = new Label({
|
|
2755
|
+
text: this.LEFT_SELECTION_INDICATOR,
|
|
2756
|
+
fontSize: this.fontSize,
|
|
2757
|
+
fontColor: this.fontColor,
|
|
2758
|
+
position: {
|
|
2759
|
+
x: sceneCenter.x - localeOption.svg.width / 2,
|
|
2760
|
+
y: sceneCenter.y + i * lineHeight - dialogHeight / 2 + lineHeight / 2
|
|
2761
|
+
},
|
|
2762
|
+
hidden: true,
|
|
2763
|
+
// do not localize the left selection indicator
|
|
2764
|
+
localize: false
|
|
2765
|
+
});
|
|
2766
|
+
this.addChild(leftSelectionIndicator);
|
|
2767
|
+
const rightSelectionIndicator = new Label({
|
|
2768
|
+
text: this.RIGHT_SELECTION_INDICATOR,
|
|
2769
|
+
fontSize: this._fontSize,
|
|
2770
|
+
fontColor: this.fontColor,
|
|
2771
|
+
position: {
|
|
2772
|
+
x: sceneCenter.x + localeOption.svg.width / 2,
|
|
2773
|
+
y: sceneCenter.y + i * lineHeight - dialogHeight / 2 + lineHeight / 2
|
|
2774
|
+
},
|
|
2775
|
+
hidden: true,
|
|
2776
|
+
// do not localize the left selection indicator
|
|
2777
|
+
localize: false
|
|
2778
|
+
});
|
|
2779
|
+
this.addChild(rightSelectionIndicator);
|
|
2780
|
+
}
|
|
2781
|
+
localeSprite.onTapDown((e) => {
|
|
2782
|
+
this.handleLocaleSelection(e, localeOption);
|
|
2783
|
+
});
|
|
2784
|
+
}
|
|
2785
|
+
}
|
|
2786
|
+
this.needsInitialization = false;
|
|
2787
|
+
}
|
|
2788
|
+
handleLocaleSelection(e, localeOption) {
|
|
2789
|
+
e.handled = true;
|
|
2790
|
+
if (this.eventListeners.length > 0) {
|
|
2791
|
+
this.eventListeners.filter(
|
|
2792
|
+
(listener) => listener.type === M2EventType.Composite && listener.compositeType === "LocalePickerResult" && listener.nodeUuid == this.uuid
|
|
2793
|
+
).forEach((listener) => {
|
|
2794
|
+
const languagePickerEvent = {
|
|
2795
|
+
type: M2EventType.Composite,
|
|
2796
|
+
compositeType: this.compositeType,
|
|
2797
|
+
compositeEventType: "LocalePickerResult",
|
|
2798
|
+
target: this,
|
|
2799
|
+
handled: false,
|
|
2800
|
+
result: {
|
|
2801
|
+
locale: localeOption.locale
|
|
2802
|
+
},
|
|
2803
|
+
timestamp: Timer.now(),
|
|
2804
|
+
iso8601Timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
2805
|
+
};
|
|
2806
|
+
listener.callback(languagePickerEvent);
|
|
2807
|
+
});
|
|
2808
|
+
}
|
|
2809
|
+
this.setDialogVisibility(false);
|
|
2810
|
+
if (this.automaticallyChangeLocale) {
|
|
2811
|
+
this.game.i18n?.switchToLocale(localeOption.locale);
|
|
2812
|
+
this.currentLocale = localeOption.locale;
|
|
2813
|
+
}
|
|
2814
|
+
}
|
|
2815
|
+
setDialogVisibility(visible) {
|
|
2816
|
+
this.children.filter((child) => child.name !== "localePickerIcon").forEach((child) => {
|
|
2817
|
+
child.hidden = !visible;
|
|
2818
|
+
});
|
|
2819
|
+
}
|
|
2820
|
+
get backgroundColor() {
|
|
2821
|
+
return this._backgroundColor;
|
|
2822
|
+
}
|
|
2823
|
+
set backgroundColor(backgroundColor) {
|
|
2824
|
+
this._backgroundColor = backgroundColor;
|
|
2825
|
+
this.needsInitialization = true;
|
|
2826
|
+
}
|
|
2827
|
+
get fontSize() {
|
|
2828
|
+
return this._fontSize;
|
|
2829
|
+
}
|
|
2830
|
+
set fontSize(fontSize) {
|
|
2831
|
+
this._fontSize = fontSize;
|
|
2832
|
+
this.needsInitialization = true;
|
|
2833
|
+
}
|
|
2834
|
+
get fontColor() {
|
|
2835
|
+
return this._fontColor;
|
|
2836
|
+
}
|
|
2837
|
+
set fontColor(fontColor) {
|
|
2838
|
+
this._fontColor = fontColor;
|
|
2839
|
+
this.needsInitialization = true;
|
|
2840
|
+
}
|
|
2841
|
+
get cornerRadius() {
|
|
2842
|
+
return this._cornerRadius;
|
|
2843
|
+
}
|
|
2844
|
+
set cornerRadius(cornerRadius) {
|
|
2845
|
+
this._cornerRadius = cornerRadius;
|
|
2846
|
+
this.needsInitialization = true;
|
|
2847
|
+
}
|
|
2848
|
+
get overlayAlpha() {
|
|
2849
|
+
return this._overlayAlpha;
|
|
2850
|
+
}
|
|
2851
|
+
set overlayAlpha(alpha) {
|
|
2852
|
+
this._overlayAlpha = alpha;
|
|
2853
|
+
this.needsInitialization = true;
|
|
2854
|
+
}
|
|
2855
|
+
get icon() {
|
|
2856
|
+
const localePicker = this;
|
|
2857
|
+
return {
|
|
2858
|
+
get svgString() {
|
|
2859
|
+
return localePicker._icon.svgString;
|
|
2860
|
+
},
|
|
2861
|
+
set svgString(svgString) {
|
|
2862
|
+
localePicker._icon.svgString = svgString;
|
|
2863
|
+
localePicker.needsInitialization = true;
|
|
2864
|
+
},
|
|
2865
|
+
get imageName() {
|
|
2866
|
+
return localePicker._icon.imageName;
|
|
2867
|
+
},
|
|
2868
|
+
set imageName(imageName) {
|
|
2869
|
+
localePicker._icon.imageName = imageName;
|
|
2870
|
+
localePicker.needsInitialization = true;
|
|
2871
|
+
},
|
|
2872
|
+
get height() {
|
|
2873
|
+
return localePicker._icon.height;
|
|
2874
|
+
},
|
|
2875
|
+
set height(height) {
|
|
2876
|
+
localePicker._icon.height = height;
|
|
2877
|
+
localePicker.needsInitialization = true;
|
|
2878
|
+
},
|
|
2879
|
+
get width() {
|
|
2880
|
+
return localePicker._icon.width;
|
|
2881
|
+
},
|
|
2882
|
+
set width(width) {
|
|
2883
|
+
localePicker._icon.width = width;
|
|
2884
|
+
localePicker.needsInitialization = true;
|
|
2885
|
+
}
|
|
2886
|
+
};
|
|
2887
|
+
}
|
|
2888
|
+
set icon(icon) {
|
|
2889
|
+
this._icon = icon;
|
|
2890
|
+
this.needsInitialization = true;
|
|
2891
|
+
}
|
|
2892
|
+
get iconPosition() {
|
|
2893
|
+
const localePicker = this;
|
|
2894
|
+
return {
|
|
2895
|
+
get x() {
|
|
2896
|
+
return localePicker._iconPosition.x;
|
|
2897
|
+
},
|
|
2898
|
+
set x(x) {
|
|
2899
|
+
localePicker._iconPosition.x = x;
|
|
2900
|
+
if (localePicker.iconSprite) {
|
|
2901
|
+
localePicker.iconSprite.position = localePicker._iconPosition;
|
|
2902
|
+
}
|
|
2903
|
+
localePicker.needsInitialization = true;
|
|
2904
|
+
},
|
|
2905
|
+
get y() {
|
|
2906
|
+
return localePicker._iconPosition.y;
|
|
2907
|
+
},
|
|
2908
|
+
set y(y) {
|
|
2909
|
+
localePicker._iconPosition.y = y;
|
|
2910
|
+
if (localePicker.iconSprite) {
|
|
2911
|
+
localePicker.iconSprite.position = localePicker._iconPosition;
|
|
2912
|
+
}
|
|
2913
|
+
localePicker.needsInitialization = true;
|
|
2914
|
+
}
|
|
2915
|
+
};
|
|
2916
|
+
}
|
|
2917
|
+
set iconPosition(position) {
|
|
2918
|
+
this._iconPosition = position;
|
|
2919
|
+
if (this.iconSprite) {
|
|
2920
|
+
this.iconSprite.position = position;
|
|
2921
|
+
}
|
|
2922
|
+
this.needsInitialization = true;
|
|
2923
|
+
}
|
|
2924
|
+
get localeOptions() {
|
|
2925
|
+
return this._localeOptions;
|
|
2926
|
+
}
|
|
2927
|
+
set localeOptions(options) {
|
|
2928
|
+
this._localeOptions = options;
|
|
2929
|
+
this.needsInitialization = true;
|
|
2930
|
+
}
|
|
2931
|
+
get currentLocale() {
|
|
2932
|
+
return this._currentLocale;
|
|
2933
|
+
}
|
|
2934
|
+
set currentLocale(locale) {
|
|
2935
|
+
if (locale === this.currentLocale) {
|
|
2936
|
+
return;
|
|
2937
|
+
}
|
|
2938
|
+
this._currentLocale = locale;
|
|
2939
|
+
this.needsInitialization = true;
|
|
2940
|
+
}
|
|
2941
|
+
update() {
|
|
2942
|
+
super.update();
|
|
2943
|
+
}
|
|
2944
|
+
draw(canvas) {
|
|
2945
|
+
super.drawChildren(canvas);
|
|
2946
|
+
}
|
|
2947
|
+
warmup(canvas) {
|
|
2948
|
+
this.initialize();
|
|
2949
|
+
this.children.filter((child) => child.isDrawable).forEach((child) => {
|
|
2950
|
+
child.warmup(canvas);
|
|
2951
|
+
});
|
|
2952
|
+
}
|
|
2953
|
+
/**
|
|
2954
|
+
* Duplicates a node using deep copy.
|
|
2955
|
+
*
|
|
2956
|
+
* @remarks This is a deep recursive clone (node and children).
|
|
2957
|
+
* The uuid property of all duplicated nodes will be newly created,
|
|
2958
|
+
* because uuid must be unique.
|
|
2959
|
+
*
|
|
2960
|
+
* @param newName - optional name of the new, duplicated node. If not
|
|
2961
|
+
* provided, name will be the new uuid
|
|
2962
|
+
*/
|
|
2963
|
+
duplicate(newName) {
|
|
2964
|
+
throw new Error(`duplicate not implemented. ${newName}`);
|
|
2965
|
+
}
|
|
2966
|
+
}
|
|
2967
|
+
|
|
2968
|
+
console.log("\u26AA @m2c2kit/addons version 0.3.16 (0679492d)");
|
|
1985
2969
|
|
|
1986
|
-
export { Button, CountdownScene, Dialog, DialogResult, DrawPad, DrawPadEventType, DrawPadItemEventType, Grid, Instructions, VirtualKeyboard };
|
|
2970
|
+
export { Button, CountdownScene, Dialog, DialogResult, DrawPad, DrawPadEventType, DrawPadItemEventType, Grid, Instructions, LocalePicker, VirtualKeyboard };
|
|
1987
2971
|
//# sourceMappingURL=index.js.map
|