@m2c2kit/addons 0.3.15 → 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.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 = "grid";
16
+ this.compositeType = "Grid";
17
17
  // Grid options
18
- // TODO: make getter, setter for these so they can be changed after initial construction
19
- this.rows = 0;
20
- this.columns = 0;
21
- // default Grid is: transparent gray, red lines, line width 1
22
- this.gridBackgroundColor = [0, 0, 233, 0.25];
23
- this.gridLineColor = WebColors.Red;
24
- this.gridLineWidth = 1;
25
- this.gridChildren = new Array();
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
- super.removeAllChildren();
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: "_" + this.name + "-gridBackground",
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
- this.addChild(this.gridBackground);
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: "_" + this.name + "-gridVerticalLine-" + col,
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: "_" + this.name + "-gridHorizontalLine-" + row,
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
- if (this.gridChildren) {
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
- const x = -this.size.width / 2 + this.cellWidth / 2 + gridChild.column * this.cellWidth;
104
- const y = -this.size.height / 2 + this.cellHeight / 2 + gridChild.row * this.cellHeight;
105
- gridChild.node.position = {
106
- x: x + gridChild.node.position.x,
107
- y: y + gridChild.node.position.y
108
- };
109
- this.gridBackground.addChild(gridChild.node);
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
- * Removes all children from the grid, but retains grid lines.
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
- removeAllChildren() {
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
- const gridChild = this.gridChildren.pop();
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 position.
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.push({ node, row, column });
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
- removeChild(node) {
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
- // todo: add getters/setters so button can respond to changes in its options
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,12 +407,12 @@ class Button extends Composite {
252
407
  */
253
408
  constructor(options) {
254
409
  super(options);
255
- this.compositeType = "button";
410
+ this.compositeType = "Button";
411
+ this.isText = true;
256
412
  // Button options
257
413
  this._backgroundColor = WebColors.Black;
258
- this.size = { width: 200, height: 50 };
259
- this.cornerRadius = 9;
260
- this.fontSize = 20;
414
+ this._cornerRadius = 9;
415
+ this._fontSize = 20;
261
416
  this._text = "";
262
417
  this._fontColor = WebColors.White;
263
418
  this._interpolation = {};
@@ -267,6 +422,8 @@ class Button extends Composite {
267
422
  }
268
423
  if (options.size) {
269
424
  this.size = options.size;
425
+ } else {
426
+ this.size = { width: 200, height: 50 };
270
427
  }
271
428
  if (options.cornerRadius !== void 0) {
272
429
  this.cornerRadius = options.cornerRadius;
@@ -292,6 +449,19 @@ class Button extends Composite {
292
449
  if (options.localize !== void 0) {
293
450
  this.localize = options.localize;
294
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
+ };
295
465
  }
296
466
  initialize() {
297
467
  this.removeAllChildren();
@@ -306,19 +476,23 @@ class Button extends Composite {
306
476
  );
307
477
  this.backgroundPaint.setStyle(this.canvasKit.PaintStyle.Fill);
308
478
  const buttonRectangle = new Shape({
479
+ name: "__" + this.name + "-buttonRectangle",
309
480
  rect: { size: this.size },
310
481
  cornerRadius: this.cornerRadius,
311
- fillColor: this._backgroundColor
482
+ fillColor: this._backgroundColor,
483
+ suppressEvents: true
312
484
  });
313
485
  this.addChild(buttonRectangle);
314
486
  const buttonLabel = new Label({
487
+ name: "__" + this.name + "-buttonLabel",
315
488
  text: this.text,
316
489
  localize: this.localize,
317
490
  interpolation: this.interpolation,
318
491
  fontName: this.fontName,
319
492
  fontNames: this.fontNames,
320
493
  fontSize: this.fontSize,
321
- fontColor: this.fontColor
494
+ fontColor: this.fontColor,
495
+ suppressEvents: true
322
496
  });
323
497
  buttonRectangle.addChild(buttonLabel);
324
498
  this.needsInitialization = false;
@@ -330,51 +504,101 @@ class Button extends Composite {
330
504
  return this._text;
331
505
  }
332
506
  set text(text) {
507
+ if (Equal.value(this._text, text)) {
508
+ return;
509
+ }
333
510
  this._text = text;
334
511
  this.needsInitialization = true;
512
+ this.savePropertyChangeEvent("text", text);
335
513
  }
336
514
  get backgroundColor() {
337
515
  return this._backgroundColor;
338
516
  }
339
517
  set backgroundColor(backgroundColor) {
518
+ if (Equal.value(this._backgroundColor, backgroundColor)) {
519
+ return;
520
+ }
340
521
  this._backgroundColor = backgroundColor;
341
522
  this.needsInitialization = true;
523
+ this.savePropertyChangeEvent("backgroundColor", backgroundColor);
342
524
  }
343
525
  get fontColor() {
344
526
  return this._fontColor;
345
527
  }
346
528
  set fontColor(fontColor) {
529
+ if (Equal.value(this._fontColor, fontColor)) {
530
+ return;
531
+ }
347
532
  this._fontColor = fontColor;
348
533
  this.needsInitialization = true;
534
+ this.savePropertyChangeEvent("fontColor", fontColor);
349
535
  }
350
536
  get fontName() {
351
537
  return this._fontName;
352
538
  }
353
539
  set fontName(fontName) {
540
+ if (this._fontName === fontName) {
541
+ return;
542
+ }
354
543
  this._fontName = fontName;
355
544
  this.needsInitialization = true;
545
+ this.savePropertyChangeEvent("fontName", fontName);
356
546
  }
357
547
  get fontNames() {
358
548
  return this._fontNames;
359
549
  }
360
550
  set fontNames(fontNames) {
551
+ if (Equal.value(this._fontNames, fontNames)) {
552
+ return;
553
+ }
361
554
  this._fontNames = fontNames;
362
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);
363
579
  }
364
580
  get interpolation() {
365
581
  return this._interpolation;
366
582
  }
367
583
  set interpolation(interpolation) {
584
+ if (Equal.value(this._interpolation, interpolation)) {
585
+ return;
586
+ }
368
587
  this._interpolation = interpolation;
369
588
  Object.freeze(this._interpolation);
370
589
  this.needsInitialization = true;
590
+ this.savePropertyChangeEvent("interpolation", interpolation);
371
591
  }
372
592
  get localize() {
373
593
  return this._localize;
374
594
  }
375
595
  set localize(localize) {
596
+ if (Equal.value(this._localize, localize)) {
597
+ return;
598
+ }
376
599
  this._localize = localize;
377
600
  this.needsInitialization = true;
601
+ this.savePropertyChangeEvent("localize", localize);
378
602
  }
379
603
  /**
380
604
  * Duplicates a node using deep copy.
@@ -423,6 +647,7 @@ class Button extends Composite {
423
647
  });
424
648
  }
425
649
  }
650
+ M2c2KitHelpers.registerM2NodeClass(Button);
426
651
 
427
652
  var DialogResult = /* @__PURE__ */ ((DialogResult2) => {
428
653
  DialogResult2["Dismiss"] = "Dismiss";
@@ -442,9 +667,9 @@ class Dialog extends Composite {
442
667
  this.contentText = "";
443
668
  this.positiveButtonText = "";
444
669
  this.negativeButtonText = "";
670
+ this._fontColor = WebColors.White;
445
671
  this.zPosition = Number.MAX_VALUE;
446
672
  this.hidden = true;
447
- this._fontColor = WebColors.White;
448
673
  if (!options) {
449
674
  return;
450
675
  }
@@ -478,7 +703,7 @@ class Dialog extends Composite {
478
703
  }
479
704
  onDialogResult(callback, options) {
480
705
  const eventListener = {
481
- type: M2EventType.CompositeCustom,
706
+ type: M2EventType.Composite,
482
707
  compositeType: "DialogResult",
483
708
  nodeUuid: this.uuid,
484
709
  callback
@@ -494,10 +719,10 @@ class Dialog extends Composite {
494
719
  this.removeAllChildren();
495
720
  const overlay = new Shape({
496
721
  rect: {
497
- width: Globals.canvasCssWidth,
498
- height: Globals.canvasCssHeight,
499
- x: Globals.canvasCssWidth / 2,
500
- y: Globals.canvasCssHeight / 2
722
+ width: m2c2Globals.canvasCssWidth,
723
+ height: m2c2Globals.canvasCssHeight,
724
+ x: m2c2Globals.canvasCssWidth / 2,
725
+ y: m2c2Globals.canvasCssHeight / 2
501
726
  },
502
727
  fillColor: [0, 0, 0, this.overlayAlpha],
503
728
  zPosition: -1,
@@ -507,12 +732,14 @@ class Dialog extends Composite {
507
732
  e.handled = true;
508
733
  this.hidden = true;
509
734
  if (this.eventListeners.length > 0) {
510
- this.eventListeners.filter((listener) => listener.type === M2EventType.CompositeCustom).forEach((listener) => {
735
+ this.eventListeners.filter((listener) => listener.type === M2EventType.Composite).forEach((listener) => {
511
736
  const dialogEvent = {
512
- type: M2EventType.CompositeCustom,
737
+ type: M2EventType.Composite,
513
738
  target: this,
514
739
  handled: false,
515
- dialogResult: "Dismiss" /* Dismiss */
740
+ dialogResult: "Dismiss" /* Dismiss */,
741
+ timestamp: Timer.now(),
742
+ iso8601Timestamp: (/* @__PURE__ */ new Date()).toISOString()
516
743
  };
517
744
  listener.callback(dialogEvent);
518
745
  });
@@ -523,8 +750,8 @@ class Dialog extends Composite {
523
750
  rect: {
524
751
  width: 300,
525
752
  height: 150,
526
- x: Globals.canvasCssWidth / 2,
527
- y: Globals.canvasCssHeight / 2
753
+ x: m2c2Globals.canvasCssWidth / 2,
754
+ y: m2c2Globals.canvasCssHeight / 2
528
755
  },
529
756
  cornerRadius: this.cornerRadius,
530
757
  fillColor: this.backgroundColor,
@@ -555,12 +782,14 @@ class Dialog extends Composite {
555
782
  e.handled = true;
556
783
  this.hidden = true;
557
784
  if (this.eventListeners.length > 0) {
558
- this.eventListeners.filter((listener) => listener.type === M2EventType.CompositeCustom).forEach((listener) => {
785
+ this.eventListeners.filter((listener) => listener.type === M2EventType.Composite).forEach((listener) => {
559
786
  const dialogEvent = {
560
- type: M2EventType.CompositeCustom,
787
+ type: M2EventType.Composite,
561
788
  target: this,
562
789
  handled: false,
563
- dialogResult: "Negative" /* Negative */
790
+ dialogResult: "Negative" /* Negative */,
791
+ timestamp: Timer.now(),
792
+ iso8601Timestamp: (/* @__PURE__ */ new Date()).toISOString()
564
793
  };
565
794
  listener.callback(dialogEvent);
566
795
  });
@@ -577,12 +806,14 @@ class Dialog extends Composite {
577
806
  e.handled = true;
578
807
  this.hidden = true;
579
808
  if (this.eventListeners.length > 0) {
580
- this.eventListeners.filter((listener) => listener.type === M2EventType.CompositeCustom).forEach((listener) => {
809
+ this.eventListeners.filter((listener) => listener.type === M2EventType.Composite).forEach((listener) => {
581
810
  const dialogEvent = {
582
- type: M2EventType.CompositeCustom,
811
+ type: M2EventType.Composite,
583
812
  target: this,
584
813
  handled: false,
585
- dialogResult: "Positive" /* Positive */
814
+ dialogResult: "Positive" /* Positive */,
815
+ timestamp: Timer.now(),
816
+ iso8601Timestamp: (/* @__PURE__ */ new Date()).toISOString()
586
817
  };
587
818
  listener.callback(dialogEvent);
588
819
  });
@@ -606,6 +837,13 @@ class Dialog extends Composite {
606
837
  this._fontColor = fontColor;
607
838
  this.needsInitialization = true;
608
839
  }
840
+ get hidden() {
841
+ return this._hidden;
842
+ }
843
+ set hidden(hidden) {
844
+ this._hidden = hidden;
845
+ this.needsInitialization;
846
+ }
609
847
  /**
610
848
  * Duplicates a node using deep copy.
611
849
  *
@@ -617,7 +855,7 @@ class Dialog extends Composite {
617
855
  * provided, name will be the new uuid
618
856
  */
619
857
  duplicate(newName) {
620
- throw new Error("duplicate not implemented");
858
+ throw new Error(`duplicate not implemented. ${newName}`);
621
859
  }
622
860
  update() {
623
861
  super.update();
@@ -668,6 +906,7 @@ class DrawPad extends Composite {
668
906
  * of all interactions with each DrawPadStroke.
669
907
  */
670
908
  this.strokes = new Array();
909
+ this.originalOptions = JSON.parse(JSON.stringify(options));
671
910
  if (options.isUserInteractionEnabled === void 0) {
672
911
  this.isUserInteractionEnabled = true;
673
912
  }
@@ -699,6 +938,15 @@ class DrawPad extends Composite {
699
938
  if (options.continuousDrawingOnlyExceptionDistance !== void 0) {
700
939
  this.continuousDrawingOnlyExceptionDistance = options.continuousDrawingOnlyExceptionDistance;
701
940
  }
941
+ this.saveNodeNewEvent();
942
+ }
943
+ get completeNodeOptions() {
944
+ return {
945
+ ...this.options,
946
+ ...this.getNodeOptions(),
947
+ ...this.getDrawableOptions(),
948
+ ...this.originalOptions
949
+ };
702
950
  }
703
951
  initialize() {
704
952
  this.initializeDrawShape();
@@ -721,7 +969,8 @@ class DrawPad extends Composite {
721
969
  if (!this.drawArea) {
722
970
  this.drawArea = new Shape({
723
971
  rect: { size: this.size },
724
- isUserInteractionEnabled: true
972
+ isUserInteractionEnabled: true,
973
+ suppressEvents: true
725
974
  });
726
975
  this.addChild(this.drawArea);
727
976
  this.drawArea.onTapDown((e) => {
@@ -765,7 +1014,8 @@ class DrawPad extends Composite {
765
1014
  type: DrawPadEventType.StrokeStart,
766
1015
  target: this,
767
1016
  handled: false,
768
- position: e.point
1017
+ position: e.point,
1018
+ ...M2c2KitHelpers.createTimestamps()
769
1019
  };
770
1020
  this.strokes.push([
771
1021
  {
@@ -796,7 +1046,8 @@ class DrawPad extends Composite {
796
1046
  type: DrawPadEventType.StrokeMove,
797
1047
  target: this,
798
1048
  handled: false,
799
- position: interpolatedPoint
1049
+ position: interpolatedPoint,
1050
+ ...M2c2KitHelpers.createTimestamps()
800
1051
  };
801
1052
  this.strokes[strokeCount - 1].push({
802
1053
  type: DrawPadEventType.StrokeMove,
@@ -826,7 +1077,8 @@ class DrawPad extends Composite {
826
1077
  type: DrawPadEventType.StrokeEnd,
827
1078
  position: this.strokes[strokeCount - 1][strokeInteractionCount - 1].position,
828
1079
  target: this,
829
- handled: false
1080
+ handled: false,
1081
+ ...M2c2KitHelpers.createTimestamps()
830
1082
  };
831
1083
  this.strokes[strokeCount - 1].push({
832
1084
  type: DrawPadEventType.StrokeEnd,
@@ -854,7 +1106,8 @@ class DrawPad extends Composite {
854
1106
  type: DrawPadEventType.StrokeEnd,
855
1107
  position: this.strokes[strokeCount - 1][strokeInteractionCount - 1].position,
856
1108
  target: this,
857
- handled: false
1109
+ handled: false,
1110
+ ...M2c2KitHelpers.createTimestamps()
858
1111
  };
859
1112
  this.strokes[strokeCount - 1].push({
860
1113
  type: DrawPadEventType.StrokeEnd,
@@ -882,7 +1135,8 @@ class DrawPad extends Composite {
882
1135
  type: DrawPadEventType.StrokeMove,
883
1136
  target: this,
884
1137
  handled: false,
885
- position: e.point
1138
+ position: e.point,
1139
+ ...M2c2KitHelpers.createTimestamps()
886
1140
  };
887
1141
  const strokeCount = this.strokes.length;
888
1142
  this.strokes[strokeCount - 1].push({
@@ -1037,7 +1291,8 @@ class DrawPad extends Composite {
1037
1291
  node.isStrokeWithinBounds = true;
1038
1292
  const drawPadItemEvent = {
1039
1293
  type: DrawPadItemEventType.StrokeEnter,
1040
- target: node
1294
+ target: node,
1295
+ ...M2c2KitHelpers.createTimestamps()
1041
1296
  };
1042
1297
  this.raiseDrawPadItemEvent(node, drawPadItemEvent);
1043
1298
  }
@@ -1049,7 +1304,8 @@ class DrawPad extends Composite {
1049
1304
  node.isStrokeWithinBounds = true;
1050
1305
  const drawPadItemEvent = {
1051
1306
  type: DrawPadItemEventType.StrokeEnter,
1052
- target: node
1307
+ target: node,
1308
+ ...M2c2KitHelpers.createTimestamps()
1053
1309
  };
1054
1310
  this.raiseDrawPadItemEvent(node, drawPadItemEvent);
1055
1311
  }
@@ -1061,7 +1317,8 @@ class DrawPad extends Composite {
1061
1317
  node.isStrokeWithinBounds = false;
1062
1318
  const drawPadItemEvent = {
1063
1319
  type: DrawPadItemEventType.StrokeLeave,
1064
- target: node
1320
+ target: node,
1321
+ ...M2c2KitHelpers.createTimestamps()
1065
1322
  };
1066
1323
  this.raiseDrawPadItemEvent(node, drawPadItemEvent);
1067
1324
  }
@@ -1072,7 +1329,8 @@ class DrawPad extends Composite {
1072
1329
  node.isStrokeWithinBounds = false;
1073
1330
  const drawPadItemEvent = {
1074
1331
  type: DrawPadItemEventType.StrokeLeave,
1075
- target: node
1332
+ target: node,
1333
+ ...M2c2KitHelpers.createTimestamps()
1076
1334
  };
1077
1335
  this.raiseDrawPadItemEvent(node, drawPadItemEvent);
1078
1336
  }
@@ -1095,10 +1353,10 @@ class DrawPad extends Composite {
1095
1353
  if (!drawArea) {
1096
1354
  throw new Error("DrawPad.takeScreenshot(): no drawArea");
1097
1355
  }
1098
- const sx = (drawArea.absolutePosition.x - drawArea.size.width / 2) * Globals.canvasScale;
1099
- const sy = (drawArea.absolutePosition.y - drawArea.size.height / 2) * Globals.canvasScale;
1100
- const sw = drawArea.size.width * Globals.canvasScale;
1101
- const sh = drawArea.size.height * Globals.canvasScale;
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;
1102
1360
  const imageInfo = {
1103
1361
  alphaType: this.game.canvasKit.AlphaType.Unpremul,
1104
1362
  colorType: this.game.canvasKit.ColorType.RGBA_8888,
@@ -1237,9 +1495,10 @@ class DrawPad extends Composite {
1237
1495
  this.needsInitialization = true;
1238
1496
  }
1239
1497
  duplicate(newName) {
1240
- throw new Error("DrawPad.duplicate(): Method not implemented.");
1498
+ throw new Error(`DrawPad.duplicate(): Method not implemented. ${newName}`);
1241
1499
  }
1242
1500
  }
1501
+ M2c2KitHelpers.registerM2NodeClass(DrawPad);
1243
1502
 
1244
1503
  class VirtualKeyboard extends Composite {
1245
1504
  /**
@@ -1250,11 +1509,14 @@ class VirtualKeyboard extends Composite {
1250
1509
  constructor(options) {
1251
1510
  super(options);
1252
1511
  this.compositeType = "VirtualKeyboard";
1253
- this.rowsConfiguration = new Array();
1512
+ this.keyboardRows = new Array();
1254
1513
  this.shiftActivated = false;
1255
1514
  this.keyShapes = new Array();
1256
- // VirtualKeyboard defaults to being user interactive.
1257
- this._isUserInteractionEnabled = true;
1515
+ this.keyLabels = new Array();
1516
+ this.originalOptions = JSON.parse(JSON.stringify(options));
1517
+ if (options.isUserInteractionEnabled === void 0) {
1518
+ this._isUserInteractionEnabled = true;
1519
+ }
1258
1520
  this.size = options.size;
1259
1521
  this.position = options.position ?? { x: 0, y: 0 };
1260
1522
  this.keyboardHorizontalPaddingPercent = options.keyboardHorizontalPaddingPercent ?? 0.02;
@@ -1262,11 +1524,12 @@ class VirtualKeyboard extends Composite {
1262
1524
  this.keyHorizontalPaddingPercent = options.keyHorizontalPaddingPercent ?? 0.1;
1263
1525
  this.keyVerticalPaddingPercent = options.keyVerticalPaddingPercent ?? 0.1;
1264
1526
  if (options.rows !== void 0) {
1265
- this.rowsConfiguration = options.rows.map((row) => {
1527
+ this.keyboardRows = options.rows.map((row) => {
1266
1528
  const internalRow = row.map((key) => {
1267
1529
  if (key instanceof Object && !Array.isArray(key)) {
1268
1530
  const internalKeyConfig = key;
1269
1531
  if (key.keyIconShapeOptions) {
1532
+ key.keyIconShapeOptions.suppressEvents = true;
1270
1533
  internalKeyConfig.keyIcon = new Shape(key.keyIconShapeOptions);
1271
1534
  internalKeyConfig.keyIconShapeOptions = void 0;
1272
1535
  }
@@ -1288,157 +1551,48 @@ class VirtualKeyboard extends Composite {
1288
1551
  this.specialKeyDownColor = options.specialKeyDownColor ?? WebColors.LightSteelBlue;
1289
1552
  this.backgroundColor = options.backgroundColor ?? [242, 240, 244, 1];
1290
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
+ };
1291
1563
  }
1292
1564
  initialize() {
1293
- if (this.rowsConfiguration.length === 0) {
1294
- const numKeys = [
1295
- ["1", "!"],
1296
- ["2", "@"],
1297
- ["3", "#"],
1298
- ["4", "$"],
1299
- ["5", "%"],
1300
- ["6", "^"],
1301
- ["7", "&"],
1302
- ["8", "*"],
1303
- ["9", "("],
1304
- ["0", ")"]
1305
- ];
1306
- const row1 = [
1307
- "q",
1308
- "w",
1309
- "e",
1310
- "r",
1311
- "t",
1312
- "y",
1313
- "u",
1314
- "i",
1315
- "o",
1316
- "p"
1317
- ];
1318
- const row2 = [
1319
- "a",
1320
- "s",
1321
- "d",
1322
- "f",
1323
- "g",
1324
- "h",
1325
- "j",
1326
- "k",
1327
- "l"
1328
- ];
1329
- const shiftArrowShapeOptions = {
1330
- path: {
1331
- // Public Domain from https://www.freesvg.org
1332
- pathString: "m288-6.6849e-14 -288 288h144v288h288v-288h144l-288-288z",
1333
- width: 24
1334
- },
1335
- lineWidth: 2,
1336
- strokeColor: WebColors.Black,
1337
- fillColor: WebColors.Transparent
1338
- };
1339
- const backspaceShapeOptions = {
1340
- path: {
1341
- // CC0 from https://www.svgrepo.com
1342
- 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",
1343
- width: 24
1344
- },
1345
- lineWidth: 1,
1346
- strokeColor: WebColors.Black,
1347
- fillColor: WebColors.Red
1348
- };
1349
- const row3 = [
1350
- {
1351
- code: "Shift",
1352
- isShift: true,
1353
- widthRatio: 1.5,
1354
- keyIcon: new Shape(shiftArrowShapeOptions)
1355
- },
1356
- "z",
1357
- "x",
1358
- "c",
1359
- "v",
1360
- "b",
1361
- "n",
1362
- "m",
1363
- {
1364
- code: "Backspace",
1365
- widthRatio: 1.5,
1366
- keyIcon: new Shape(backspaceShapeOptions)
1367
- }
1368
- ];
1369
- const row4 = [
1370
- { code: " ", labelText: "SPACE", widthRatio: 5 }
1371
- ];
1372
- const keyboardRows = [
1373
- numKeys,
1374
- row1,
1375
- row2,
1376
- row3,
1377
- row4
1378
- ];
1379
- this.rowsConfiguration = keyboardRows;
1380
- 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(
1381
1571
  (max, row) => Math.max(max, row.length),
1382
1572
  0
1383
1573
  );
1384
- this.fontSize = this.size.height / this.rowsConfiguration.length / 2.5;
1574
+ this.fontSize = this.size.height / this.keyboardRows.length / 2.5;
1385
1575
  }
1386
1576
  const keyboardRectangle = new Shape({
1387
1577
  rect: { size: this.size },
1388
- fillColor: this.backgroundColor
1578
+ fillColor: this.backgroundColor,
1579
+ suppressEvents: true
1389
1580
  });
1390
1581
  this.addChild(keyboardRectangle);
1391
- const rows = this.rowsConfiguration.map((row) => {
1392
- return row.map((key) => {
1393
- let widthRatio = 1;
1394
- const heightRatio = 1;
1395
- let code;
1396
- let label;
1397
- let labelShifted;
1398
- let keyIcon;
1399
- let isShift = false;
1400
- if (typeof key === "string") {
1401
- code = key;
1402
- if (this.capitalLettersOnly) {
1403
- label = code.toUpperCase();
1404
- } else {
1405
- label = code;
1406
- }
1407
- labelShifted = code.toUpperCase();
1408
- } else if (Array.isArray(key)) {
1409
- code = key[0];
1410
- label = code;
1411
- labelShifted = key[1];
1412
- } else {
1413
- code = key.code;
1414
- label = key.labelText ?? "";
1415
- labelShifted = key.labelTextShifted ?? label;
1416
- widthRatio = key.widthRatio ?? 1;
1417
- keyIcon = key.keyIcon;
1418
- isShift = key.isShift ?? false;
1419
- }
1420
- return {
1421
- widthRatio,
1422
- heightRatio,
1423
- code,
1424
- labelText: label,
1425
- labelTextShifted: labelShifted,
1426
- keyIcon,
1427
- isShift
1428
- };
1429
- });
1430
- });
1582
+ const keyboard = this.internalKeyboardRowsToInternalKeyboardConfiguration(
1583
+ this.keyboardRows
1584
+ );
1431
1585
  const keyboardOrigin = {
1432
1586
  x: -keyboardRectangle.size.width / 2,
1433
1587
  y: -keyboardRectangle.size.height / 2
1434
1588
  };
1435
1589
  const keyboardVerticalPadding = (this.keyboardVerticalPaddingPercent ?? 0.025) * this.size.height;
1436
1590
  const keyboardHorizontalPadding = (this.keyboardHorizontalPaddingPercent ?? 0.02) * this.size.width;
1437
- const keyBoxHeight = (this.size.height - 2 * keyboardVerticalPadding) / rows.length;
1591
+ const keyBoxHeight = (this.size.height - 2 * keyboardVerticalPadding) / keyboard.length;
1438
1592
  const keyBoxWidth = (this.size.width - 2 * keyboardHorizontalPadding) / this.keysPerRow;
1439
1593
  this.keyShapes = [];
1440
- for (let r = 0; r < rows.length; r++) {
1441
- const row = rows[r];
1594
+ for (let r = 0; r < keyboard.length; r++) {
1595
+ const row = keyboard[r];
1442
1596
  const rowSumKeyWidths = row.reduce(
1443
1597
  (sum, key) => sum + (key.widthRatio ?? 1),
1444
1598
  0
@@ -1449,7 +1603,7 @@ class VirtualKeyboard extends Composite {
1449
1603
  }
1450
1604
  for (let k = 0; k < row.length; k++) {
1451
1605
  const key = row[k];
1452
- if (this.hiddenKeys?.split(",").map((s) => s.trim()).includes(key.code)) {
1606
+ if (this.hiddenKeys?.split(",").map((s) => s === " " ? " " : s.trim()).includes(key.code)) {
1453
1607
  continue;
1454
1608
  }
1455
1609
  const keyBoxWidthsSoFar = row.slice(0, k).reduce((sum, key2) => sum + (key2.widthRatio ?? 1), 0) * keyBoxWidth;
@@ -1466,7 +1620,8 @@ class VirtualKeyboard extends Composite {
1466
1620
  position: {
1467
1621
  x: extraPadding + keyboardOrigin.x + keyboardHorizontalPadding + keyBoxWidthsSoFar + (key.widthRatio ?? 1) * keyBoxWidth / 2,
1468
1622
  y: keyboardOrigin.y + keyboardVerticalPadding + r * keyBoxHeight + keyBoxHeight / 2
1469
- }
1623
+ },
1624
+ suppressEvents: true
1470
1625
  });
1471
1626
  const keyWidth = keyBoxWidth * (key.widthRatio ?? 1) - 2 * this.keyHorizontalPaddingPercent * keyBoxWidth;
1472
1627
  const keyHeight = keyBoxHeight - (key.heightRatio ?? 1) - 2 * this.keyVerticalPaddingPercent * keyBoxHeight;
@@ -1475,164 +1630,50 @@ class VirtualKeyboard extends Composite {
1475
1630
  cornerRadius: 4,
1476
1631
  fillColor: this.keyColor,
1477
1632
  lineWidth: 0,
1478
- isUserInteractionEnabled: this.isUserInteractionEnabled
1633
+ isUserInteractionEnabled: this.isUserInteractionEnabled,
1634
+ suppressEvents: true
1479
1635
  });
1636
+ keyShape.userData = { code: key.code };
1480
1637
  keyBox.addChild(keyShape);
1481
1638
  this.keyShapes.push(keyShape);
1482
- keyShape.onTapUp((tapEvent) => {
1483
- let keyAsString = "";
1484
- if (!key.isShift) {
1485
- if (this.shiftActivated) {
1486
- this.shiftActivated = false;
1487
- if (this.shiftKeyShape) {
1488
- this.shiftKeyShape.fillColor = this.keyColor;
1489
- if (key.keyIcon) {
1490
- key.keyIcon.fillColor = WebColors.Transparent;
1491
- }
1492
- }
1493
- rows.flatMap((k2) => k2).forEach((k2) => {
1494
- if (k2.keyLabel?.text !== void 0) {
1495
- k2.keyLabel.text = k2.labelText ?? "";
1496
- }
1497
- });
1498
- keyAsString = key.labelTextShifted ?? key.code;
1499
- } else {
1500
- keyAsString = key.labelText ?? key.code;
1501
- }
1502
- if (key.code === " " || key.code === "Backspace") {
1503
- keyAsString = key.code;
1504
- }
1505
- keyShape.fillColor = this.keyColor;
1506
- } else {
1507
- if (!this.shiftActivated) {
1508
- keyShape.fillColor = this.keyColor;
1509
- } else {
1510
- keyShape.fillColor = this.specialKeyDownColor;
1511
- }
1512
- keyAsString = key.code;
1513
- }
1514
- letterCircle.hidden = true;
1515
- if (this.eventListeners.length > 0) {
1516
- this.eventListeners.filter(
1517
- (listener) => listener.type === M2EventType.CompositeCustom && listener.compositeType === "VirtualKeyboardKeyUp"
1518
- ).forEach((listener) => {
1519
- const virtualKeyboardEvent = {
1520
- type: M2EventType.CompositeCustom,
1521
- target: this,
1522
- handled: false,
1523
- key: keyAsString,
1524
- code: key.code,
1525
- shiftKey: this.shiftActivated,
1526
- keyTapMetadata: {
1527
- size: keyShape.size,
1528
- point: tapEvent.point,
1529
- buttons: tapEvent.buttons
1530
- }
1531
- };
1532
- listener.callback(virtualKeyboardEvent);
1533
- });
1534
- }
1535
- });
1536
- keyShape.onTapDown((tapEvent) => {
1537
- if (key.isShift) {
1538
- this.shiftActivated = !this.shiftActivated;
1539
- if (this.shiftActivated) {
1540
- keyShape.fillColor = this.specialKeyDownColor;
1541
- if (key.keyIcon) {
1542
- key.keyIcon.fillColor = WebColors.Black;
1543
- }
1544
- rows.flatMap((k2) => k2).forEach((k2) => {
1545
- if (k2.keyLabel?.text !== void 0) {
1546
- k2.keyLabel.text = k2.labelTextShifted ?? k2.labelText ?? "";
1547
- }
1548
- });
1549
- } else {
1550
- keyShape.fillColor = this.keyColor;
1551
- if (key.keyIcon) {
1552
- key.keyIcon.fillColor = WebColors.Transparent;
1553
- }
1554
- rows.flatMap((k2) => k2).forEach((k2) => {
1555
- if (k2.keyLabel?.text !== void 0) {
1556
- k2.keyLabel.text = k2.labelText ?? "";
1557
- }
1558
- });
1559
- }
1560
- }
1561
- let keyAsString = "";
1562
- if (key.isShift || key.code === " " || key.code === "Backspace") {
1563
- keyShape.fillColor = this.specialKeyDownColor;
1564
- keyAsString = key.code;
1565
- } else {
1566
- keyShape.fillColor = this.keyDownColor;
1567
- if (this.showKeyDownPreview) {
1568
- letterCircle.hidden = false;
1569
- letterCircle.position.x = keyBox.position.x;
1570
- letterCircle.position.y = keyBox.position.y - keyHeight * 1.2;
1571
- if (this.shiftActivated) {
1572
- letterCircleLabel.text = key.labelTextShifted ?? key.code;
1573
- } else {
1574
- letterCircleLabel.text = key.labelText ?? key.code;
1575
- }
1576
- }
1577
- if (this.shiftActivated) {
1578
- keyAsString = key.labelTextShifted ?? key.code;
1579
- } else {
1580
- keyAsString = key.labelText ?? key.code;
1581
- }
1582
- }
1583
- if (this.eventListeners.length > 0) {
1584
- this.eventListeners.filter(
1585
- (listener) => listener.type === M2EventType.CompositeCustom && listener.compositeType === "VirtualKeyboardKeyDown"
1586
- ).forEach((listener) => {
1587
- const virtualKeyboardEvent = {
1588
- type: M2EventType.CompositeCustom,
1589
- target: this,
1590
- handled: false,
1591
- key: keyAsString,
1592
- code: key.code,
1593
- shiftKey: this.shiftActivated,
1594
- keyTapMetadata: {
1595
- size: keyShape.size,
1596
- point: tapEvent.point,
1597
- buttons: tapEvent.buttons
1598
- }
1599
- };
1600
- listener.callback(virtualKeyboardEvent);
1601
- });
1602
- }
1603
- });
1604
- keyShape.onTapLeave(() => {
1605
- keyShape.fillColor = this.keyColor;
1606
- letterCircle.hidden = true;
1607
- });
1608
1639
  const keyLabel = new Label({
1609
1640
  text: key.labelText,
1610
1641
  fontSize: this.fontSize,
1611
- fontNames: this.fontNames
1642
+ fontNames: this.fontNames,
1643
+ suppressEvents: true
1612
1644
  });
1645
+ keyLabel.userData = { code: key.code };
1613
1646
  keyBox.addChild(keyLabel);
1614
- key.keyLabel = keyLabel;
1615
- if (key.isShift) {
1616
- this.shiftKeyShape = keyShape;
1617
- }
1647
+ this.keyLabels.push(keyLabel);
1618
1648
  if (key.keyIcon) {
1619
1649
  keyBox.addChild(key.keyIcon);
1620
1650
  }
1621
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
+ });
1622
1661
  }
1623
1662
  }
1624
- const letterCircle = new Shape({
1663
+ this.letterCircle = new Shape({
1625
1664
  circleOfRadius: 28,
1626
1665
  fillColor: WebColors.Silver,
1627
- hidden: true
1666
+ hidden: true,
1667
+ suppressEvents: true
1628
1668
  });
1629
- keyboardRectangle.addChild(letterCircle);
1630
- const letterCircleLabel = new Label({
1669
+ keyboardRectangle.addChild(this.letterCircle);
1670
+ this.letterCircleLabel = new Label({
1631
1671
  text: "",
1632
1672
  fontSize: this.fontSize,
1633
- fontNames: this.fontNames
1673
+ fontNames: this.fontNames,
1674
+ suppressEvents: true
1634
1675
  });
1635
- letterCircle.addChild(letterCircleLabel);
1676
+ this.letterCircle.addChild(this.letterCircleLabel);
1636
1677
  this.needsInitialization = false;
1637
1678
  }
1638
1679
  /**
@@ -1643,8 +1684,9 @@ class VirtualKeyboard extends Composite {
1643
1684
  */
1644
1685
  onKeyDown(callback, options) {
1645
1686
  const eventListener = {
1646
- type: M2EventType.CompositeCustom,
1647
- compositeType: "VirtualKeyboardKeyDown",
1687
+ type: M2EventType.Composite,
1688
+ compositeEventType: "VirtualKeyboardKeyDown",
1689
+ compositeType: this.compositeType,
1648
1690
  nodeUuid: this.uuid,
1649
1691
  callback
1650
1692
  };
@@ -1658,13 +1700,433 @@ class VirtualKeyboard extends Composite {
1658
1700
  */
1659
1701
  onKeyUp(callback, options) {
1660
1702
  const eventListener = {
1661
- type: M2EventType.CompositeCustom,
1662
- compositeType: "VirtualKeyboardKeyUp",
1703
+ type: M2EventType.Composite,
1704
+ compositeEventType: "VirtualKeyboardKeyUp",
1705
+ compositeType: this.compositeType,
1663
1706
  nodeUuid: this.uuid,
1664
1707
  callback
1665
1708
  };
1666
1709
  this.addVirtualKeyboardEventListener(eventListener, options);
1667
1710
  }
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);
1732
+ }
1733
+ update() {
1734
+ super.update();
1735
+ }
1736
+ draw(canvas) {
1737
+ super.drawChildren(canvas);
1738
+ }
1739
+ warmup(canvas) {
1740
+ this.initialize();
1741
+ this.children.filter((child) => child.isDrawable).forEach((child) => {
1742
+ child.warmup(canvas);
1743
+ });
1744
+ }
1745
+ duplicate(newName) {
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
+ }
1668
2130
  addVirtualKeyboardEventListener(eventListener, options) {
1669
2131
  if (options?.replaceExisting) {
1670
2132
  this.eventListeners = this.eventListeners.filter(
@@ -1684,26 +2146,14 @@ class VirtualKeyboard extends Composite {
1684
2146
  */
1685
2147
  set isUserInteractionEnabled(isUserInteractionEnabled) {
1686
2148
  this._isUserInteractionEnabled = isUserInteractionEnabled;
1687
- this.keyShapes.forEach((keyShape) => {
2149
+ this.keyShapes?.forEach((keyShape) => {
1688
2150
  keyShape.isUserInteractionEnabled = isUserInteractionEnabled;
1689
2151
  });
1690
2152
  }
1691
- update() {
1692
- super.update();
1693
- }
1694
- draw(canvas) {
1695
- super.drawChildren(canvas);
1696
- }
1697
- warmup(canvas) {
1698
- this.initialize();
1699
- this.children.filter((child) => child.isDrawable).forEach((child) => {
1700
- child.warmup(canvas);
1701
- });
1702
- }
1703
- duplicate(newName) {
1704
- throw new Error(`Method not implemented. ${newName}`);
1705
- }
1706
2153
  }
2154
+ M2c2KitHelpers.registerM2NodeClass(
2155
+ VirtualKeyboard
2156
+ );
1707
2157
 
1708
2158
  const SCENE_TRANSITION_EASING$1 = Easings.sinusoidalInOut;
1709
2159
  const SCENE_TRANSITION_DURATION = 500;
@@ -2079,7 +2529,6 @@ class LocalePicker extends Composite {
2079
2529
  constructor(options) {
2080
2530
  super(options);
2081
2531
  this.compositeType = "LocalePicker";
2082
- this.zPosition = Number.MAX_VALUE;
2083
2532
  this.DEFAULT_FONT_SIZE = 24;
2084
2533
  this.automaticallyChangeLocale = true;
2085
2534
  this._localeOptions = new Array();
@@ -2107,6 +2556,7 @@ class LocalePicker extends Composite {
2107
2556
  */
2108
2557
  this.LEFT_SELECTION_INDICATOR = "\xAB";
2109
2558
  this.RIGHT_SELECTION_INDICATOR = "\xBB";
2559
+ this.zPosition = Number.MAX_VALUE;
2110
2560
  if (!options) {
2111
2561
  return;
2112
2562
  }
@@ -2146,7 +2596,7 @@ class LocalePicker extends Composite {
2146
2596
  */
2147
2597
  onResult(callback, options) {
2148
2598
  const eventListener = {
2149
- type: M2EventType.CompositeCustom,
2599
+ type: M2EventType.Composite,
2150
2600
  compositeType: "LocalePickerResult",
2151
2601
  nodeUuid: this.uuid,
2152
2602
  callback
@@ -2200,10 +2650,10 @@ class LocalePicker extends Composite {
2200
2650
  }
2201
2651
  const overlay = new Shape({
2202
2652
  rect: {
2203
- width: Globals.canvasCssWidth,
2204
- height: Globals.canvasCssHeight,
2205
- x: Globals.canvasCssWidth / 2,
2206
- y: Globals.canvasCssHeight / 2
2653
+ width: m2c2Globals.canvasCssWidth,
2654
+ height: m2c2Globals.canvasCssHeight,
2655
+ x: m2c2Globals.canvasCssWidth / 2,
2656
+ y: m2c2Globals.canvasCssHeight / 2
2207
2657
  },
2208
2658
  fillColor: [0, 0, 0, this.overlayAlpha],
2209
2659
  zPosition: -1,
@@ -2215,12 +2665,16 @@ class LocalePicker extends Composite {
2215
2665
  if (this.eventListeners.length > 0) {
2216
2666
  this.eventListeners.filter((listener) => listener.type === "LocalePickerResult").forEach((listener) => {
2217
2667
  const languagePickerEvent = {
2218
- type: "LocalePickerResult",
2668
+ type: M2EventType.Composite,
2669
+ compositeType: this.compositeType,
2670
+ compositeEventType: "LocalePickerResult",
2219
2671
  target: this,
2220
2672
  handled: false,
2221
2673
  result: {
2222
2674
  locale: void 0
2223
- }
2675
+ },
2676
+ timestamp: Timer.now(),
2677
+ iso8601Timestamp: (/* @__PURE__ */ new Date()).toISOString()
2224
2678
  };
2225
2679
  listener.callback(languagePickerEvent);
2226
2680
  });
@@ -2230,10 +2684,10 @@ class LocalePicker extends Composite {
2230
2684
  this.addChild(overlay);
2231
2685
  const lineHeight = this.fontSize / this.DEFAULT_FONT_SIZE * 50;
2232
2686
  const dialogHeight = this.localeOptions.length * lineHeight;
2233
- const dialogWidth = Globals.canvasCssWidth / 2;
2687
+ const dialogWidth = m2c2Globals.canvasCssWidth / 2;
2234
2688
  const sceneCenter = {
2235
- x: Globals.canvasCssWidth / 2,
2236
- y: Globals.canvasCssHeight / 2
2689
+ x: m2c2Globals.canvasCssWidth / 2,
2690
+ y: m2c2Globals.canvasCssHeight / 2
2237
2691
  };
2238
2692
  const localeDialog = new Shape({
2239
2693
  rect: {
@@ -2335,16 +2789,19 @@ class LocalePicker extends Composite {
2335
2789
  e.handled = true;
2336
2790
  if (this.eventListeners.length > 0) {
2337
2791
  this.eventListeners.filter(
2338
- (listener) => listener.type === M2EventType.CompositeCustom && listener.compositeType === "LocalePickerResult" && listener.nodeUuid == this.uuid
2792
+ (listener) => listener.type === M2EventType.Composite && listener.compositeType === "LocalePickerResult" && listener.nodeUuid == this.uuid
2339
2793
  ).forEach((listener) => {
2340
2794
  const languagePickerEvent = {
2341
- type: M2EventType.CompositeCustom,
2342
- compositeType: "LocalePickerResult",
2795
+ type: M2EventType.Composite,
2796
+ compositeType: this.compositeType,
2797
+ compositeEventType: "LocalePickerResult",
2343
2798
  target: this,
2344
2799
  handled: false,
2345
2800
  result: {
2346
2801
  locale: localeOption.locale
2347
- }
2802
+ },
2803
+ timestamp: Timer.now(),
2804
+ iso8601Timestamp: (/* @__PURE__ */ new Date()).toISOString()
2348
2805
  };
2349
2806
  listener.callback(languagePickerEvent);
2350
2807
  });
@@ -2508,7 +2965,7 @@ class LocalePicker extends Composite {
2508
2965
  }
2509
2966
  }
2510
2967
 
2511
- console.log("\u26AA @m2c2kit/addons version 0.3.15 (b3a70752)");
2968
+ console.log("\u26AA @m2c2kit/addons version 0.3.16 (0679492d)");
2512
2969
 
2513
2970
  export { Button, CountdownScene, Dialog, DialogResult, DrawPad, DrawPadEventType, DrawPadItemEventType, Grid, Instructions, LocalePicker, VirtualKeyboard };
2514
2971
  //# sourceMappingURL=index.js.map